Difference between revisions of "User:Robin Cornelius/IRC LSL Bridge"
Line 96: | Line 96: | ||
Perl code, run on an appropriate server | Perl code, run on an appropriate server | ||
#!/usr/bin/perl | |||
# | |||
# Copyright (C) 2010 Robin Cornelius <robin.cornelius@gmail.com> | |||
# | |||
# This program is free software: you can redistribute it and/or modify | |||
# it under the terms of the GNU General Public License as published by | |||
# the Free Software Foundation, either version 3 of the License, or | |||
# (at your option) any later version. | |||
# | |||
# This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU General Public License | |||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
# | |||
# User configuration section | |||
my $nickname = 'irc-bridge'; | |||
my $ircname = 'The bridge'; | |||
#@servers = (['irc.servercentral.net']); | |||
my @servers = (['127.0.0.1']); | |||
my %channels = ( | |||
'#opensl' => '', | |||
); | |||
my $http_server_port=8088; | |||
# end of user configuration section | |||
use strict; | |||
use warnings; | |||
#use POE | |||
use POE; | |||
use POE::Component::Child; | |||
# Pull in various IRC components | |||
use POE::Component::IRC; | |||
use POE::Component::IRC::State; | |||
use POE::Component::IRC::Plugin::NickReclaim; | |||
use POE::Component::IRC::Plugin::AutoJoin; | |||
use POE::Component::IRC::Plugin::Connector; | |||
use POE::Component::IRC::Plugin::BotCommand; | |||
use POE::Component::IRC::Plugin::CycleEmpty; | |||
# POE::Component::Client::HTTP uses HTTP::Request and response objects. | |||
use HTTP::Request::Common qw(GET POST); | |||
# Include POE and the HTTP client component. | |||
use POE::Component::Client::HTTP; | |||
# Include POE HTTP Server component | |||
use POE qw(Component::Server::TCP Filter::HTTPD); | |||
use HTTP::Response; | |||
# We want to encode and decode escaped URIs | |||
use URI::Escape; | |||
# This the the URI of the CAP for the prim's http server | |||
my $LLURI; | |||
# *************** IRC **************************** | |||
my $irc = POE::Component::IRC::State->spawn( | |||
nick => $nickname, | |||
ircname => $ircname, | |||
Server => $servers[0]->[0], | |||
) or die "Could not use name $!"; | |||
sub _start { | |||
my ($kernel, $heap) = @_[KERNEL, HEAP]; | |||
$irc->yield( register => 'all' ); | |||
# Create and load our NickReclaim plugin, before we connect | |||
$irc->plugin_add( 'NickReclaim' => POE::Component::IRC::Plugin::NickReclaim->new( poll => 60 ) ); | |||
my $chans=\%channels; | |||
my $svrs=\@servers; | |||
$irc->plugin_add('AutoJoin', POE::Component::IRC::Plugin::AutoJoin->new( Channels => $chans)); | |||
$irc->plugin_add('Connector',POE::Component::IRC::Plugin::Connector->new( servers => $svrs)); | |||
$irc->plugin_add('CycleEmpty', POE::Component::IRC::Plugin::CycleEmpty->new()); | |||
$irc->yield( connect => { } ); | |||
return; | |||
} | |||
# channel message | |||
sub irc_public { | |||
my ($kernel,$sender)=@_[KERNEL,SENDER]; | |||
my $hostmask=$_[ARG0]; | |||
my $target=@$_[ARG1]; | |||
my $msg=$_[ARG2]; | |||
$hostmask =~ s/^(.*)!(.*)@(.*)$//;; | |||
my $nick = $1; | |||
my $hostuser = $2; | |||
my $hostname = $3; | |||
my $url=$LLURI."/?".uri_escape("<$nick> ".$msg); | |||
# Send the recieved message from IRC component to the http client component | |||
$kernel->post("ua" => "request", "got_response", GET $url); | |||
} | |||
# **************** HTTP CLIENT ********************** | |||
POE::Component::Client::HTTP->spawn( | |||
Alias => 'ua', | |||
MaxSize => 4096, # Remove for unlimited page sizes. | |||
Timeout => 180, | |||
); | |||
sub got_response { | |||
my ($heap, $request_packet, $response_packet) = @_[HEAP, ARG0, ARG1]; | |||
my $http_request = $request_packet->[0]; | |||
my $http_response = $response_packet->[0]; | |||
my $response_string = $http_response->as_string(); | |||
# Client response, we could be good and check for errors here | |||
} | |||
# **************** HTTP SERVER ********************** | |||
# Spawn a web server on all interfaces. | |||
sub error_handler { | |||
my ($syscall_name, $error_number, $error_string) = @_[ARG0, ARG1, ARG2]; | |||
print "MEH an error $error_string"; | |||
exit(-1); | |||
} | |||
POE::Component::Server::TCP->new( | |||
Alias => "web_server", | |||
Port => $http_server_port, | |||
ClientFilter => 'POE::Filter::HTTPD', | |||
Error => \&error_handler, | |||
ClientInput => sub { | |||
my ($kernel, $heap, $request) = @_[KERNEL, HEAP, ARG0]; | |||
if ($request->isa("HTTP::Response")) { | |||
$heap->{client}->put($request); | |||
$kernel->yield("shutdown"); | |||
return; | |||
} | |||
my $msg=uri_unescape($request->uri()); | |||
$msg =~ s/\///; | |||
if($msg =~ m/\?URI=/) | |||
{ | |||
$msg =~ s/\?URI=//; | |||
$LLURI=$msg; | |||
} | |||
if($msg =~ m/\?MSG=/) | |||
{ | |||
$msg =~ s/\?MSG=//; | |||
# Send the recieved message from http server to the IRC component | |||
$irc->call(privmsg => ("#opensl",$msg)); | |||
} | |||
my $response = HTTP::Response->new(200); | |||
$response->push_header('Content-type', 'text'); | |||
$response->content("OK"); | |||
# Once the content has been built, send it back to the client | |||
# and schedule a shutdown. | |||
$heap->{client}->put($response); | |||
$kernel->yield("shutdown"); | |||
} | |||
); | |||
# ******************** POE ************************************* | |||
# Create the POE session | |||
POE::Session->create( | |||
package_states => [ main => [ qw(got_response _start irc_public) ]], | |||
); | |||
# Start POE. This will run the server until it exits | |||
$poe_kernel->run(); |
Revision as of 10:00, 10 April 2010
A simple LSL/IRC bridge using a perl implementation of an IRC client
LSL code, insert in to a prim in world
<lsl> // // Copyright (C) 2010 Robin Cornelius <robin.cornelius@gmail.com> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //
// CHANGE THE URL AND PORT BELOW string server_url="MY URL"; string server_port="MY PORT";
string url;
key http_request_id;
default {
touch_start(integer num_detected) { if(llDetectedKey(0)==llGetOwner()) { // Rsend the URI to the server if the owner touches us http_request_id = llHTTPRequest(server_url+":"+server_port+"/?URI="+llEscapeURL(url), [], ""); } } state_entry() { // Start up request a URL and listen on channel 0 llRequestURL(); llListen(0,"","",""); } changed(integer What) { // On a region restart request a new URL if (What & CHANGED_REGION_START) { llRequestURL(); } } http_request(key ID, string Method, string Body) { if (Method == URL_REQUEST_GRANTED) { //If the URL was granted save the URL and send it to the server url = Body; http_request_id = llHTTPRequest(server_url+":"+server_port+"/?URI="+llEscapeURL(Body), [], ""); } else if (Method == URL_REQUEST_DENIED) { // We are boned llOwnerSay("No URLs"); } else if (Method == "GET") { // Get the data sent to us, say it on channel 0 and respond with a 200 llSay(0,llUnescapeURL(llGetHTTPHeader(ID, "x-query-string"))); llHTTPResponse(ID, 200, "Hello there !"); } } listen(integer channel,string name, key id,string msg) { // Send all channel 0 data to the server llHTTPRequest(server_url+":"+server_port+"/?MSG="+llEscapeURL("<"+name+"> "+msg), [], ""); } http_response(key request_id, integer status, list metadata, string body) { //Check http response after sending data from listen or a URI update if (request_id == http_request_id) { //Do some error checking for status !=200 } }
} </lsl>
Perl code, run on an appropriate server
#!/usr/bin/perl # # Copyright (C) 2010 Robin Cornelius <robin.cornelius@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # User configuration section my $nickname = 'irc-bridge'; my $ircname = 'The bridge'; #@servers = (['irc.servercentral.net']); my @servers = (['127.0.0.1']); my %channels = ( '#opensl' => , ); my $http_server_port=8088; # end of user configuration section use strict; use warnings; #use POE use POE; use POE::Component::Child; # Pull in various IRC components use POE::Component::IRC; use POE::Component::IRC::State; use POE::Component::IRC::Plugin::NickReclaim; use POE::Component::IRC::Plugin::AutoJoin; use POE::Component::IRC::Plugin::Connector; use POE::Component::IRC::Plugin::BotCommand; use POE::Component::IRC::Plugin::CycleEmpty; # POE::Component::Client::HTTP uses HTTP::Request and response objects. use HTTP::Request::Common qw(GET POST); # Include POE and the HTTP client component. use POE::Component::Client::HTTP; # Include POE HTTP Server component use POE qw(Component::Server::TCP Filter::HTTPD); use HTTP::Response; # We want to encode and decode escaped URIs use URI::Escape; # This the the URI of the CAP for the prim's http server my $LLURI; # *************** IRC **************************** my $irc = POE::Component::IRC::State->spawn( nick => $nickname, ircname => $ircname, Server => $servers[0]->[0], ) or die "Could not use name $!"; sub _start { my ($kernel, $heap) = @_[KERNEL, HEAP]; $irc->yield( register => 'all' ); # Create and load our NickReclaim plugin, before we connect $irc->plugin_add( 'NickReclaim' => POE::Component::IRC::Plugin::NickReclaim->new( poll => 60 ) ); my $chans=\%channels; my $svrs=\@servers; $irc->plugin_add('AutoJoin', POE::Component::IRC::Plugin::AutoJoin->new( Channels => $chans)); $irc->plugin_add('Connector',POE::Component::IRC::Plugin::Connector->new( servers => $svrs)); $irc->plugin_add('CycleEmpty', POE::Component::IRC::Plugin::CycleEmpty->new()); $irc->yield( connect => { } ); return; } # channel message sub irc_public { my ($kernel,$sender)=@_[KERNEL,SENDER]; my $hostmask=$_[ARG0]; my $target=@$_[ARG1]; my $msg=$_[ARG2]; $hostmask =~ s/^(.*)!(.*)@(.*)$//;; my $nick = $1; my $hostuser = $2; my $hostname = $3; my $url=$LLURI."/?".uri_escape("<$nick> ".$msg); # Send the recieved message from IRC component to the http client component $kernel->post("ua" => "request", "got_response", GET $url); } # **************** HTTP CLIENT **********************
POE::Component::Client::HTTP->spawn( Alias => 'ua', MaxSize => 4096, # Remove for unlimited page sizes. Timeout => 180, ); sub got_response { my ($heap, $request_packet, $response_packet) = @_[HEAP, ARG0, ARG1]; my $http_request = $request_packet->[0]; my $http_response = $response_packet->[0]; my $response_string = $http_response->as_string(); # Client response, we could be good and check for errors here } # **************** HTTP SERVER ********************** # Spawn a web server on all interfaces. sub error_handler { my ($syscall_name, $error_number, $error_string) = @_[ARG0, ARG1, ARG2]; print "MEH an error $error_string"; exit(-1); } POE::Component::Server::TCP->new( Alias => "web_server", Port => $http_server_port, ClientFilter => 'POE::Filter::HTTPD', Error => \&error_handler, ClientInput => sub { my ($kernel, $heap, $request) = @_[KERNEL, HEAP, ARG0]; if ($request->isa("HTTP::Response")) { $heap->{client}->put($request); $kernel->yield("shutdown"); return; } my $msg=uri_unescape($request->uri()); $msg =~ s/\///; if($msg =~ m/\?URI=/) { $msg =~ s/\?URI=//; $LLURI=$msg; } if($msg =~ m/\?MSG=/) { $msg =~ s/\?MSG=//; # Send the recieved message from http server to the IRC component $irc->call(privmsg => ("#opensl",$msg)); } my $response = HTTP::Response->new(200); $response->push_header('Content-type', 'text'); $response->content("OK"); # Once the content has been built, send it back to the client # and schedule a shutdown. $heap->{client}->put($response); $kernel->yield("shutdown"); } ); # ******************** POE ************************************* # Create the POE session POE::Session->create( package_states => [ main => [ qw(got_response _start irc_public) ]], ); # Start POE. This will run the server until it exits $poe_kernel->run();