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, but 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 start 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 :-)