Using Cloud Services from Second Life
I was playing around with building scripted objects in Second Life and ran across a function to pull text from the web. I thought it might be neat to create Live Messenger buddy object in Second Life that showed whether I was online or offline. I figured I could query the Windows Live Presence API directly from script and be done. Unfortunately it turns out there is a bit of a gap between Second Life and Windows Live. The Presence API serves up information by way of JSON. Second Life does not know what to do with JSON file coming back as the payload and gives an error.
Given this gap, I thought Azure might make a nice bridge. I could call the Live Presence API from a cloud based service, reproduce the information in a very simple format for Second Life, and then consume the new service with an HTTP call in Second Life.
I had to accomplish three things in order to get everything wired up.
- Put something in the cloud to provide a simple service
- Consume JSON from server code instead of a browser
- Connect Second Life to Azure
To get started, I registered for the Azure Community Technical Preview. This gave me a sandbox in the cloud to play with and I downloaded the free Visual Studio 2008 Web Developer 2008 which provided all the power I needed for this little project. Once in Visual Studio I created a new Web Cloud Service and used the following code.
1: using System.Net;
2: using System.IO;
3: using System.Text;
4: using System.Runtime.Serialization.Json;
5:
6: namespace SecondLife_WebRole
7: {
8:
9: [Serializable]
10: public class Presence
11: {
12: public string status;
13: public string displayName;
14: }
15:
16: public partial class _Default : System.Web.UI.Page
17: {
18: string LiveUrl =
19: "https://messenger.services.live.com/users/5a11680377739a32@apps.messenger.live.com/presence";
20:
21: protected void Page_Load(object sender, EventArgs e)
22: {
23: // Make a web request to Live service
24: HttpWebRequest request = (HttpWebRequest)WebRequest.Create(LiveUrl);
25: HttpWebResponse response = (HttpWebResponse)request.GetResponse();
26:
27: // Hydrate a .Net object from the JSON response
28: Stream receiveStream = response.GetResponseStream();
29: DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Presence));
30: Presence presence = ser.ReadObject(receiveStream) as Presence;
31:
32: // Output very simple text so Second Life can consume it
33: Response.Clear();
34: Response.ContentType = "text/plain";
35: Response.Write(presence.status + "\n");
36: Response.Write(presence.displayName + "\n");
37: }
38: }
39: }
I was pretty happy that the .NET Framework had a JSON helper class and a rich language with C# to work with the data. This code worked fine from an ASP.Net application but not from a cloud application. Turns out I needed to set enableNativeCodeExecution to true so that the stream classes would not hit a security exception.
1: <?xml version="1.0" encoding="utf-8"?>
2: <ServiceDefinition name="SecondLife" xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
3: <WebRole name="WebRole" enableNativeCodeExecution="true" >
4: <InputEndpoints>
5: <!-- Must use port 80 for http and port 443 for https when running in the cloud -->
6: <InputEndpoint name="HttpIn" protocol="http" port="80" />
7: </InputEndpoints>
8: </WebRole>
9: </ServiceDefinition>
Once I had that working, I used the cloud deploy feature of Azure to get the service hosted. It worked and my service was now serving something easily consumable by Second Life:
Finally I went into Second Life and added script to a buddy object created all in-game. The Second Life script simply makes an HTTP request to the cloud service and returns the very-simple-to-parse name and status. If I am online, i set the object to light blue and glowing and if I am offline, I dim the object and use a darker color.
// Use an Azure service in the cloud to get Live Messenger status
string AZUREHOST = "https://secondlife.cloudapp.net/Default.aspx";
key http_request_id;
default
{
touch_start(integer total_number)
{
llSetText("", <1,1,1>, 1.0);
string response = "";
http_request_id = llHTTPRequest(AZUREHOST, [], "");
}
http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == http_request_id)
{
list lines = llParseString2List(body, ["\n"], []);
string status = llList2String(lines, 0);
string name = llList2String(lines, 1);
if (status == "Online")
{
llSetText(name + " is Online", <0,0,1>, 1);
llSetLinkColor(LINK_SET, <0.15686, 0.58039, 1.00000>, ALL_SIDES);
llSetLinkPrimitiveParams(LINK_SET, [PRIM_GLOW, ALL_SIDES, .1] );
llSetLinkPrimitiveParams(LINK_SET, [PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_LOW, PRIM_BUMP_BRIGHT] );
}
else // user offline
{
llSetText("User Offline", <0,0,1>, 1);
llSetLinkColor(LINK_SET, <0.38824, 0.38824, .38824>, ALL_SIDES);
llSetLinkPrimitiveParams(LINK_SET, [PRIM_GLOW, ALL_SIDES, 0] );
llSetLinkPrimitiveParams(LINK_SET, [PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_NONE, PRIM_BUMP_NONE] );
}
}
}
}
The Messenger buddy in second life is darker with no glow if I am logged out of Messenger. For Second Life builders, buddy is 10 prims big:
… but when I’m logged into Messenger, buddy lights up like a Christmas light:
So what's the big deal? Why use Azure for such a little thing? I think the answer is that it is such a "little thing." As a developer I just wanted to get my service online and working. I didn't want to have to go find a hosting provider, sign up and spend a bunch of money, and then take a few days trying to get everything working. I'd rather just spend time on getting the code to work. If I add significant features later on, or make the service public, I am confident Azure will scale with me. Again, I can just focus on the functionality of the service and not worry about scale and configuration.
When I account for my time on this project, I’m pretty happy with the breakdown. Much of the time was spent on community: Ben Williams pointed me towards the Windows Live Presence API. Jim O’Neil gave me a rough architecture by suggesting I try a WebRequest and then use the JSON Serializer. The venerable Steve Marx helped me debug by showing me the enableNativeCodeExecution flag. Second Life resident and coffee machine builder, amira Mathilde helped me craft the “buddy” object so it wasn’t terrible looking.
My Second Life resident is “Macaw Roogus” so say hi to me if you see me online and maybe we can find some more interesting things to build.
Comments
Anonymous
April 22, 2009
Nice article Jeremy, as usual you make "hard things" look very simple.Anonymous
April 22, 2009
Thank you for submitting this cool story - Trackback from DotNetShoutoutAnonymous
April 22, 2009
Nice post! Just wondering... How long do you think you spent actually developing this?Anonymous
April 22, 2009
John I figure I spent about an hour getting the environment going and a 'hello world' just working with Azure. I probably then spent an hour on the .NET side and an hour on the Second Life side. Most of that time was just looking up which APIs to use and seeing if they worked. amira did the heavy lifting in building the Buddy shape but she has built many things in SL so I don't know that it took her very long at all. Maybe three hours? That's a guess.Anonymous
April 22, 2009
Nice post. Even a slacker like me might give it a try with these nice instructions.