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 🙂

CC BY 4.0 Figuring out your online status, revisited by Gwyneth Llewelyn is licensed under a Creative Commons Attribution 4.0 International License.

About Gwyneth Llewelyn

I'm just a virtual girl in a virtual world...

  • Gwyneth,
    Nice job, very interesting.

    But note that in the SL script there is a little bug:
    the line [if (status = 200) // we’ll...]
    should be if (status == 200) // we’ll...]

    However, many tks for your great job!

  • Oops. You’re so right! Thanks for spotting the bug!

  • Parse error: syntax error, unexpected T_VARIABLE in /home/kevinoto/public_html/online.php on line 3 I am getting this. I am not sure how to fix it. Thanks

  • Kevin, which of the two PHP scripts gives that error to you?

  • On the online.php that shows your online or not i get Parse error: syntax error, unexpected T_CLASS in /home/searchi9/public_html/web3/online.php on line 2
    and on the save-channel.php is giving me
    Parse error: syntax error, unexpected ‘/’ in /home/searchi9/public_html/web3/wp-content/uploads/save-channel.php on line 4

    And also are you going to remake this when http-in is in the main version? One of my scripter friends told me they are going to take out xml-rpc when http-in is in.

  • Ah… I wonder if you’re using this script on a WordPress blog? 🙂

    Because if you aren’t, you’ll need to download class-IXR.php, install it somewhere, and rewrite the whole code to point the paths properly to it. Or, well, use any other PHP XML-RPC packages (there are a lot of them; Incutio’s IXR just happens to be small, efficient, and very simple to us; these days, most installations of PHP also include XML-RPC classes, which are probably faster since they’re C libraries 🙂 ).

    Oh yes, I most definitely will use http-in as soon as it’s available (hopefully still in 2009!). LL will slowly phase out XML-RPC — and not abruptly — since their own XstreetSL.com web shop uses XML-RPC profusely, and a hundred thousand people use that every day. That’s a lot of code to replace!

  • I have it install on my wordpress. So i don’t really know whats up with that.

  • Thanks for catching this 🙂