Archive for AIR
JUICE chat (Stratus Peer to Peer)
Posted by: | CommentsOne of my ongoing weekend projects is an AIR chat application, recently rechristened “JUICE” a.k.a. “John’s Ultimate Internet Chat Experience”. I realize that may only be the case for myself, but the project has been very educational and entertaining for me.
The initial release used AIR/Flex as the front-end, ColdFusion and MySQL for the backend, and BlazeDS messaging for message transmission and “peer discovery”. I worked on it over a couple weeks adding features like encryption, toast-style notifications, as well as a few other less notable things.
I knew the architecture was awful and would never scale beyond a couple hundred users (if that many). Here’s the basics of how it worked:
- The user would login, ColdFusion/MySQL would send back a list of chat buddies.
- Each logged in user would ping the messaging server every 10-30 seconds to announce “I’m still here!”
- The pings would be broadcast to everyone logged in (and connected to the messaging server). The application would filter out the ones it was interested in based on user id.
- Sending messages worked similarly, the user would send the message (which included information about the intended recipient), which would then be broadcast to EVERYONE.
- Everyone would filter this information, and the recipient would know it was for him, and would display it.
You can see why this would not scale well, the amount of traffic and pinging going on. Eventually even a user with only 1 or 2 buddies would notice a significant drop in performance as the number of total users increased. There are some applications of “chat” for which BlazeDS messaging and polling is well suited for (like a chat room). A chat application involving “buddies” is much better suited for P2P.
Enter Stratus. I discovered Stratus a few months ago but was unwilling to delve into it on account of my hectic schedule. Fortunately one of my friends went and did all the dirty work figuring out how to get it up and running (turns out it’s pretty easy) and I was able to apply it to my chat client.
I’m very pleased with the results, though it’s still very much a work in progress. I’ve even been able to add video and voice chat features, which is why I went through the trouble in the first place. Here is how my peer discovery mechanism operates. It requires only 3 calls to the server per client (which I could easily condense to 2 if I wanted).
- The user logs in.
- If the user successfully authenticated, he connects to Stratus and receives his peer ID.
- The user updates his peer ID in the database (which was set to 0) and gets a list of his buddies and their peer IDs. I also update information like whether or not I have a camera/mic.
- The user processes his buddy. If the peer ID is something other than 0, then I know this buddy logged in before me, so I must send him my peer ID.
- Any buddies that have a peer ID of 0 are not logged in, I need to listen for them though since they will get my peer ID when they log in.
- When I log out or close the application, I call the server and reset my peer ID to 0. I also notify all of my connected peers I’m logging out.
There are a few more steps in the process, but it decreases the load on the server significantly, transferring the “burden of proof” onto the clients.
Interesting to note is the way I get the peer ID of a client who connects after me (step 4). I don’t actually have to make a call for this, rather he simply has to start broadcasting to me on the NetStream I set up to listen for him (step 5). When the connection is made, an event will be dispatched by the NetStream class. In fact, 3 events will be fired, I just chose to act on one of them.
The peer ID can be obtained from the peerStreams array on the publishing NetStream. I then use that information to set up my subscribing NetSream.
if (this.peerId == null || this.peerId == "0") {
this.peerId = publishNetStream.peerStreams[0].farID;
this.subscribeNetStream = new NetStream(model.netConnection, this.peerId);
this.subscribeNetStream.client = new NetStreamClient();
this.subscribeNetStream.play(streamName);
}
Anyway,I’m planning on doing another post to outline my video and voice handshake protocols. They’re nothing to write home about, but I’d love some feedback if there’s a better way. I’m also planning on releasing JUICE after I bring it’s level of functionality back up to where the original version was, so stay tuned and you should see my install badge at the bottom of my blog.
Messaging with Flex/ColdFusion via BlazeDS: Part 2 (Flex configuration)
Posted by: | CommentsThis is part two of a two part series. See part one, Messaging with Flex/ColdFusion via BlazeDS : Part 1 (CF configuration)
This installment will go over setting up messaging in Flex, and assumes everything is working correctly on the server. Recall I will be covering two scenarios. A client-publish/client-subscribe model, and a server-publish/client-subscribe model.
Configuring Channels with ActionScript
I prefer defining my channels and channel sets in ActionScript on the client for a number of reasons. It does away with the need for client side configuration files and additional command line parameters that need to be set up each time I check out the project onto a new machine.
A channel is instantiated as follows:
private var pollChannel : AMFChannel = new AMFChannel(“cf-polling-amf”, http://cfserver.domain.com/flex2gateway/cfamfpolling);
The cf-polling-amf corresponds to the channel definition in the services-config.xml file residing on the server. If you gave it a different name previously, or set up a new one, the names should correspond.
The channel set is instantiated as follows:
private var amfChannelSet : ChannelSet = new ChannelSet();
Then, somewhere inside a method (init(), for example) the channel needs to be assigned to the channel set using the addChannel() method. The channel is now ready to use for remoting or messaging.
Publish/Subscribe
There are three classes you’ll use almost exclusively when dealing with AMF messaging. The Producer class, which connects to the messaging channel and is used to send messages. The AsyncMessage class which defines the format of the messages broadcast via the Producer. And the Consumer, which subscribes to the incoming messages received from the server.
The channelSet and destination properties need to be set on the Producer and Consumer, where the destination corresponds to the destination configured in the messaging-config.xml file on the server.
A MessageFaultEvent.FAULT listener can be attached to the Producer to listen for any errors that occur when connecting. And a MessageEvent.MESSAGE listener should be attached to the Consumer to handle messages that are broadcast to the clients.
Finally the consumer must call it’s subscribe method to indicate it is ready to receive messages. A consumer can subscribe and unsubscribe as often as needed.
Publishing a Message
The Publisher sends message to the server in the form of an AsyncMessage. The AsyncMessage class has two properties that we will be concerned with, the headers property and the body property.
The headers property is a dynamic object that you can add any data you want to. In this case we only need to set up one header value (many more are set after you call send() as it moves up the call stack) which is gatewayid. The gatewayid will correspond to the event gateway you set up in your CF Adminstrator.
The body property on the AsyncMessage class is used to send the message payload, and can contain anything. It is an anonymous object, and can have any number of additional properties or objects attached to it.
After setting these properties, the producer calls send, and passes the message as a parameter. The rest happens on the server and in the method that handles the MessageEvent.
Handling the Message Event
Handling the MessageEvent is similar to creating it, only backward. All of the properties that were set when it was published should be there (unless the CFC gateway explicitly removed or overwrote them). Nested in the event is a body and a headers property. They can be accessed as follows:
event.message.body event.message.headers
And that’s all there is to it.
Server Publish
As previously mentioned, the server can also publish messages. This is different from the previous scenario in the following ways:
1. You only need to set up a Consumer… no Publisher is needed since the client will not be publishing messages.
2. A CFC on the server needs to manually publish the message. This can happen in a variety of applications.
This is accomplished in ColdFusion by setting up the event object, and then passing it in a call to SendGatewayMessage(). Here is some sample code demonstrating:
<cfset data.message = “someObjectOrValue” />
<cfset data.type = "optionalValue" />
<cfset event.body = data />
<cfset event.Destination = "AValidDestination" />
<cfset ret = SendGatewayMessage("anEventGateway", event) />
Other Applications
There are a number of configurations you could have that I haven’t mentioned. A Flex application could publish messages and broadcast to a separate Flex or AIR application that is subscribed to the same channel. There are a variety of methods available to filter messages received.
I’ve only just scratched the surface in getting it set up. What I’m excited for is for an RTMP library to become available, as Adobe announced plans to open source it in the first half of this year. We’ll see how that turns out.
Book Review: Flex 3 Component Solutions
Posted by: | CommentsFlex 3 Component Solutions, subtitled Build Amazing Interfaces with Flex Components, by Jack Herrington is an interesting read. Though I worry that the content will become somewhat dated (moreso than a book that covers Flex in a more general light) as time goes on and the community comes out with ever more inspiring custom components.
If you are looking for a book that showcases a bunch of existing Flex components (that aren’t a part of the standard Flex framework) then get this book and enjoy it. The book is well written and organized, and Herrington does an excellent job covering a lot of really cool components that will have people who visit your site asking, ‘Wow, how’d he do that?’
If you’d like to give a more in depth answer to that question than, “I just tied this component into my app” OR if you’re looking for a book that deals more in how to create cool, advanced Flex components (like I was); then you might feel a tinge of disappointment. Chapter 15 is dedicated to this topic, but it will feel like child’s play to anyone who has extended UIComponent.
To anyone who has played around with the “Tour de Flex” application (http://flex.org/tour), many of the examples will seem familiar. In fact, if you enjoyed this book you’ll probably enjoy exploring Tour de Flex. Though there is a lot of overlap, each also showcases components that are not in the other.
Creating components and integrating components are two very distinct (though related) topics. Before deciding to get this book, you should know that it is definitely weighted more towards integrating existing components.
Simple Flex Builder Performance Tip
Posted by: | CommentsI wanted to put this little tidbit out for boosting Flex Builder’s performance on all platforms. I was ecstatic when I got my new desktop this past June (quad-core, 12MB cache, etc., etc.) and the build process flew. It was awesome (see complaints in previous post about my laptop seeming like a dinosaur in comparison), but as time went by it started getting more and more sluggish about building my apps.
There wasn’t any apparent explanation (except for maybe the fact that I was running Windows Vista with only 8GB of RAM) so it was a little disheartening. On the other hand I wasn’t seeing any performance decreases in any of my other “benchmark” apps (JBoss 4.2 startup in 10 seconds, NetBeans startup in 15 seconds, Photoshop CS3 in 8 seconds) so I got a little suspicious.
I did a little searching around and ran a few experiments, and came to realize that the more projects I had open, the longer it would take to build any one of them. When I started closing the projects, there was a corresponding increase in performance. This information allowed me to focus my search efforts and sure enough, Flex Builder will process every open project to see if it needs to be recompiled, and in the process compile the project you’re interested in.
So close some of those projects (right-click, or in case of a Mac two-finger-tap, and close).
Error #2044: Unhandled IOErrorEvent; text=Error #2038: File I/O Error.
Posted by: | CommentsI started this post a few months ago while I was working on an AIR application that uploads files to a remote server (by way of an upload script). I ran into this error, Error #2044: Unhandled IOErrorEvent; text=Error #2038: File I/O Error, which caused me considerable grief until I discovered the simple solution. I got the same error in an application I was working on today, and so decided to finish this post.
I looked up the problem when I first encountered it, and there seemed to be a consensus that the problem was due to using a bad URL for the location of the upload script. That was actually the case for me today, so I was able to fix it right away.
When I encountered the problem a few months ago, you could say that it was from using a bad URL, but it was much less obvious. I had written the upload script in ColdFusion, hosted on a CF server. I was certain that I had the URL typed correctly because I could access it in my browser. I discovered over an hour later that I had an authenticated session that allowed me to see it in the browser, a privilege not shared by the AIR app.
The problem was ultimately remedied by placing a special Application.cfc in the upload script’s directory that did away with the requirement for any session variables. This particular case may have been due to a combination of the CF server’s settings and the fact that I was using AIR, and not a Flex app that might have been served from the same server as the upload script.
Training Videos
Posted by: | CommentsI created a new site where I hope to start posting screencasts of some of the training I’ve been working on. Nothing great yet, but I hope I can build up a helpful library over time. More than anything it helps me understand these concepts better.
URL updated. Well, here it is: http://flexplanations.com
You’ll need Flash player installed to view the training videos. I should mention that I have a quad-core CPU, 4GB of RAM, and a 15Mbps internet connection, and they work fine for me. I have noticed issues on my slower computers with slower internet connections.
Custom Chrome for Adobe AIR Apps
Posted by: | CommentsEvery time I’ve seen one of those “branded” AIR applications with the custom window chrome, I’ve thought to myself “That would be kind of cool,” but I didn’t get around to learning how until now. It’s pretty fun, and is very gratifying for those of you who have a little creative side that likes to come out every now and then.
I start by creating the background image, or custom chrome for my application, along with any other graphical components I’ll need (a close/minimize button, for example). Then you create an AIR application (this assumes Flex Builder). Normally this will give you a default MXML file with a WindowedApplication tag in it. You need to change it to Application (just like for a web project).
Next you should modify the config file, usually AppName-app.xml Specifically you will need to change the following tags: systemChrome, transparent, visible and give them settings as follows (don’t forget to uncomment them… FlexBuilder doesn’t highlight this file properly for me so I always forget these config settings are commented out by default).
<systemChrome>none</systemChrome>
<transparent>true</transparent>
<visible>true</visible>
If you’re not going to allow the user to resize the application, it is a good idea to set the height and the width to whatever size you need. The systemChrome setting tells AIR you’re going to be supplying the chrome (if you don’t, then Adobe’s generic custom chrome will be used if you have it set to “none”). The transparent setting will allow you to click through parts of your application that are not visible. And the visible setting… well if you don’t know what that means, this tutorial probably isn’t for you.
Next you will need a style for the Application to this effect:
Application {
background-color: "";
background-image: "";
padding: 0px;
}
This clears everything out, so to speak. Then you add your chrome image to the Application tag, and you’re pretty much finished. The problem you will have if you run the application at this point is that you will not be able to move it, close it, etc. There are a few event handlers you will need to add to give the app this functionality.
Adding mouseDown="stage.nativeWindow.startMove() to your background image tag will allow you to grip the application by pressing the mouse anywhere on the image, and drag it around. A few of the more useful ones are:
mouseDown="stage.nativeWindow.startMove()"
---- allows you to move the app
For your window icons:
click="stage.nativeWindow.minimize()"
----allows you to minimize your app
click="stage.nativeWindow.maximize()"
----allows you to maximize the app (if it makes sense to do so)
click="stage.nativeWindow.close()"
----allows you to close the app
There are also ways to resize, but I haven’t gotten into that as much yet. At this point you’re finished. Some things to note: Your application will take up as much room as you give it, though it may not all be visible. This is nice if you want to have slide-out menus and such. Putting the close, etc. icons in weird places may confuse your users, as will changing their basic appearance (square, bar, x).
It’s pretty addictive, but it allows you to create applications that are memorable, I don’t think I’ll be able to go back to normal system chrome for a while.
TrueMVC Framework
Posted by: | CommentsAt the organization where I work we are currently building a general purpose framework for Adobe Flex / AIR applications. We do a lot of Flex development there, and have done several large projects based on Cairngorm. It wasn’t working out for us for a couple of reasons, primarily because:
- There was a large chunk of code that had to be included. If this weren’t bad enough, the user needs to have a fair knowledge of this code (as many classes are extended to make use of the framework’s features).
- The learning curve is quite steep, and assumes a basic understanding of several design patterns (especially if you need to create workarounds in areas the framework fails your project).
- A large majority of the development staff are students, and therefore we experience an above average turnover rate compared to the industry as a whole.
Any one of these might not seem so bad, but taken as a whole we needed something simpler. Something with little or no code to extend, and a few basic patterns that could be taught as “conventions” rather than patterns. TrueMVC is (or will be) the result of these efforts. I don’t have a link at the moment to the documentation
The basics of it are as follows:
- All models implement an interface.
- All views bind to the model (which is in fact an instance of
ISomethingModel). - All controllers have the same name as their respective views appended by the suffix “
Controller“. - Controllers reside in the same folder as their views, and are included in the view using a
<Script source="" />tag.
It makes heavy use of binding, in fact the views should only be updated via their bindings to the model (i.e. as per the Model-View-Controller pattern). And that’s pretty much it. We’re in the process of implementing an Active Record-like data object, which will be the only code artifact of the framework (and won’t be necessary, strictly speaking as long as any other data retrieval mechanism gets data and sticks it in the model). There’ll be a separate post about that.
blog.flexexamples.com
Posted by: | CommentsI have this block that won’t allow me to blog about a solution to a problem unless I either A) spent hours agonizing over it, or B) didn’t find anything satisfactory from the search engines. But I just wanted to put in a plug for this site: http://blog.flexexamples.com. A lot of the samples posted on his blog are trivial to someone who’s been developing in Flex for a while (things I’d definitely never devote a blog post to). I frequently find answers to my Flex related questions there, though.
So if by some mistake you’ve found my blog looking for answers to a Flex question, you might have better luck over there.
Lab 5 : Web App to Desktop App using Flex 3
Posted by: | CommentsI’m almost finished with lab 5. On the whole it’s been pretty fun, aside from some of the frustration from minute details that take an hour apiece to hammer out. I had developed most of my application as a web app before the specs came out. Fortunately I was using Flex, so let me show you how easy it was to convert it from a web app to a desktop app.
As a web app, the main page was enclosed in elements like these:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#2C3552" xmlns:local="*">
.
.
.
<mx:Application>
To deploy it as a desktop app, I had to change it to:
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#2C3552" xmlns:local="*">
.
.
.
<mx:WindowedApplication>
and then recompile. And that’s it. And this may appeal to those of you with high design sensibilities– it looks the same on the desktop as it does on the Web. Incidentally, on the web it looks identical on every browser/platform combination (any platform that has a Flash player, that is).

