Saturday, September 18, 2010

Let Windows Azure update your Facebook status (part 1)

Wouldn’t it be cool to have a bot which automatically posts something to your Facebook profile for you? Imagine how much time you could save if you wouldn’t have to log on to your profile several times a day anymore to post something, but still get a steady stream of comments and responses from your friends!


For instance, the bot could automatically do the following types of Facebook postings for you:




  • “Hello world”: general statements like “Good morning everyone!”, or “Have a great weekend, everybody!”, based on current day / time. Could also mix with some feelings, such as “.. is tired .. looking forward to the weekend.”
  • News: post a link to a random news article, with a generic comment such as “This is interesting…” or “Wow!”. 
  • Humor: post a random link to a humor page (such as TheOnion.com, Dilbert.com), with a comment like “LOL” or “This is funny..”
  • Events: post a comment referring to a local event, e.g. “Is anyone planning to go to the Seattle Beer Festival on Sunday?”
  • Movies/TV: post a comment regarding a movie or TV show, like “Has anyone already seen ‘Twilight’? Is it really that good?!”
  • Countdown: counting down the hours or days until a specified event. Example: “5 hours left until my party starts - hope to see all of you guys tonight!”
Ok, seriously, probably that would be pretty useless. But I’ve been curious for a while now how hard it would be to implement at least a basic version of such a bot. Plus, I needed a reason to play with the set of new Microsoft technologies such as Windows Azure, SQL Azure, and the developer tools for Windows Phone 7 (RTM version has just been released yesterday) anyways.

So far, I see at least two key challenges:
  • Style and content of the automated posts need to vary.  Ideally, readers shouldn’t be able to distinguish bot-generated posts from human-written ones. A Facebook version of the Turing Test, so to say. ;-) This is probably a hard artificial intelligence (AI) / natural language processing (NLP) problem. For the V1 of the bot, a small set of patterns, repeated in a random fashion, would be sufficient.
  • The bot needs to be able to communicate with the Facebook APIs asynchronously, without requiring the user to be online. Authentication will be the biggest issue here. Therefore this is the problem I’d like to solve first.
So, since I’d like to use the Microsoft technology stack - what’s the best way to access the Facebook APIs in .NET? There is a Codeplex project Facebook Developer Toolkit which provides high-level wrapper classes (such as “User”, “Friends”) to access the Facebook API. However, after playing with it for a little while, it appeared rather buggy and unstable to me, which is consistent with the feedback from several other users (refer for instance to this stackoverflow discussion). Therefore, I’ll use Facebook’s C# SDK instead. It’s still only an alpha release and not much more than a lightweight wrapper around the REST API, but that’s good enough for now.

As a first proof of concept, I’d like to set up a simple ASP.NET web form, hosted in a Windows Azure web role, which takes a string as an input and immediately posts it to the user’s profile:



Only a few lines of code need to be added to the Page_Load method to immediately post the content of the text box to the user’s profile:

if (IsPostBack)
{
  Facebook.FacebookAPI api = new Facebook.FacebookAPI(token);
  Dictionary<string, string> postArgs = new Dictionary<string, string>();
  postArgs["message"] = TextBox1.Text;
  api.Post("/me/feed", postArgs);
}

That’s the easy part. However, note that the FacebookAPI class expects a “token” parameter, which is an access token string. If no such token is available from an earlier session, the page needs to redirect the user to a Facebook authentication form first.


Here's where we need to work around a quirk of Windows Azure: when redirecting to the Facebook authentication page, we need to pass in a redirect_uri parameter. It indicates the page the user needs to get redirected back after a successful login. Since want the user to be redirected to the current page after signing in, we'd usually want to use Request.Url.AbsoluteUri in ASP.NET for this purpose. In Windows Azure however, this will not return the URL of the original request (the one received by Azure's load balancer), but the one received by the actual web role VM handling the request. This "internal" URL contains a port number (:20000) only to be used between the load balancer and the VM.
This is a known issue and will be fixed in a future Azure release. Until then, we'll have to work around it by manually removing the port number :20000 from the URL:


string urlThisPage = Request.Url.AbsoluteUri.Replace(":20000",""); 

string urlRedirectAuthenticate = string.Format(




"https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope=publish_stream",
_appId,
urlThisPage);

Page.Response.Redirect(string.urlRedirect);



Note the “scope=publish_stream” parameter: this is an extended permission the bot needs to be able to actually post to the user’s profile later.

Regarding the appId parameter: any connection to the Facebook API requires a (public) appID and a 128 bit private key, called the “App Secret”. Therefore, as a first step, it’s necessary to create an application in Facebook and point it to a valid URL: the page will be hosted in Windows Azure under http://maxifacebookbot.cloudapp.net, so Facebook needs to know about that.

After the user has signed in, Facebook does redirect the request to the original URL and adds a "code" parameter to it. The web server then needs to contact the Facebook API one more time to get it exchanged for the actual access token. Unfortunately, Facebook's C# SDK doesn't offer any help in doing this, but a HttpWebRequest to https://graph.facebook.com/oauth/access_token does the job. Note that this is where Facebook also requires the app secret to be passed in.





string urlExchangeCode = string.Format(
  "https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}",
  _appId,
  urlThisPage, 
  _appSecret,
  Request.QueryString["code"]
);

HttpWebRequest request = WebRequest.Create(urlExchangeCode) as HttpWebRequest;
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
  StreamReader reader = new StreamReader(response.GetResponseStream());
  response = reader.ReadToEnd(); // contains "access_token=..."
}




Ok, let’s try it out: publish the web role to Windows Azure …







After opening http://maxifacebookbot.cloudapp.net, the app indeed redirects to the Faceboot login page. After logging in, the user has to confirm the special permissions requested by the application:




After “allow”ing, the web form shows up, and indeed, it does what it’s expected to do – nice!




Facebook is giving away that the post has been created via an application and not by the user. L So one of the things I’ll investigate later is whether there’s a way to authenticate with a real user session instead of “as an application”.

Anyways, since it turns out to be possible to do immediate wall posts from a Windows Azure web role process, I’m curious to find out whether this can also be done in a delayed/scheduled fashion from a Windows Azure worker process. One issue will be to hand over the access token: the user will still need to authenticate through a web form. Azure then needs to persist that token somewhere, maybe in a SQL Azure database. Also, it needs to make sure the token doesn’t expire – maybe sending dummy requests every few minutes will prevent a timeout.

Until then, have fun updating your Facebook status with MaxiBot! J


No comments:

Post a Comment