Figuring out your online status, revisited

Three years ago, when I was learning how to integrate Second Life with external web servers in the summer of 2004, I posted some code for figuring out your online status from a website, blog, forum, etc. The tricky bit at the time was that XML-RPC requires a ‘channel’, which is created from scratch every time you register an object to handle XML-RPC calls, but this channel changes over time as sims get rebooted, or SL gets upgraded, or the asset server goes down, etc.

XML-RPC only allows queries from outside to an in-world object (but you can return an answer); in those days, the only way to store that channel on your webserver, to make sure you knew where to send the XML-RPC messages, was to send the channel ID by email. Parsing mails on a webserver, however, is an option that most low-cost web hosting services do not give you; it’s also not trivial, and very often requires you to have mail set up correctly (also, forget doing that under a Windows server). I just sent the channel to my own email address and manually changed it on my website.

Since Linden Lab introduced llHTTPRequest(), things are much easier. Using it, you can also call a webserver from any object — so now you have a simple and easy way to inform your website that the channel ID has changed! The PHP code I had was also designed for PHP4, using an external XML-RPC library that was quite easy to use. PHP4 has been made obsolete now, so it’s time to change the code to adapt. For me, it meant finding a new XML-RPC library. PHP5 has one, PEAR has another, and a lot of those are around, but almost all are hugely complex and, in some cases, you need to install it first, which may not be an option for the low-end hosting services. By chance, I was browsing through WordPress to see what library they were using — and I found one that works well under PHP4 and 5, comes with every WordPress installation, and it’s even simpler to use than Keith Devens‘ own, who never troubled himself to upgrade his library to PHP5. So here follows the code. The first bit is the LSL script to place in your object. As you can see, it follows the same model as my 2004 code pretty closely. If your object changes XML-RPC channel by any chance, just reset it or rez it again. Note that the webserver will always store the channel ID from the last object rezzed (but all should retrieve the same information from LL’s database servers, so it’s irrelevant).

// Code by Gwyneth Llewelyn to show online status and let it
// be retrieved by external XML-RPC calls
// Global Variables
key avatar;
string avatarName;
string onlineStatus = "status unknown"; // preserve it
key onlineStatusRequest;
key webResponse;	// we send the RPC channel ID to the webserver
default
{
state_entry()
{
llSetTimerEvent(60.0);  // call a timer event
// every 60 seconds.
avatar = llGetOwner();
avatarName = llKey2Name(avatar);
llOwnerSay("Registering with RPC server and retrieving user data from database server...");
llOpenRemoteDataChannel();	// this sets the object up to accept external XML-RPC calls
}	
on_rez(integer startParam)
{
llResetScript();
}
timer()
{
// Every 60 seconds, retrieve the online status from the SL database server
onlineStatusRequest = llRequestAgentData(avatar, DATA_ONLINE);
llSetText(avatarName + " is " + onlineStatus, ZERO_VECTOR, 1.0);	// set the hover text
}
dataserver(key queryid, string data)
{
// this is what SL returns to us when we call llRequestAgentData()
if (queryid == onlineStatusRequest)	// check if it's the correct request
{
if (data == "1")	// online status is just 0 or 1
onlineStatus = "online";
else
onlineStatus = "offline";
}
}
remote_data(integer event_type, key channel, key message_id, string sender, integer idata, string sdata)
{
if (event_type == REMOTE_DATA_CHANNEL)
{
// SL has set up a channel for the XML-RPC calls
llOwnerSay("Channel id "+(string)channel);
llOwnerSay("Sending channel id to web server...");
// We'll save it, by sending it to our server
webResponse = llHTTPRequest("http://insert.your.domain.here.tld/save-channel.php",
[HTTP_METHOD, "POST",
HTTP_MIMETYPE, "application/x-www-form-urlencoded"],
"channel=" + (string)channel);
}
if (event_type == REMOTE_DATA_REQUEST)
{
// This is a call made from our web site/blog asking us for the online status
llRemoteDataReply(channel, message_id, onlineStatus, idata);
}
}
http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == webResponse)
{
if (status == 200)	// we'll get a 200 OK status if the web server stored the XML-RPC channel correctly
llOwnerSay("Channel id successfully saved");
else llOwnerSay("Webserver error " + (string)status + ": " + body);
}
}
}

Now it’s time to take a look at the web-side code. The first bit is the handler for the new channel. I’ve done a quick-and-dirty thingy that simply writes to a local file. Since this is meant to be used inside things like your own hosted blogs/websites/forums, just pick a local directory that is writable and use it. For WordPress, I’m using the uploads directory and the filename I’ve picked was channels.inc. Just copy and paste the following code into a file called save-channel.php where your webserver can find it (remember to place the PHP tags before and after this code, I cannot display them inside WordPress):

if ($_REQUEST['channel'])
{
include('./wp-config.php');
$filename = ABSPATH . 'wp-content/uploads/channel.inc';
$fd = fopen($filename, 'w');
if (fwrite($fd, $_REQUEST['channel']) === FALSE)
{
header("HTTP/1.0 503 Service Unavailable");
echo "File $filename not writeable - channel not saved";
}
else
{
fclose($fd);
header("Content-type: text/plain; charset=utf-8");
echo "Channel " . $_REQUEST['channel'] . " saved.";
}
}
else
{
header("HTTP/1.0 405 Method Not Allowed");
echo "No channel specified";
}

And finally comes the last bit — adding the relevant code on your site/blog/forum to check if you’re in-world or not. This requires including class-IXR.php, which is available from Incutio. However, the WordPress guys have continued to update this XML-RPC library and have a more recent version.

include_once(ABSPATH . WPINC . '/class-IXR.php');
$client = new IXR_Client('http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi');
$payload["Channel"] = file_get_contents(ABSPATH . 'wp-content/uploads/channel.inc');
$payload["IntValue"] = 0;
$payload["StringValue"] = "online status";
print "I am ";
if ($client->query('llRemoteData', $payload))
{
$response = $client->getResponse();
print $response["StringValue"] . " in Second Life.";
}
else
{
print "having problems contacting RPC server...";
}

Enjoy!

UPDATE: If you’re on a self-hosted WordPress blog, you might be interested in testing my Online Status inSL WordPress Plugin, which should be way easier to install 🙂

Print Friendly, PDF & Email
%d bloggers like this: