WTF is WIM?
Steven G. Chipman
Principal Software Engineer, AOL
WIM is...
- A host based JSON/XML API for interacting with the AIM service.
- A Javascript API that takes care of the business of interacting with the host API.
- Very Web Twopointoh, and therefore 2.0pen.
- Pretty freakin' cool.
WIM ain't...
- AIM Express
- Hard to use or get up to speed with.
What can I do with it?
First, the super-easy stuff:
- Use one of the "Whimsicles" to embed functionality in your page.
- Buddy List
- Presence Information
- IM
Ok, how?
We'll use the Buddy List widget as an example.
- Add a reference to aimapi.js to the head of your document.
- Add an element with an id of "AIMBuddyListContainer" with an attribute named "wim_key" with your developer key as its value.
- Add an anchor element with an onclick handler that fires "AIM.widgets.buddylist.launch();".
- Done.
In other words, just this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="http://o.aolcdn.com/aim/web-aim/aimapi.js"></script>
</head>
<body>
<div id="AIMBuddyListContainer" wim_key="12345678"></div>
<a href="nojavascript.html" onclick="AIM.widgets.buddylist.launch(); return false;">Launch My Buddy List</a>
</body>
</html>
An Example.
Great, I have a Buddy List. Now what?
Well, you could make it look however you want with just CSS...
Speaking of CSS
We've provided loads of design hooks in the CSS to make skinning as flexible as possible, such as:
- Even/odd classes to provide for alternating styles for buddies and entire groups
- AIM ids are also class names.
- All very verbosely named.
Every aspect of the list is customizable.
Or you could add new functionality...
- Add additional icons to the buddy list.
- Only show buddies that share similar interests.
- ...or whatever else you can think of.
After all, this is just HTML and easily accessible via the DOM. As such, it is infinately hackable and mashup-able.
An example:
You could check if a person in the buddy list has a public gallery on pictures.aol.com, and if so - add a link next to their name to that gallery.
Another example:
What if a popular online shop stored your AIM id with your information, and the service provided a "wishlist" feature? That shop could add links to the buddy list that go off to that user's wishlist, or only display buddies with wishlists in a side menu.
Or do things that aren't Buddy List related at all...
- Two player javascript games.
- Bots.
- Extended IM capability - for example, a Picto-Chat like interface.
How it works - a WIM Walkthrough.
What follows is a step by step examination of what happens from the time a user clicks "Launch my Buddy List" until they see their list render.
(Its not as boring as it sounds, really.)
AIM.widgets.buddylist.launch
Does generic checks and environment setup.
- Is the browser supported? (We don't block, we only inform)
- Does the AIMBuddyListContainer exist in the DOM?
- Do we have an API key?
A moment for client/host communications
- All transactions occur over HTTP using dynamically created script elements via the AIM.core.requestData method.
- Client to host transactions look like this: http://api.oscar.aol.com/im/sendIM?arguments
- The host then responds with either XML or JSONP based on the format you've asked for in the above arguments.
- After the response is handled, the script element is destroyed.
Those URL arguments are...
- k - The key the API found on AIMBuddyListContainer's wim_key attribute.
- f - The format of the response. Values are json or xml. The javascript API always passes json.
- c - The callback that the returned json object should be passed to. The API routes all responses through AIM.core.acceptData.
The Host Response
A response for a client to host transaction would look like this:
AIM.core.acceptData({
statusCode:200,
statusText:"Ok",
requestId:"2",
data:{
aimsid:"13.1271104237:iheartwim",
fetchBaseURL:"http://64.12.162.163:80/aim/fetchEvents?aimsid=13.1271104237:iheartwim",
myInfo:{
aimId:"iheartwim",
displayId:"I Heart WIM",
state:"online",
onlineTime:0,
idleTime:0,
presenceIcon:"http://o.aolcdn.com/aim/img/online.gif",
profileMsg:"yo"
}
}
})
From Host to Client
If the host has something it needs to tell the client, it does so through the "listener" script via AIM.core.listen. An event update would look like this:
AIM.core.listen({
fetchBaseURL:"http://64.12.162.163:80/aim/fetchEvents?aimsid=14.1727053795:iheartwim&seqNum=53",
timeToNextFetch:500,
events:[{
type:"presence",
eventData:{
aimId:"slayeroffice2",
displayId:"slayeroffice2",
state:"online",
presenceIcon:"http://o.aolcdn.com/aim/img/online.gif"
}
}]
})
How does the client know what to do?
- Every transaction and event type can have multiple callbacks assigned to it.
- Example: AIM.params.callbacks.listener.presence = ["AIM.ui.updateBuddyList"];
- Every time a presence event is received, AIM.ui.updateBuddyList is called. Additional callbacks can be pushed into the array, and each will be passed the JSON object from the host.
This model makes it very easy to modify or overwrite the default behavior of the API.
The Listener
- A script element that holds open a connection to the host, waiting for event notifications.
- In non-Mozilla browsers, this is a 60 second "long poll". In Mozilla, it is a two second poll.
- When the listener receives an event or events, it is processed, the listener is destroyed, and a new listener is created.
Final notes on client/host communication
If using the base API, it is unlikely that you'll need to create or destroy listener or transaction script elements. All of this is taken care of by the various transaction API, such as AIM.transactions.sendTextIM.
You pass it the AIM id and the message, and it takes care of everything we just covered. That means you don't have to manage URL arguments or the host API URLs or any other minutia.
AIM.transactions.getToken
The entry point that starts up communication between client and host. Takes a list of event subscriptions as its argument.
- Code 200: The user is logged in via SNS, and a token that will be used on all transactions is passed back.
- Code 450 or 401: Token fetch failed. A redirect URL is provided, which will be opened in an iframe. Generally the SNS sign in.
- Any other code: We fail over and bail out completely.
In case of a 401 or 450
The iframe is created, but how do we know that the user has authenticated? Or canceled? Or done nothing at all?
- Using fragment identifiers, the iframe can talk with the parent document, allowing cross domain communication.
- The API watches for these identifiers and takes the appropriate actions when it finds them.
For example, when the user successfully completes the login process, #AUTHDONE is sent to the parent document.
Now that the user has logged in...
We can call getToken again, and this time we'll get a successful response with a token. Now we can start a session with the host.
AIM.transactions.startSession
- Code 200: All is well, and we'll start receiving event notifications immediately.
- Code 450: The user hasn't granted the application permission to take the requested action. We need to get that permission.
- Code 451:The user doesn't have the appropriate rights to use the application. Example: a kids account.
- Any other code: Alert the user that we're having technical problems and to try back later.
Mother May I...
- Any application requesting access to the buddy list or to send IMs must first get permission from the user to do so.
- The permission URL is served in the same manner as the login screen.
- Users may choose to "Grant Once", "Grant Always" or "Decline".
- Action is communicated back to the parent document via fragment identifiers, i.e. #CONSENTDONE and #CONSENTCANCEL
Now that thats outa the way
We'll start getting events coming down the pipe.
- The first is the "buddylist" event, a massive JSON object containing the entire buddy list, complete with presence data.
- The API accepts this data and builds the buddy list with it.
- From there, events come in as they happen. Buddies signing on and off, changing states, incoming instant messages, typing status, etc.
How Does the API Break Down?
The API is broken out into several objects:
- AIM.transactions
- AIM.params
- AIM.core
- AIM.ui
- AIM.util
- AIM.widgets
AIM.transactions
Provides client to host communication methods.
- sendTextIM
- setTypingStatus
- setState
- etc...
AIM.params
Defines various parameters that direct how the API behaves.
- Display Text
- The Availability Menu Construct
- Constants like SHOW_OFFLINE and RENDER_SEND_BUTTON
AIM.core
Contains all of the methods that the Javascript API can't live without.
- createAuthWindow
- requestData, acceptData
- listen
AIM.ui
Provides methods for creating a buddy list, windows, and accessing parts of the UI.
- createBuddyList, createAvailablityMenu, createIMWindow
- setIMWindowZIndex
- getIMWindows, showVisualNotification
AIM.util
A series of utility methods.
- Style sheet creation
- Cookie methods
- addClass/removeClass
AIM.widgets
Methods to handle Whimsical setup.
Questions?
Thanks for coming!