Tuesday, March 3, 2009

File Sharing using Stratus (Part 2: Send file example)

As described in previous post, I was experimenting with the new Stratus service introduced by Adobe with the relase 10 of Flash Player.

After going over the VideoPhoneLabs example by Jozsef
Vass, I was curious about trying to use the same approach for a different need, in this case a binary file transfer, having in mind P2P file sharing in Flash.

Here it is the resulting app:


Remember Flash 10 or newer is required. Test your current verision here.

Notes:
By a quick search, I came across this forum post where someone asked about the possibility of doing this and there was the confirmation by using the NetStream’s “send()” method to send any kind of content.

A guy called Kris in Duesseldorf did also introduce his work in that thread, and these posts about transferring Classes between peers were also quite interesting.
communicating arbitrary data via rtfmp (pt. 1)
communicating arbitrary data via rtfmp (pt. 2)



So hands on, let’s code a proof of concept that is capable of sending files through peers!

I. Use case:

A user will log in into the application using a nick name and he/she will get a List of other users connected to it. He/she will be able to choose one of the connected users, select one of the files in his/her local filesystem and send it to the target peer. He/she (the destination user), will be prompted to accept/deny the new incoming file.

This is just a proof of concept and is not intended to work as a production application, so there’s no work related to security, performance or other possible improvements.


II. User management service:

As described in the previous post, Stratus is a service used to manage the connection between 2 peers and allow them to communicate directly, but the way one discovers each other, how they meet, is out of scope of the service.

In Josez Vass example, a “reg.cgi” file with the structure of a python web app is provided, with the idea of people interested in running the example deploying it into his/hers own systems. It’s great he provided this script, b
ut it was a subject and a technology totally disconnected from were the example is about, Flex and Stratus.

I started looking how to deploy this script when I thought that it would be great if I could offer access to it to anyone trying my example, to avoid this non related subject/technology barrier. So it was a great excuse to st
art with Python, Django and Google’s AppEngine, and my first dummy Google AppEngine application came out!

If you run the example, you’ll be connecting to a Django application hosted in http://stratus-demo-service.appspot.com/ . It’s so simple and, probably, so bad coded, so I’ll keep the code, but feel free to ask for it if
someone wants to check.

It just implements the same API as Josez’s python script, so if you want to use it to try VideoPhoneLabs application, just go and change the WebServiceUrl constant in VideoPhoneLabs.mxml file to

private const WebServiceUrl:String = "http://stratus-demo-service.appspot.com/"


This app has three possible calls:

  • http://stratus-demo-service.appspot.com/?username=myUserName&identity=12345678901234567890 will register the requesting usename with the nearID passed as “identity” in to the system. This just stores a triple username-nearID-updatetime into a Django Model (in this case, a google.appengine.ext.db.Model object), that contains those three files. Successive calls with the same username will result in updating this updatetime field, used to timeout unactive users.
  • http://stratus-demo-service.appspot.com/?listUsers=true will retrieve a list of all currently conneceted users. Are considered connected users those that made a “PING” call to the system (a user register call) before than 2 minutes ago (so user connections expire after 2 minutes).
  • http://stratus-demo-service.appspot.com/?friends=username1&friends=username2 will retrieve the list of just the given usernames with their ids. This called is provided for compatibility with the VideoPhoneLabs example but it’s not used for the File Sharing one.



As said before, this is my first Python, Django and AppEngine app, so please don't be very strict if something is not working ;-)


III. File Sharing itself:
So, with the user management problem solved, I proceed to creat a project to illustrate the file sending functionallity. The structure is similar to the VideoPhoneLabs application, but without the camera/mic setup and managing the user connection to the user management system all in a single .mxml file. I just wanted to make the code easy to follow, so I tried to write it in the execution order, and avoid adding any auxiliar file.

Then in the file, you’ll see the following structure:

0. Stratus service connection code. Here, a NetConnection object that handles the connection to the Stratus service is set up.
1. Registering to the user management service. A call to the AppEngine service is done here to register the new nearID provided by the Stratus service in section 0. This code will be called regularly to maintain the user session alive. Once the user is registered, a NetStream “listenerStream” is created to recieve incoming file transfers.
2. Userlist request. The result is parsed into an Array used as binding source for a ComboBox of users.

This first sections are common for both, sending and recieving users.

3. Makes the handling for File selection from the browsed file system.
4. Waits for the “Send” button to be pressed. If it is the case and a destination user has been chosen, a NetStream “outgoingStream” is published. This is stream is the one the receiving user will register to to download the transfered file. So once it is published, the sending user asks the receiving if he/she would be so kind to ask it “please”. This sounds ironic, but is the only way of the transfer to start... if the destination user asks it, that is, if the destination user registers to a origin’s user NetStream (in this case, the “outgoingStream” we’ve just created).
5. The recieving user is pinged in his listenerStream then, and he/she answers subscribing to the sender’s “outgoingStream”, published with the name “fileRequest”.
6. The sender recieves some events, and we’ll wait until a NetStream.Play.Start to invoke the desired function:

switch (event.info.code){
case "NetStream.Play.Start":
log(INFO,"Sending "+sendFile.name+" ("
+sendFile.size+" bytes)");
outgoingStream.send("receiverFunction",
sendFile.data as ByteArray,userName.text,sendFile.name);
break;
}

Receiver “receiverFunction” is called, and the user is prompted to get the file. If he/she answers affirmatively, a new File with the transfered content is stored were the user decided.



So that’s much it! Try the app at the top of the post, entering a username and waiting for someone to connect... or being more realistic, opening a couple of browsers and simulating being two different users :-P

Here the code. Any kind of feedback is appreciated :-)

Sunday, March 1, 2009

File Sharing using Stratus (Part 1: Jozsef Vass example)

This days I've been playing with the new Stratus service introduced by Adobe with the Flash Player 10 release.

Stratus is a service that enables Flash Player clients to connect directly point to point, to share data (audio, video, binary...). Stratus is just an external actor put between both end points that manages the connection, but doesn't deal with the information transfered, as it is illustrated in the following figure published by Jozsef Vass in its article "Stratus service for developing end-to-end applications using RTMFP in Flash Player".


In the article, Jozsef makes an introduction about Stratus and the Real-Time Media Flow Protocol (RTMFP), introduced also in FP10, built on UDP, that is perfectly suited for audio/video transfers and simplifies connections when clients are behind NATs. To make applications that use this beta service from Adobe, developers have to apply for a developer key.




The article comes with a source code example which is really illustrative, which is a video conference application built in Flex, using the Stratus service.
You can try it out here). Just open a couple of browsers and sign in the application using two different nick names. Once signed, enter your "buddy's" nickname and call him/her to see him/her doing strange faces (as in the picture, me talking to myself).

The example is really cool, and a great start point for plenty of possible applications where messaging is involved. I found it a little tricky to follow, because there are big code jumps, 2 user scenarios depending on whether one is calling/answering, and some auxiliar classes to deal with the user login service.



How does the connection process work?

I think this is the interesting point in this example. To put both peers in touch, the process is more or less like this:

  • User A connects to Stratus service (rtmfp://stratus.adobe.com) using a NetConnection object, from the application that has a specific developer key. The service assigns the User A an ID.
  • User A registers this ID into some kind of user manager service. This is independent from Stratus and Adobe, and has to manage the pair User Name - User ID.
  • Once registered, User A publishes a listener Stream, that will be waiting for other user connections.
  • User B makes the same process as User A about registering.
  • User B publishes its listener stream.
  • User B decides to call User A, so he/she publishes its media stream, with the audio/video from his/her webcam. At this point, B doesn't know nothing about A, so he/she has to ask te user managment service which ID has the user with name "User B".
  • With the returned ID and through Stratus (by means of the NetConnection object that keeps the connection with Stratus alive), User B reaches User A.
  • User A listener StreamHhandler function is called. This is where by accepting the call, User A will subscribe to User B published media stream and at the same time, A will publish his/her media stream.
  • User A will send a notification to B about it's call acceptance, so B will know he/she can subscribe to A's recently published media stream.
  • A and B will start chatting, fall in love, or whatever.

And it works great! So I started thinking about if it could be also used for other purposes as binary data transmition, and of course, I was not the first to think about it. Anyway, here comes my example!

Monday, December 29, 2008

Keeping DataTips in Charts boundaries

Here goes a little trick I used for an application some time ago. The problem was that data tips that are displayed on mouse overing Flex Charts, fly over the Application content, and in some cases do not respect the visible boundaries of it. This effect can be undesired, and a usability problem because can make the information impossible to read in some situations.

The attached application shows the problem in action.

If you hover the first pair of charts, you'll see the custom created data tip appearing at the right of the central point of the sector being pointed. For the pie on the right, the information is unreadable.
The second set of charts, use another data tip renderer implementation that keeps the data tip in the pie boundaries, making the information always visible.




Get the source code here.



It's so simple, just take care when displaying the data tip in the default position that it fits into its owner chart, and if it's not possible, adjust its position. Hope it helps! And if you find a better way to solve the problem... or see anything that could be improved, please write! ;-)

MAXwidget