Showing posts with label social networking. Show all posts
Showing posts with label social networking. Show all posts

Thursday, September 1, 2011

Accessing the Twitter Streaming API from Adobe Flex/AIR

Over the weekend I discovered an interesting new hobby, so being the geek that I am I wrote a mobile application to support it. I found that I really like watching the pictures people post on Twitter in real-time. This was based around hurricane #irene so seeing the incoming photos was awesome, although I suppose it could also be applied to even more interesting endeavors like #friskyfriday (NSFW) ;) In the application I wrote I wanted to connect to the Twitter live stream instead of using search. Although it doesn't send you the full firehose of tweets, I wanted everything in real-time for geek-ability.

I won't post all the gory details of getting this application up and running, but there were two things that anyone developing for this API will need to do, and here they are:

1. Connect to the Streaming API


I had tried to do this in the past and had much more luck using curl or Java to coax the tweets out of the Streaming API, but this time I wanted to do it all in ActionScript as I didn't want to keep track of anything in a database. I wanted real-time streaming of data as it came in, and nothing historical. To do this I used the URLStream class. URLStream opens a HTTP request and then downloads the received data as it comes. URLStream is especially suited to this type of request as the download does not have to finish before you can access the downloaded bytes. This means two things: 1) You can read the bytes as they come and maintain the connection to keep receiving bytes, and 2) you must be super careful, as the Streaming API sends chunks of data. This means that the last chunk you received from Twitter might not be a complete object. You can imagine what this does to the parser (more on this later).

The Streaming API current supports both basic and OAuth authentication. Twitter says that basic authentication is deprecated, so use at your own risk. This article will use basic auth as OAuth and Twitter has been done to death on
other blogs.

While setting up the stream controller, we will create a property that will hold our URLStream. This must exist in the scope of the controller as all of the events will interact with this stream as the URLRequest is processed.

private var stream:URLStream;
After instantiating the class we need to set up our URLStream. This is accomplished by defining a new request, setting the URI we want to hit, setting the basic auth parameters and finally adding event handlers to react to the data streaming in or any errors that might occur.

public function startStream():void {
  stream = new URLStream();
  var request:URLRequest;
      
  request = new URLRequest("http://stream.twitter.com/1/statuses/filter.json?track=&include_entities=1");
  
  // set up basic auth
  var encoder:Base64Encoder = new Base64Encoder();
  encoder.encode(appController.username + ":" + appController.password);
  var credentials:String = encoder.toString();
  var authHeader:URLRequestHeader = new URLRequestHeader("Authorization","Basic " + credentials);
  //add the header to request
  request.requestHeaders.push(authHeader);
  request.method = URLRequestMethod.POST;
  
  // in a real app I would also recommend handlers for SecurityErrorEvent.SECURITY_ERROR, IOErrorEvent.IO_ERROR at a minimum
  stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
  
  try {
    stream.load(request);
  } catch (error:Error) {
    trace("Bad URL.");
  }
}
A few notes about the code above... First, there is a track parameter being passed but it is currently empty. This allows you to filter your request. For my example I let the user enter this in on a prior view and passed it in via an application controller. Second, we are only listening for a single event, ProgressEvent.PROGRESS. In the real application I suggest you listen for at least security errors and input errors. You can also listen for HTTP status codes. This is important and Twitter would like for you to watch those codes and throttle your requests accordingly. Please make sure to do this or they will terminate your stream. Lastly, please note that we are requesting the response to be JSON. The streaming API only allows you to request JSON. Next, we need to define our handler. The one I am concerned with for this tutorial is the progress handler (it handles the ProgressEvent.PROGRESS event). When a progress event is received you can check the Stream object to see if enough bytes have been loaded to process the stream's data. In this application I didn't care how much data had been sent as I was more concerned with if the data available had any complete tweets (JSON objects) in it. To do this I fire off an event to another controller which processes the data.

private function progressHandler(event:ProgressEvent):void {
  // read the bytes
  var x:ByteArray = new ByteArray();
  stream.readBytes(x, 0, stream.bytesAvailable);
  
  // create an event to create the picTweets from the JSON
  var te:TweetEvent = new TweetEvent( TweetEvent.NEW_TWEET_RECEIVED );
  te.json = x.toString();
  // I'm using Swiz to dispatch my events - perhaps you should be also ;)
  dispatcher.dispatchEvent(te);
  
  trace("Progress Event Handled.");
}
We read the bytes from the stream as a ByteArray. The ByteArray data is then sent across to the other controller as a string using a custom event. The custom event looks like this:
package events
{
  import flash.events.Event;
  
  public class TweetEvent extends Event
  {
    public static const NEW_TWEET_RECEIVED:String = "events.TweetEvent.NEW_TWEET_RECEIVED";
    
    public var json:String;
    
    public function TweetEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
    {
      super(type, bubbles, cancelable);
    }
  }
}

2. Parse the resulting data


The handler for this event takes the JSON response and adds it to any other text left over in the buffer from prior requests. We then need to parse the JSON text to look for complete objects to deserialize. Twitter made this easy. They send along a newline character at the end of each JSON object. Simply split() the JSON text on newline and you'll have an array of objects. By trying to deserialize any of these objects using the JSON class (available from the
as3corelib package) we can create tweet objects. Any text that can't be deserialized will be put back into the String variable that is holding the JSON data to be parsed with the next data stream response.

public function handleNewTweet(json:String):void {
  // add the new json to the text storage - this is a private var for this controller
  jsonText += json;
  
  // now parse through the text for newline chars, which denote the end of a JSON object
  var aJSON:Array = jsonText.split(/\n/);
  
  
  if ( aJSON.length ) {
    // clear the jsonText for appending any partial objects
    jsonText = '';
    
    for ( var i:String in aJSON ) {
      // try to deserialize, if we error, we dont have a complete object in that array, add it back to the queue (it will always be the last item in the array that fails, if any)
      // deserialize the JSON
      if ( aJSON[i].length ) {
        try {
          var tweet:Object = JSON.decode(aJSON[i]);
          
          var j:String;
          
          // HERE IS WHERE YOU CAN ACTUALLY PROCESS THE TWEET
          
        } catch ( e:Error ) {
          // here is where we add the partial object back into the jsonText variable - will be appended to the next response
          if ( aJSON[i].length && aJSON[i].indexOf('\r') != 0 ) { jsonText += aJSON[i]; }
        }
      }
    }
  }
}
For my purposes I just parsed the entities for media and displayed it within my application. You have the full status object to play with for your application. Have fun, and if you use this drop me a comment so I can check it out!

Thursday, June 25, 2009

Mixing it Up: Defining the Corporate Solution

At a high level, solving the corporate issue can be accomplished by performing the following:
  1. Identify what networks to monitor initially
  2. Define what criteria makes a node the most influential for each network
  3. Identify the most influential nodes within each social network
  4. Identify which nodes belong to more than one of the networks
  5. Also, allow an entity to define what networks have more weight than others
  6. Rank each node according to influence across entire set of networks
The end user perspective is a bit more challenging but necessary since this is the dataset we need to crunch to perform the aobve. I will begin to tackle that in my next post.

Wednesday, June 24, 2009

Mixing it Up: Corporate Perspective


More and more companies are beginning to understand the importance of social networks within their marketing campaigns. I received an email from buy.com this morning with an extensive Twitter campaign. In the case of buy.com's campaign, they focus on existing buy.com customers to extend the invitation and then pull them into Twitter and furthermore require them to become a follower of @buy_com. This enables buy.com to grow within the Twitter network and push new campaigns, as well as have their followers tweet to their own networks.

Now, once they have the followers and retweets, what next? How do they keep their message from being diluted, lost in the shuffle, or from becoming Spam? Companies need to determine the most influential nodes within their network to ensure targeted campaigns that reach as many people as possible but do so in such a manner that the message is not diluted or Spammy, but come directly from a trusted member of the social network.

How do we determine the most influential people within a social network? Well, we can easily define who within our network is connected to the most people. Consider the following image:

While two members of this network have 6 connections, the highest number of friends within this example, they are probably not the most influential. The person in the middle of the graph with only three connections is the sole link between the two subgroupings. This does not necessarily make them the most influential, but is meant to illustrate the concept that more connections does not mean more influence. Even with this determination, many more factors need to be taken into account.

There are several algorithms that are helpful in targeting the key influencers within a social network (beyond the scope of this posting). One limitation of running these algorithms within a network is that they fail to take into account the connections between disparate networks. Defining what edges are key influencers within Twitter that are ALSO key influencers within Facebook is an awesome tool for an advertiser within a corporation. If we can break down the barriers between the individual social properties, the possibilities are endless.

User stories:
  • As a company I can determine key influencers that bridge multiple social networks so that targeted advertising reaches as many trusted nodes as possible
  • As a social network I can determine key influencers within my own network that are also key influencers within a competing network so that I can bring more nodes into my own social property

Mixing it Up: End User Perspective

In continuing my open source social network project transparency theme, I'm going to post two perspectives with several use cases. The first perspective I'll post is the end user.

As a user of multiple social networks that understands that there exist tons of other networks I currently do not belong to, I have a hard time deciding where to spend my time and effort. The two I use most heavily are Twitter and Facebook.
  1. Twitter - Allows me to connect with my followers on mostly non-personal conversation, instructional items and interesting tidbits as well as find others with similar interests.
  2. Facebook - Allows me to connect with trusted friends and colleagues and post personal comments and updates.
These networks take time and effort to upkeep and there may be great social circles I am missing out on just because I do not know I already have a following on them which would allow me to test the waters without having to invest time building up a circle of followers.

Currently, I can import contacts from other social networks and online services, however, until I create an account I have no idea.

User Stories:
  • As an end user I want to be told that a friend in one social network belongs to another social network that I am a member of so that we can connect in multiple mediums.
  • As an end user I want to be told that a friend in one social network belongs to another social network that I am NOT a member of so that I may join and connect in another medium.

Tuesday, June 23, 2009

You Need to Mix it Up

From Thesaurus.com:

'..in a mixture, the combined elements lose their individual identities and are fused, blended, or compounded in the result; in a mix, the elements, though combined, retain their individual identities.'

My next opensource project is currently in the planning stages. The idea is to help identify the connections between diverse social networks. I plan to run this project in the open (think 'transparency') so I can learn from my mistakes as well as get input from the Internet community as a whole. More to come over the next few days...