Skip to content

Instantly share code, notes, and snippets.

@jubishop
Created February 12, 2009 03:15
Show Gist options
  • Save jubishop/62465 to your computer and use it in GitHub Desktop.
Save jubishop/62465 to your computer and use it in GitHub Desktop.
package fbconnect {
import flash.external.ExternalInterface;
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoaderDataFormat;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
import mx.core.Application;
import mx.controls.Alert;
import com.adobe.crypto.MD5;
import com.adobe.serialization.json.JSON;
import fbconnect.FBEvent;
public class FBConnect {
public static const MALE:String = "male";
public static const FEMALE:String = "female";
private static function get parameters():Object {
return Application.application.loaderInfo.parameters;
}
// We use these to make sure every API call is unique
private static var datePrefix:String = (new Date()).time.toString();
private static var callCount:int = 0;
// All the calls we've queued to dispatch on the next frame
// key => methodName:String
// value => {args:URLVariables, dispatcher:EventDispatcher}
private static var queuedCalls:Object = new Object();
// This is our most fundamental public api-calling function.
// It just takes the method name and args and prepares for batch launch.
public static function callAPI(method:String, callArgs:URLVariables):EventDispatcher {
if (! queuedCalls[method]) queuedCalls[method] = new Array();
// Create a unique dispatcher for this event, and store with arguments/method
var dispatcher:EventDispatcher = new EventDispatcher();
queuedCalls[method].push({args:callArgs, dispatcher:dispatcher});
// We're going to be sure to fire our postBatch on the next frame now
Application.application.addEventListener(Event.ENTER_FRAME, postBatch);
// Dispatcher can then be subscribed to by caller
return dispatcher;
}
// Function is called at the beginning of any frame in which calls have been made.
// Simply iterates over all queuedCalls and posts them via post()
private static function postBatch(event:Event):void {
Application.application.removeEventListener(Event.ENTER_FRAME, postBatch);
for (var method:String in queuedCalls) {
for each (var call:Object in queuedCalls[method]) {
post(method, call.args, call.dispatcher);
}
}
// Clear queue for next time
queuedCalls = new Object();
}
// Meaty logic of posting a method to the rest api.
// Adds all our default params, creates our sig, posts.
private static function post(method:String, callArgs:URLVariables,
dispatcher:EventDispatcher):void {
callCount++;
// All the default stuff we require
callArgs['v'] = '1.0';
callArgs['format'] = 'JSON';
callArgs['method'] = method;
callArgs['ss'] = true;
callArgs['api_key'] = FBConnect.api_key;
callArgs['session_key'] = FBConnect.session_key;
callArgs['call_id'] = datePrefix + callCount;
// Carefully create a string to MD5 for our hash-sig
var argsArray:Array = new Array();
for(var arg:String in callArgs) {
var val:* = callArgs[arg];
if (callArgs[arg] is Array)
callArgs[arg] = callArgs[arg].join(",");
argsArray.push(arg + "=" + callArgs[arg]);
}
argsArray.sort();
var hashString:String = argsArray.join("") + FBConnect.secret;
callArgs['sig'] = MD5.hash(hashString);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, function(event:Event):void {
// TODO: Check to see if response is an error
// When the server's responded we marshal the data and dispatch
// the data loaded event via our unique dispatcher
Alert.show(event.target.data);
dispatcher.dispatchEvent((new FBEvent(FBEvent.DATA_LOADED,
JSON.decode(event.target.data))));
});
loader.addEventListener(IOErrorEvent.IO_ERROR, callError);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, callError);
// Now we bundle things up and fire it off.
var request:URLRequest = new URLRequest("http://api.facebook.com/restserver.php");
request.contentType = "application/x-www-form-urlencoded";
request.method = URLRequestMethod.POST;
request.data = callArgs;
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.load(request);
}
private static function callError(event:Event):void {
// TODO: Handle error
}
// callAPI wrapper for our fb:name tag.
// Checks the queue to see if a users.getInfo is already queued
// and adds its ids to that call, otherwise creates its own.
public static function getUserInfo(uids:Array):EventDispatcher {
if (queuedCalls['users.getInfo']) {
var queuedCall:Object = queuedCalls['users.getInfo'][0];
var queued_uids:Array = queuedCall.args['uids'] as Array;
// We already have a queued call, so we'll just make sure we don't
// add dupes to our array
for each (var uid:int in uids) {
if (queued_uids.indexOf(uid) == -1) queued_uids.push(uid);
}
// Return the dispatcher already in queue, to be reused here
return queuedCall.dispatcher;
}
else {
// Create our own call via callAPI
var args:URLVariables = new URLVariables();
args['fields'] = ['first_name', 'last_name', 'sex', 'affiliations'];
args['uids'] = uids;
return callAPI('users.getInfo', args);
}
}
// Authentication getters
private static function get_property(property:String):String {
if (parameters.hasOwnProperty(property))
return parameters[property];
return null;
}
public static function get api_key():String {
return get_property("fb_sig_api_key");
}
public static function get secret():String {
return get_property("fb_sig_ss");
}
public static function get session_key():String {
return get_property("fb_sig_session_key");
}
public static function get uid():String {
return get_property("fb_uid");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment