User:Robin Cornelius/IRC LSL Bridge
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();