<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8153350445724118154</id><updated>2012-02-17T16:18:29.228-08:00</updated><category term='ret'/><title type='text'>Random Goo</title><subtitle type='html'>O O O O Random Thoughts O Mine</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-1360878073186182310</id><published>2012-02-15T14:13:00.000-08:00</published><updated>2012-02-15T14:13:25.316-08:00</updated><title type='text'>An Implementation</title><content type='html'>&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Get caught up:&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 1:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html"&gt;http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html&lt;/a&gt;&lt;span id="goog_565352830" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;span id="goog_565352831" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;"&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 2:&lt;/span&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/events.html"&gt;http://randomgoo.blogspot.com/2012/02/events.html&lt;/a&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 3:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html"&gt;http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html&lt;/a&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 4:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/event-hub.html"&gt;http://randomgoo.blogspot.com/2012/02/event-hub.html&lt;/a&gt;&lt;br /&gt;Part 5:&amp;nbsp;&lt;a href="http://randomgoo.blogspot.com/2012/02/deploying-event-hub-application.html"&gt;http://randomgoo.blogspot.com/2012/02/deploying-event-hub-application.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have cobbled together an Event Hub implementation here:&amp;nbsp;&lt;a href="https://github.com/zzo/EventHub"&gt;https://github.com/zzo/EventHub&lt;/a&gt;.&lt;br /&gt;This implementation happens to be in Javascript and it built upon &lt;a href="http://socket.io/"&gt;socket.io&lt;/a&gt;. &amp;nbsp;Which means besides being very easy to add to client-side modules, there is support for many languages on the server side including Erlang, Lua, Java, Perl, Go, Python, Ruby, Flash, and of course Javascript. &amp;nbsp;See the &lt;a href="https://github.com/learnboost/socket.io/wiki/"&gt;socket.io wiki for details&lt;/a&gt;. &amp;nbsp;The Event Hub itself is also available as an npm package.&lt;br /&gt;&lt;br /&gt;The actual Event Hub code is very small. &amp;nbsp;It actually uses the connect frame work for transport and serves the static socket.io and Event Hub client libraries itself (there are currently 2, one for YUI and another for jQuery - feel free to add more!). &amp;nbsp;There is also a NodeJS client-library for NodeJS client to connect to the hub. &amp;nbsp;Check out the examples/ directory for how to use all of this stuff.&lt;br /&gt;&lt;br /&gt;You have a couple choices when starting server-side event hub modules. &amp;nbsp;They can either all be completely separate processes, which is cleanest. &amp;nbsp;Each server-side module would sit on its own port connected to the event hub completely independent of each other. &amp;nbsp;They can all be on separate hosts, however you want to do it - they are all completely separate from each other.&lt;br /&gt;You can also start them all up in one shot and multiplex their port amongst them. &amp;nbsp;While this is perhaps easier to do initially, if you need to restart any one of them you will need to restart all of them.&lt;br /&gt;&lt;br /&gt;Let's look at some examples!&lt;br /&gt;&lt;br /&gt;Here is a NodeJS EventHub client:&lt;br /&gt;&lt;br /&gt;&lt;pre class="postCode"&gt;var eventHub = require('eventClient.js')&lt;br /&gt;                     .getClientHub('http://localhost:5883?token=SECRET');&lt;br /&gt;&lt;br /&gt;eventHub.on('eventHubReady', &lt;br /&gt;    function() {&lt;br /&gt;        eventHub.on('HelloWorld', &lt;br /&gt;            function(data, callback) {&lt;br /&gt;                // SESSION key is in data['eventHub:session']&lt;br /&gt;                callback(null, { mark: 'trostler' });&lt;br /&gt;             }&lt;br /&gt;            , { type: 'unicast' }&lt;br /&gt;        );&lt;br /&gt;&lt;br /&gt;        eventHub.on('eventClient:done', &lt;br /&gt;            function(event) {&lt;br /&gt;                console.log('DONE LISTENING FOR ' + event);&lt;br /&gt;                // wait for us to finish processing any current&lt;br /&gt;                //    event and then....&lt;br /&gt;                process.exit(0);&lt;br /&gt;            }&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So we connect to the hub using the secret key ('SECRET' in this case).  If we successfully connect (because the token is correct) we become a 'trusted' module and can listen for 'unicast' events.  &lt;br /&gt;If the connection is established we listen for a 'HelloWorld' event, telling the EventHub this is a 'unicast' event - so only send these events to us.  That also means the Hub will sent us an 'eventClient:done' event if someone else comes along and starts listening for this event too - so we also listen for that event.  If we get that event we shut ourselves down gracefully.  And finally 'trusted' modules will also receive the session key of the client who emitted this event - and will be available to this modules in data['eventHub:session'] in the event data.&lt;br /&gt;Upon receiving a 'HelloWorld' event, we do some processing and call back to the emitted using the supplied callback.  We follow the convention that the first argument of the callback is an error object or string if there was an error, and whatever data in the second callback argument.&lt;br /&gt;&lt;br /&gt;Now let's look at something that might emit this event:&lt;br /&gt;&lt;br /&gt;&lt;pre class="postCode"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://dashr.net:5883/socket.io/socket.io.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://dashr.net:5883/yui3.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;button id=&amp;quot;button&amp;quot;&amp;gt;Press Me&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;    YUI().use('node', 'EventHub', function(Y) {&lt;br /&gt;&lt;br /&gt;        var hub = new Y.EventHub(io, 'http://dashr.net:5883');&lt;br /&gt;        hub.on('eventHubReady', function() {&lt;br /&gt;            var helloWorld = hub.addEvent('HelloWorld');&lt;br /&gt;            Y.one('#button').on('click',&lt;br /&gt;                function(event) {&lt;br /&gt;                    helloWorld.fire({ button: 'clicked' },&lt;br /&gt;                        function(error, data) { &lt;br /&gt;                            Y.log(&amp;quot;callback from event listener!&amp;quot;);&lt;br /&gt;                        }&lt;br /&gt;                    );&lt;br /&gt;                }&lt;br /&gt;            );&lt;br /&gt;            hub.on('someOtherEvent', function(data, callback) {&lt;br /&gt;                Y.log("Got some other event!");&lt;br /&gt;                callback(null, { hello: "stranger" });&lt;br /&gt;            });&lt;br /&gt;        });&lt;br /&gt;    });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ok so check it out - first we load the YUI seed (we'll use the YUI EventHub client), socket.io and the YUI event hub library.  Note we can load those last two scripts directly from the EventHub itself.&lt;br /&gt;We then connect to the hub and when ready we use a convenience function in the client YUI library to create a 'shortcut' for the HelloWorld event we are going to fire.&lt;br /&gt;So when someone clicks our button we fire the HelloWorld event and set up the callback for the response.  At some point the callback comes back and Bob is your uncle.&lt;br /&gt;&lt;br /&gt;Listening for events is just as easy, here I'm not using the convenience 'addEvent' method and just listening for 'someOtherEvent' and calling its callback function back when I get it.&lt;br /&gt;&lt;br /&gt;The jQuery example is remarkably similar!&lt;br /&gt;&lt;br /&gt;&lt;pre class="postCode"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://dashr.net:5883/socket.io/socket.io.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;script src=&amp;quot;http://dashr.net:5883/jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;button id=&amp;quot;button&amp;quot;&amp;gt;Press Me&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;    var hub = new $.fn.eventHub(io, 'http://dashr.net:5883');&lt;br /&gt;    hub.bind('eventHubReady', function() {&lt;br /&gt;        var helloWorldEvent = hub.addEvent('HelloWorld');&lt;br /&gt;        $('#button').bind('click',&lt;br /&gt;            function(event) {&lt;br /&gt;                console.log('clicked on button - making new event for hub');&lt;br /&gt;                console.log(clickEvent);&lt;br /&gt;                helloWorldEvent.trigger({ button: 'clicked' },&lt;br /&gt;                    function(error, data) { &lt;br /&gt;                        console.log(&amp;quot;callback from event listener!&amp;quot;);&lt;br /&gt;                    }&lt;br /&gt;                );&lt;br /&gt;            }&lt;br /&gt;        );&lt;br /&gt;     &lt;br /&gt;        // listen for some other event&lt;br /&gt;        hub.bind('someOtherEvent',&lt;br /&gt;            function(data, callback) {&lt;br /&gt;                console.log('got someOtherEvent');&lt;br /&gt;                console.log(data);&lt;br /&gt;                callback(null, { mark: 'rox' });&lt;br /&gt;            }&lt;br /&gt;        );&lt;br /&gt;    }); &lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For jQuery we use the jQuery syntax of 'trigger' and 'bind' instead of 'fire' and 'on' but everything else is pretty much the same.  We use the client utility method 'addEvent' for the HelloWorld event but don't for the 'someOtherEvent', totally optional to use the syntactic sugar 'addEvent' provides for you.&lt;br /&gt;&lt;br /&gt;It's equally easy to add clients in other languages that socket.io supports - or any language with a Web Sockets library.&lt;br /&gt;&lt;br /&gt;Finally starting the event hub is easy:&lt;br /&gt;&lt;br /&gt;&lt;pre class="postCode"&gt;% node eventHub.js&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For now you need to edit 'eventHub.js' itself if you want to change the port (5883) or the secret used to determine trusted clients.&lt;br /&gt;&lt;br /&gt;If you installed EventHub using npm try:&lt;br /&gt;&lt;br /&gt;&lt;pre class="postCode"&gt;% npm start EventHub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Have fun out there and stay tuned for even more!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-1360878073186182310?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/1360878073186182310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/implementation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1360878073186182310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1360878073186182310'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/implementation.html' title='An Implementation'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-4761916834792269326</id><published>2012-02-15T11:46:00.000-08:00</published><updated>2012-02-15T11:46:20.910-08:00</updated><title type='text'>Deploying an Event Hub application</title><content type='html'>&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Get caught up:&lt;/span&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 1:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html"&gt;http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html&lt;/a&gt;&lt;span id="goog_565352830" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;span id="goog_565352831" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;"&gt;&lt;/a&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 2:&lt;/span&gt;&amp;nbsp;&lt;a href="http://randomgoo.blogspot.com/2012/02/events.html"&gt;http://randomgoo.blogspot.com/2012/02/events.html&lt;/a&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 3:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html"&gt;http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html&lt;/a&gt;&lt;br /&gt;Part 4:&amp;nbsp;&lt;a href="http://randomgoo.blogspot.com/2012/02/event-hub.html"&gt;http://randomgoo.blogspot.com/2012/02/event-hub.html&lt;/a&gt;&lt;br style="background-color: white;" /&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;An oft overlooked key piece to any application is its deployment. &amp;nbsp;Deploying a 'traditional' HTTP-server based application is a one-shot all-or-nothing affair. &amp;nbsp;Typically even the smallest server-side change requires a full-blown deploy and restart of all of your HTTP servers. &amp;nbsp;Well that blows.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Compare with an event-based application consisting of a federation of independent processes that comprise the application. &amp;nbsp;You only need to deploy and restart small, independent pieces of the application for updates, not the entire thing.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Now it's not all wine and roses (or beer and&amp;nbsp;dandelions). &amp;nbsp;There is more complexity because there are more pieces. &amp;nbsp;But small and independent beats large and monolithic even with the extra complexity, of which there isn't &lt;b&gt;that&lt;/b&gt; much.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;But the biggest issue is dropping events. &amp;nbsp;HTTP servers have 'graceful' shutdowns, ensuring all current requests are satisfied before shutting down, ensuring remote clients aren't left in the lurch during a restart, what about Event Hubs?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Glad you asked, let's look at the scenarios:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;Server Side&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;1. Broadcast events&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Broadcasted events are sent to every connected module. &amp;nbsp;Each broadcast event listener should listen for a signal or other outside data that tells it to shutdown. &amp;nbsp;So to shut down and restart a broadcast event listener, simply bring up the newer version of the listener and tell the old one(s) to shutdown.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Like a 'graceful' shutdown the current about-to-be-shutdown listeners should immediately stop listening for the given event, wait until they are done servicing any existing events, and then shut down if that is the only event that module is listening for.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Here is where putting a version number in the event name is also useful. &amp;nbsp;If using this method bring up the new listener that listens for the new event name with the updated version number and update the clients to use this new event name. &amp;nbsp;As clients start calling the new event name (with an updated version number in it) the old listeners duties trickle away until it can be safely killed.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;2. Unicast Events&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;This is even easier as the event hub notifies the old listener (via an event) when a new one takes over that it has been replaced and can stop listening for the unicast event. &amp;nbsp;At that point the listener will finish with any current events its dealing with and then shut down.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;So you need only the bring up the newer version of the unicast listener, it will connect to the hub, telling the hub it is the new listener for the given unicast event. &amp;nbsp;All subsequent unicast events will get passed to the new listener and the old listener will receive a event from the hub telling the old listener that its work is done.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;Client-Side&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;The above two scenarios detail how to shutdown old server-side listeners, what about updating clients? &amp;nbsp;Welp that is no different than what we currently do when we roll out new client-side web application code: push the code out the the CDN. &amp;nbsp;Your HTTP server is still around to server the static client-side code. &amp;nbsp;Subsequent browser refreshes will now get served this new code. &amp;nbsp;Same deal.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;What is more interesting is the client-side code is split into many smaller individual files which can be changed independent of all the other files. &amp;nbsp;It's not quite as clean as that because for&amp;nbsp;efficiency&amp;nbsp;the small Javascript files would be mashed into one large one and then minified for performance, regardless the process is the same as for current web applications.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Deploying small changes in client-side code is a&amp;nbsp;&lt;b&gt;very &lt;/b&gt;interesting topic and I hope someday to learn how to do it better...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;The Hub&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;What about the hub itself? &amp;nbsp;The time will come when it needs to be restarted for whatever reason. &amp;nbsp;The best way is to bring up a new hub and bring up another set of listeners that connect to it. &amp;nbsp;Update client-side code to point to the new hub and push it out. &amp;nbsp;Wait. &amp;nbsp;Wait some more. &amp;nbsp;Eventually traffic to your old hub will cease, then you can shut it down and shut down all the listeners connected to it.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;When is safe to shut down the old hub? &amp;nbsp;Where there is no more client traffic! &amp;nbsp;We'll look at that in the 'Logging' post coming up soon!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;I hope you can see deployment of event-based asynchronous application is more complex because there are more pieces but much more fine-grained and much safer overall.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;Stay tuned for Logging, languages, and an implementation!&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-4761916834792269326?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/4761916834792269326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/deploying-event-hub-application.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/4761916834792269326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/4761916834792269326'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/deploying-event-hub-application.html' title='Deploying an Event Hub application'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-1436339133532589130</id><published>2012-02-14T16:38:00.000-08:00</published><updated>2012-02-14T16:38:16.430-08:00</updated><title type='text'>Event Hub</title><content type='html'>&lt;b&gt;Event Hub&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Get caught up:&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 1:&amp;nbsp;&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;"&gt;http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html&lt;/a&gt;&lt;span id="goog_565352830" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;span id="goog_565352831" style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;"&gt;&lt;/a&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;"&gt;Part 2:&lt;/span&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/events.html" style="background-color: white; color: #6699cc; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px; text-decoration: none;"&gt;&amp;nbsp;http://randomgoo.blogspot.com/2012/02/events.html&lt;/a&gt;&lt;br /&gt;Part 3:&amp;nbsp;&lt;a href="http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html"&gt;http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html&lt;/a&gt;&lt;br style="background-color: white;" /&gt;&lt;br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 20px;" /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;The hub (maybe more like a switch) is pretty dumb with some minimal smarts.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;The Dumb&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;The hub listens on a port for connections from interested modules. &amp;nbsp;Once connected the hub relays events to all connected modules (yes even back to the module that fired the event - the handler may be there too!). &amp;nbsp;Nice and dumb.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;The Smart&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Cry not for our poor hub. &amp;nbsp;It also has some basic smarts. &amp;nbsp;The smarts are necessary for 2 separate reasons:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;1. sessions&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;2. trust&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;Sessions&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Each connection to the hub is associated with a session, not an entire session, just a unique identifier. &amp;nbsp;This identifier, hmmm... identifies a session uniquely. &amp;nbsp;Didn't I just say that? &amp;nbsp;Anyway the hub itself does not use the session key, but merely passes it along to 'trusted' modules. &amp;nbsp;'Trusted' modules can use this identifier to store data associated with this session if they so choose.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;The hub injects the session key into any event arguments before passing the event on to any 'trusted' connected modules.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;Trust&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Some connected modules are more special than others. &amp;nbsp;These are typically server-side listeners that do actual work, like updating a database or flipping switches in a nuclear reactor. &amp;nbsp;Not all modules are created equally. &amp;nbsp;We wouldn't want just anyone connecting to our hub and responding to the 'reactor:TurnOn' event now would we? &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;So a module is 'trusted' by the hub if, upon connection, it provides a secret key shared only by trusted modules and the event hub. &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;So what does a 'trusted' module get that a plain old untrusted one doesn't?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;It gets 2 things, the session key and responder status.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;The session key is mentioned above, it's just a unique key that&amp;nbsp;identifies&amp;nbsp;the event emitter.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;'Responder status' means a trusted module gets to listen for certain events, and ONLY that ONE trusted module will be delivered that event.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;FOR INSTANCE the 'user:add' event.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Without a trusted listener for that event the 'user:add' event will be broadcast to all modules. &amp;nbsp;So a 'bad guy' can connect to your event hub and listen for that event and when a good guy tries to create a user (including username and password in the event data) the bad guy will get it.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Even without a bad guy some events only want one listener. &amp;nbsp;What if I had three modules, trusted ones event, listening for the 'user:add' event? &amp;nbsp;They would all get the event, the first one would succeed (say by adding the user to the database) while the other 2 would fail, as the user now already exists. &amp;nbsp;Even worse what about events with callbacks? &amp;nbsp;The first callback would work and the next 2 callbacks would fail as the callback already happened.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;SO events with callbacks can only have ONE listener. &amp;nbsp;Events that change stuff should only have ONE listener. &amp;nbsp;That ONE listener should be 'trusted'.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;SO the event hub must support trusted modules AND the ability to have only ONE listener for an event. &amp;nbsp;And as an extra added bonus IF the module is trusted it gets the session key to boot.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Ok stay with me here just about done! &amp;nbsp;Here's how it all comes together:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Module &amp;lt;-&amp;gt; Event Hub&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="line-height: 19px;"&gt;Initialization&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Clients, typically browsers or command line clients, connect to the event hub with no special&amp;nbsp;privileges. &amp;nbsp;They can emit all the events they want, not knowing or caring about all of this 'trust' or 'session' stuff.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Server-side modules can connect to the event hub with a shared key giving them 'trusted' status. &amp;nbsp;These trusted modules can request to listen for events which they deem 'unicast' using event-listening syntax sugar.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;b&gt;Unicast Event to Trusted Listener&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Ok everyone is connected to the hub now, now the user creates a new user and the client fires the 'user:add' event with the username and password. &amp;nbsp;This&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;unbeknownst&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;-to-the-client is a unicast event that ONLY gets sent to the one trusted server-side module that is listening for it. &amp;nbsp;This handler adds the user to the database and can either fire another event upon successful completion or use a callback to respond with the operation's status.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;Event with Session Key&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Great so we have created a new user, now that user wants to log in. &amp;nbsp;User fills in their username and password and a 'user:login' event is emitted. &amp;nbsp;The trusted unicast listener (doesn't have to be unicast in this case) gets the username &amp;amp; password &amp;amp; session key from the event hub and verifies the credentials against the database. &amp;nbsp;A match! &amp;nbsp;Now the listener would use the unique session key to create a session object in the database with the username of the authenticated user and again uses the callback or emits a 'user:loggedIn' event of its own to report status.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Great, now that user wants to change their password. &amp;nbsp;So the client fires a 'user:changePassword' (or 'user:updateUser' or whatever) event with the username, new password and the event hub adds in the session key before handing re-firing the event to the trusted listener (perhaps unicast). &amp;nbsp;The listener verifies the username in the event matches the username associate with the session key and if they match updates the password. &amp;nbsp;Finally it can either fire an event 'user:passwordUpdated' (or whatever) or use a callback to report back status.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: inherit;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;Doesn't that all just make perfect sense??&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;"&gt;&lt;span style="font-size: 15px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: inherit; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;So our event hub has sessions and trusted modules and unicast, everything else is just dumb event and callback passthru.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;b&gt;SSL&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;An event hub can operate just fine over SSL. &amp;nbsp;You will not get the pretty 'lock' or 'green' URL bar but all of your data can very easily be sent encrypted.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: small;"&gt;&lt;span style="line-height: 19px;"&gt;Coming up next: languages, implementations, and deployment - stay tuned!!&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-1436339133532589130?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/1436339133532589130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/event-hub.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1436339133532589130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1436339133532589130'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/event-hub.html' title='Event Hub'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-5177364301769401783</id><published>2012-02-14T14:50:00.000-08:00</published><updated>2012-02-14T14:51:52.278-08:00</updated><title type='text'>Event Listeners</title><content type='html'>&lt;b&gt;Event Listeners&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Get up to speed first:&lt;br /&gt;Part 1:&amp;nbsp;&lt;a href="http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html"&gt;http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html&lt;/a&gt;&lt;span id="goog_565352830"&gt;&lt;/span&gt;&lt;span id="goog_565352831"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/"&gt;&lt;/a&gt;&lt;br /&gt;Part 2:&lt;a href="http://randomgoo.blogspot.com/2012/02/events.html"&gt; http://randomgoo.blogspot.com/2012/02/events.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px; line-height: 19px;"&gt;Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There is no special syntax or language features required to listen for and respond to events. &amp;nbsp;So listen up!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;hub.on('user:add', function(params, callback) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; var user = params.user&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; , pass = params.pass&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; ;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; // Do something interesting (probably throw more events to&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; // &amp;nbsp; &amp;nbsp; save off to the DB) &amp;amp; when done if no error:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; callback(null, { success: true });&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's really it, attach a function to an event - the first parameter will be an object and the second will be a callback. &amp;nbsp;Both parameters are optional.&lt;br /&gt;&lt;br /&gt;Note these examples use Javascript but THAT OF COURSE IS NOT REQUIRED!&lt;br /&gt;&lt;br /&gt;Not all events require a response! &amp;nbsp;It's all about the documentation and expectation - event listeners MUST supply some sort of documentation to emitters:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;* @method user:add handler&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;* @param user username&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;* @param pass password&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;* @param callback required - response will contain 'success'&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;* &amp;nbsp; &amp;nbsp;true or false&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Something like that - exactly as you would document a method-based API. &amp;nbsp;This handler can just as easily throw a 'user:Added' event instead of a callback:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;hub.fire('user:Added', { success: true, user: params.user });&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Firing an event as a response is&amp;nbsp;&lt;/span&gt;preferable&lt;span style="font-family: inherit;"&gt;&amp;nbsp;if you can get away with it so everyone can know what just happened, especially if it was successful, to give other parts of your application knowledge of what is going on. &amp;nbsp;Sometimes you do not need any response - like logging.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;And sometimes you need a specific response directly back to you, for instance state information.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;That's it for this round - stay tuned for MUCH more!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-5177364301769401783?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/5177364301769401783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/5177364301769401783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/5177364301769401783'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html' title='Event Listeners'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-2794282321563469558</id><published>2012-02-14T13:31:00.000-08:00</published><updated>2012-02-14T13:31:18.419-08:00</updated><title type='text'>Events</title><content type='html'>Before reading this please read part 1:&lt;br /&gt;&lt;a href="http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html"&gt;http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.&lt;br /&gt;&lt;br /&gt;So let's look at the event side of Web 3.0.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Event Syntax&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Events Must have a string name&lt;/li&gt;&lt;li&gt;Events Might have an optional JSON-able set of parameters.&lt;/li&gt;&lt;li&gt;Events Might have an optional callback.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Event Names&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Event names are strings, probably namespaced, separated from the namespace with a colon ':'. &amp;nbsp;It could also be a good idea to put a version number in there too if ya like, this can help keep your code in sync. &amp;nbsp;Up to you, play&amp;nbsp;with it.&lt;br /&gt;&lt;br /&gt;Here are some good event names:&lt;br /&gt;&lt;br /&gt;user:add&lt;br /&gt;user:delete&lt;br /&gt;user:update&lt;br /&gt;user-1.0:add &amp;nbsp; &amp;nbsp;# module versioned&lt;br /&gt;user:add-1.0 &amp;nbsp; &amp;nbsp;# listener versionsed&lt;br /&gt;session:create&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Event Parameters&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Event parameters are serialized as JSON text so no function pointers or other funny business. &amp;nbsp;Toss in there whatever you need. &amp;nbsp;An&amp;nbsp;important key is a session key. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Event Callback&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Providing an optional callback allows event listeners to respond directly, asynchronously, back to the event emitter with data just&amp;nbsp;for it. &amp;nbsp;The callback function should accept two paramters, a possibly null error object (or string) and a (possibly null) object&amp;nbsp;with data for the emitter.&lt;br /&gt;&lt;br /&gt;Check it:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;hub.emit('user:add', { username: 'foobie', password: 'bloobie' },&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; function(error, resp) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (!error) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // sweet&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } else {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // no dice&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Look ma - no dependency on a 'user' object!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Event Semantics&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Events are prayers that we expect to be answered. &amp;nbsp;It's possible they don't get answered. &amp;nbsp;What happens when events do not get&amp;nbsp;answered? &amp;nbsp;Life goes on.&lt;br /&gt;&lt;br /&gt;We'll look at event listeners next time...&lt;br /&gt;(and still to come: the event hub itself, programming languages, and an implementation and experimentation)&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-2794282321563469558?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/2794282321563469558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/events.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/2794282321563469558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/2794282321563469558'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/events.html' title='Events'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-4114586390227153933</id><published>2012-02-14T08:42:00.000-08:00</published><updated>2012-02-14T08:42:19.010-08:00</updated><title type='text'>Release The Event Hub:  Web 3.0 - An Introduction</title><content type='html'>There are 2 factors of utmost import when coding: size and isolation. &amp;nbsp;While they both impact each other they are not the same.&lt;br /&gt;&lt;br /&gt;Small code has fewer bugs. &amp;nbsp;Isolatable code has fewer dependencies and is easier to maintain. &amp;nbsp;So maintable code with few bugs, sign me up for that!&lt;br /&gt;&lt;br /&gt;Small code is hard to write because code tends to get bound up in all the other code around it, despite our best efforts.&lt;br /&gt;&lt;br /&gt;Especially over time feature creep and bug fixes tend to litter our once small code. &amp;nbsp;Plus it's just darn simpler at that moment to&amp;nbsp;add code to already existing code instead of starting fresh. &amp;nbsp;So code grows and grows and without serious discipline that we all lack&amp;nbsp;it never shrinks.&lt;br /&gt;&lt;br /&gt;Isolatable code is hard to write because making everything an isolated unit is a giant pain in the ass. &amp;nbsp;There just is not any&amp;nbsp;incentive day-to-day to write truly isolatable code. &amp;nbsp;If you do it still needs to be integrated into your application, why you are writing this&amp;nbsp;code in the first place, and no one wants to keep doing that over and over again. &amp;nbsp;Besides have you ever seen an isolatable piece of&lt;br /&gt;code? &amp;nbsp;Typically only the must mundane and obvious code is written as isolatable (or you're using 3rd party/open source code) -&amp;nbsp;like obvious AOP stuff like logging and authentication. &amp;nbsp;Even then authentication is rarely isolatable from the HTTP server. &amp;nbsp;Same&amp;nbsp;with session management. &amp;nbsp;Add authorization and message routing to all of that too. &amp;nbsp;Finally pulling 'business logic' away from the&lt;br /&gt;HTTP server is difficult too.&lt;br /&gt;&lt;br /&gt;Dependency management has almost single-handedly destroyed code quality since our ancesctors first hacked code on clay tablets back&amp;nbsp;in the 1960s. &amp;nbsp;Creating, storing, calling, and destroying foreign objects has led to some of the most unmaintainable, tightly coupled,&amp;nbsp;fan-out-crazy, untestable, downright ugly code imaginable.&lt;br /&gt;&lt;br /&gt;With one stroke we can get rid of dependency hell, tightly coupled code, and useless blocking - while enhancing scalability,&amp;nbsp;testability, maintainability, and code isolation.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Release The Event Hub!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Imgaine an army of independent handlers, each handler doing only one thing, communicating via only events and callbacks. &amp;nbsp;No&amp;nbsp;external dependencies and no HTTP server requirement. &amp;nbsp;I'm talking about truly independent hunks of code 'Sofware as a Service'&amp;nbsp;connected by an event hub.&lt;br /&gt;&lt;br /&gt;Gone are the same-origin policy, HTTP servers routing messages, and tightly coupled code.&lt;br /&gt;&lt;br /&gt;So how does it work? &amp;nbsp;Every independent module of code connects to a central event hub. &amp;nbsp;This hub can live on a separate host from&amp;nbsp;your HTTP server and is actually a relatively simple piece of code. &amp;nbsp;It accepts connections from modules and passes emitted events to all&amp;nbsp;connected listeners. &amp;nbsp;It also proxies callbacks back to the event emitter, is there is one (a callback, that is).&lt;br /&gt;&lt;br /&gt;Event emitters connect to the hub and emit events and either:&lt;br /&gt;&lt;br /&gt;1. are done&lt;br /&gt;2. are listening for another event in response to theirs (or not)&lt;br /&gt;3. wait for a callback from the listener&lt;br /&gt;&lt;br /&gt;Event listeners connect to the hub and wait to service fired events. &amp;nbsp;In response they:&lt;br /&gt;&lt;br /&gt;1. do nothing&lt;br /&gt;2. fire another event&lt;br /&gt;3. execute the provided callback&lt;br /&gt;&lt;br /&gt;Of course a hunk of code can be both an event emitter and a listener.&lt;br /&gt;&lt;br /&gt;OK that's enough for the first post - next up we'll look at how this actually all works (including sessions and security). &amp;nbsp;We will all miss multi-threading and method calls&amp;nbsp;greatly: RIP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-4114586390227153933?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/4114586390227153933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/4114586390227153933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/4114586390227153933'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html' title='Release The Event Hub:  Web 3.0 - An Introduction'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-5240713085962614062</id><published>2011-08-10T01:19:00.000-07:00</published><updated>2011-08-10T12:33:43.450-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ret'/><title type='text'>Javascript Unit Testing Environment</title><content type='html'>&lt;b&gt;Ready to kick your Javascript Unit Testing up to the next level? &amp;nbsp;Or even to the very first level? &amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Javascript Unit Testing suffers from lack of standardization. &amp;nbsp;There is no universal 'JUnit' or 'PHPUnit' to 'rule them all'. &amp;nbsp;There are lots of very good Javascript testing frameworks available, especially &lt;a href="http://developer.yahoo.com/yui/3/test/"&gt;YUI3's test framework&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;YUI3's framework provides the foundation for writing unit tests, collecting them into test cases and suites, and even mocking objects. &amp;nbsp;And that's great. &amp;nbsp;But we can do more, and do it easier!&lt;br /&gt;&lt;br /&gt;The &lt;a href="https://github.com/zzo/JUTE"&gt;Javascript Unit Test Environment (JUTE)&lt;/a&gt; combines the YUI3 testing framework, automatic dynamic code coverage, a web UI, a command line interface, seamless client- and server-side Javascript testing and 3 testing back ends (Capture, Selenium, and V8) in one easy to setup and use package. &amp;nbsp;This is all provided with very little setup by you - just like we all like it!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Anatomy of a client-side Javascript Unit Test&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;First let's look at what a simple client-side Javascript Unit Test looks like. &amp;nbsp;Here's some simple code we want to test (not JUTE does NOT require that code you want to test be written using YUI3!).&lt;br /&gt;&lt;br /&gt;In 'mySum.js':&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;function mySum() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; var result = 0, i = 0;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; if (typeof arguments[0] == 'object' &amp;amp;&amp;amp; arguments[0].length) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (;i &amp;lt; arguments[0].length; i++) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += arguments[0][i];&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; } else {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (;i &amp;nbsp;&amp;lt; arguments.length; i++) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += arguments[i];&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; return result;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A slightly bizarre 'sum' function - does it work? &amp;nbsp;Let's write a test for it using JUTE! &amp;nbsp;JUTE builds on top of the YUI3 test module, so we need to use that to write our tests. &amp;nbsp;Again, the code you are testing does NOT need to use or have anything to do with YUI3 (although it can!) - only the TESTING code needs to utilize the YUI3 test stuff - which is good test stuff to use regardless!&lt;br /&gt;&lt;br /&gt;In 'testMySum.js':&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;YUI({ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; logInclude: { TestRunner: true },&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; gallery: &amp;nbsp; &amp;nbsp;'gallery-2011.06.22-20-13'&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}).use('gallery-jute', function(Y) {&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; var suite = new Y.Test.Suite('mySum');&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; suite.add(new Y.Test.Case({&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; name:'simple sums',&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; testTwoNumbers: function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Y.Assert.areEqual(mySum(5, 5), 10);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; },&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; testArray: function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Y.Assert.areEqual(mySum([5, 5]), 10);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }));&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;Y.Test.Runner.add(suite);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; Y.UnitTest.go();&lt;/code&gt;&lt;br /&gt;&lt;code&gt;});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So those are two reasonable tests for our 'mySum' function. &amp;nbsp;Now we need an HTML file to pull it all together.&lt;br /&gt;&lt;br /&gt;In 'testMySum.html':&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;html lang="en"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;head&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/head&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;body class="yui3-skin-sam"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div id="log" /&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;script src="mySum.js?coverage=1"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;script src="testMySum.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/body&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;/html&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;OK so we've got all we need for a basic client-side Javascript Unit Test. &amp;nbsp;We have what we want to test (mySum.js), our test code (testMySum.js) and finally an HTML file to pull it all together (testMySum.html). &amp;nbsp;We could be done here, run the tests, hope it all passes and move on.&lt;br /&gt;&lt;br /&gt;The only things different here than a vanilla unit test are the inclusion of the 'gallery-jute' module (which also pulls in YUI3's 'test' module for you) in testMySum.js AND node the '?do_coverage=1' query string I snuck in testMySum.html on the mySum.js file! &amp;nbsp;This will transparently tell JUTE that IF you want to run these tests with code coverage THIS is the file we want code coverage for - which, surprise surprise, is the file we're testing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Anatomy of a server-side Javascript Unit Test&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Our 'mySum' function can clearly just as easily be run on the server side using NodeJS. &amp;nbsp;What would a unit test for server-side Javascript look like?&lt;br /&gt;&lt;br /&gt;First off our mySum.js file will change slightly because we want to utilize the NodeJS 'require' feature.&lt;br /&gt;&lt;br /&gt;myServerSum.js:&lt;br /&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;module.exports = {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; mySum: function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; var result = 0, i = 0;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; if (typeof arguments[0] == 'object' &amp;amp;&amp;amp; arguments[0].length) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (;i &amp;lt; arguments[0].length; i++) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += arguments[0][i];&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; } else {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (;i &amp;nbsp;&amp;lt; arguments.length; i++) {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += arguments[i];&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; return result;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;br /&gt;&lt;code&gt;};&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here we just wrapped our 'mySum' function into a module.exports declaration. &amp;nbsp;Now our tests will change slightly to use 'require' instead of relying on an HTML file to link everything together.&lt;br /&gt;&lt;br /&gt;In 'testServerMySum.js:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;YUI({ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; logInclude: { TestRunner: true },&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;/code&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="display: inline !important;"&gt;&lt;/div&gt;&lt;div style="display: inline !important;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;code&gt;}).use('jute', function(Y) {&lt;/code&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; var suite = new Y.Test.Suite('mySum'),&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mySum = require('myServerSum', true).mySum;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; suite.add(new Y.Test.Case({&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; name:'simple sums',&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; testTwoNumbers: function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Y.Assert.areEqual(mySum(5, 5), 10);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; },&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; testArray: function() {&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Y.Assert.areEqual(mySum([5, 5]), 10);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }));&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;Y.Test.Runner.add(suite);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; Y.UnitTest.go();&lt;/code&gt;&lt;br /&gt;&lt;code&gt;});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No not a lot of (visible!) magic here - we just 'require' the myServerSum javascript &amp;amp; pull out the 'mySum' function. &amp;nbsp;Besides there being NO HTML file I've snuck something else in - note:&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="display: inline !important;"&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mySum = require('myServerSum', true).mySum;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;In 'testServerMySum.js'! &amp;nbsp;Similarly to '?do_coverage=1' in the client-side example, this tells JUTE that IF we run unit tests wanting code coverage THIS is the file to apply code coverage to. &amp;nbsp;And, surprise surprise, this is the file we are testing.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ready To Rumble&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;At this point JUTE now gives you the flexibility to run your tests via a web UI or a command-line interface. &amp;nbsp;JUTE will persist not only your unit test output in JUnit XML format, but will also automatically generate pretty HTML for code coverage AND give you the option of running these tests in either Captured browsers, on a Selenium RC or Grid host, or directly thru V8. &amp;nbsp;Of course the NodeJS version of mySum can ONLY be run thru the V8 backend. &amp;nbsp;However in this case the client-side version CAN be run thru any of the 3 backends.&lt;br /&gt;&lt;br /&gt;So you've actually done all the hard parts already: &amp;nbsp;for client-side Javascript testing you have the file you want to test, the file with your tests in it, and an HTML file tying them all together. &amp;nbsp;For server-side Javascript you've got the file you want to test and file containing all of your test code.&lt;br /&gt;&lt;br /&gt;Now lets sit back and run it all thru JUTE and start living the good life!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Installing JUTE&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;First you need to install the thing - JUTE requires only the current versions of &lt;a href="http://nodejs.org/"&gt;NodeJS&lt;/a&gt;&amp;nbsp;(0.4.10)&amp;nbsp;and &lt;a href="http://npmjs.org/"&gt;npm&lt;/a&gt;&amp;nbsp;(1.x). &amp;nbsp;Simply:&lt;br /&gt;&lt;blockquote&gt;% npm install jute -g&lt;/blockquote&gt;Starting, stopping, and restarting JUTE is equally easy:&lt;br /&gt;&lt;blockquote&gt;&amp;nbsp; &amp;nbsp; % npm start jute&lt;br /&gt;&amp;nbsp; &amp;nbsp; % npm stop jute&lt;br /&gt;&amp;nbsp; &amp;nbsp; % npm restart jute&lt;/blockquote&gt;&lt;b&gt;Basic Configuration&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;JUTE is a standalone webserver so before you start it you need to tell it where your document root is, where your test files are, and where it should put its output. &amp;nbsp;You can also give JUTE another port to run on and some other configuration. &amp;nbsp;Regardless all configuration is accessible via npm config variables:&lt;br /&gt;&lt;blockquote&gt;% npm config set jute:docRoot /var/htmlroot&lt;br /&gt;% npm config set jute:testDir test&lt;br /&gt;% npm config set jute:outputDir output&lt;br /&gt;% npm config set jute:port 8080&lt;/blockquote&gt;SO JUTE will look for all of your *.html 'glue' test file in docRoot + testDir (/var/htmlroot/test) in this example and output test results and code coverage information into docRoot + outputDir (/var/htmlroot/output) in this case. &amp;nbsp;AND JUTE will listen on port 8080.&lt;br /&gt;&lt;br /&gt;If you make ANY changes to JUTE variables you MUST restart JUTE for your changes to take effect:&lt;br /&gt;&lt;blockquote&gt;% npm restart jute&lt;/blockquote&gt;Now that JUTE is configured you are ready to run some tests the JUTE way!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Backends&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Before we run our tests let's quickly divert and discuss the testing 'backends' available with JUTE.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Capture&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Capture mode runs tests on all 'captured' browsers. &amp;nbsp;A 'captured' browser is simply one that is currently pointing to&amp;nbsp;http://&amp;lt;JUTE_SERVER&amp;gt;:&amp;lt;JUTE_PORT&amp;gt;/ &amp;nbsp;All such browsers (desktop, mobile, whatever) are 'captured' by JUTE and any submitted 'capture' unit tests will run on ALL currently captured browsers in parallel.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Selenium&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;JUTE plays nicely with Selenium RC and Grid. &amp;nbsp;The Selenium back end will ship all requested tests to a Selenium RC or Selenium Grid instance. &amp;nbsp;Just specify the Selenium browser specification (e.g. '*firefox') and off your tests go.&lt;br /&gt;The Selenium back end is only available via JUTE's command-line interface.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;V8&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Some client-side Javascript and of course and all server-side Javascript will run through the V8 back end. &amp;nbsp;The V8 back end is only available via JUTE's command-line interface.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Running Your Tests&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Hey we are just about ready to run our awesome unit tests the JUTE way! &amp;nbsp;You have two choices to kick off your unit tests, via the WebUI or the command-line interface. &amp;nbsp;Note ONLY Capture tests can be run via the web UI - Selenium and V8 back ends are only accessible via JUTE's command-line interface. &amp;nbsp;See below for details!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;WebUI&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;JUTE comes with a snazzy webui available here:&lt;br /&gt;&lt;blockquote&gt;http://&amp;lt;JUTE_SERVER&amp;gt;:&amp;lt;JUTE_PORT&amp;gt;/&lt;/blockquote&gt;This will bring up a lot of information - the most useful being the list of unit tests available to be run assuming you set up docRoot and testDir correctly! &lt;br /&gt;From the WebUI you are able to run any/all tests in Capture mode. &amp;nbsp;You can also see output from ALL modes in the 'results' pane on the right.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Command-Line Interface&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;This is where things get especially interesting. &amp;nbsp;From the command-line interface you can run tests in any of the 3 back ends with code coverage or not. &amp;nbsp;Let's look at some examples! &amp;nbsp;NOTE!!!!!! &amp;nbsp;All testfiles are specified RELATIVE to &amp;lt;docRoot&amp;gt;/&amp;lt;testDir&amp;gt;!!&lt;br /&gt;&lt;blockquote&gt;% jute_submit_test --test myTestSum.html&lt;/blockquote&gt;This is as simple as it gets - submits that 1 HTML file to be unit tested in capture mode.&lt;br /&gt;&lt;blockquote&gt;% jute_submit_test --test myTestSum.html --v8&lt;/blockquote&gt;Same thing BUT use the V8 backend.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;% jute_submit_test --test myTestSum.html --sel_host our.selenium.rc.com -sel_browser '*firefox'&lt;/blockquote&gt;How about multiple tests?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;% jute_submit_test --test myTestSum.html --test myOtherTest.html&lt;/blockquote&gt;Again added the '--v8' or '--sel_host' flags for those back ends.&lt;br /&gt;&lt;br /&gt;How about code coverage?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;% jute_submit_test --test myTestSum.html?do_coverage=1 --v8&lt;/blockquote&gt;Simply stick the '?do_coverage=1' querystring at the end any test to enable code coverage.&lt;br /&gt;&lt;br /&gt;Now JUTE will go off and run you test(s) using the specified back end and will dump output into &amp;lt;docRoot&amp;gt;/&amp;lt;outputDir&amp;gt;. &amp;nbsp;JUTE will also generate pretty HTML for code coverage if requested - all available for viewing via the webui - EVEN Selenium and V8 tests!&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;b&gt;More Information&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;I hope you've seen writing Javascript unit tests CAN be fun AND profitable! &amp;nbsp;More examples are available at the &lt;a href="https://github.com/zzo/JUTE"&gt;JUTE homepage&lt;/a&gt;&amp;nbsp;- so check it out!&lt;/div&gt;&lt;div&gt;Don't let your client- or server-side Javascript get out of control! &amp;nbsp;JUTE makes it easy and seamless to get started or kick up to the next level your Javascript Unit Testing today!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;% npm install jute -g&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;FTW!&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-5240713085962614062?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/5240713085962614062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2011/08/javascript-unit-testing-environment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/5240713085962614062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/5240713085962614062'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2011/08/javascript-unit-testing-environment.html' title='Javascript Unit Testing Environment'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>0</thr:total><georss:featurename>Carlsbad, CA 92009, USA</georss:featurename><georss:point>33.0982117 -117.23821629999998</georss:point><georss:box>33.0620537 -117.27233629999998 33.1343697 -117.20409629999997</georss:box></entry><entry><id>tag:blogger.com,1999:blog-8153350445724118154.post-1320435006518029977</id><published>2011-07-11T21:31:00.000-07:00</published><updated>2011-07-11T21:48:20.337-07:00</updated><title type='text'>Adding Facebook Chat To Your NodeJS Site</title><content type='html'>&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Had a fun time adding Facebook chat to a NodeJS-backed site - actual real Facebook chat. &amp;nbsp;That means people on your very own website can chat with their Facebook friends while on your site.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Our good friends at Facebook were kind enough to provide API hooks for authenticating into Facebook Chat using OAuth - SO your Facebook users just need to authorize your app and they can chat thru Facebook on your site. &amp;nbsp;Unfortunately no word yet about opening up Video Chat - hopefully that'll come soon.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;The basic idea is this:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;FIRST Users approve your app/website with chat permissions with Facebook - your user just needs to do this once. &amp;nbsp;Then in a loop:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;User visits your webpage&lt;/li&gt;&lt;li&gt;Your page includes a Javascript XMPP client which can handle Facebook OAuth authentication (and the XMPP protocol in general)&lt;/li&gt;&lt;li&gt;When your user is ready to chat fire up the XMPP client - which is configured to talk to back to your app which will proxy that request to your locally running BOSH server which then proxies the requests off to Facebook&lt;/li&gt;&lt;li&gt;Profit!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h1&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: large;"&gt;&lt;span class="Apple-style-span" style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;&lt;h1&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: large;"&gt;&lt;span class="Apple-style-span" style="line-height: 19px;"&gt;What He Say?&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: large;"&gt;&lt;span class="Apple-style-span" style="line-height: 19px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;h1&gt;&lt;span class="Apple-style-span" style="font-family: Times; font-weight: normal; line-height: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;If yer new to this stuff as I was here are some basic terms:&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Times; font-weight: normal; line-height: normal;"&gt;&lt;a href="http://xmpp.org/"&gt;XMPP&lt;/a&gt; - a chat protocol that is the standardized version of the 'Jabber' protocol. &amp;nbsp;XMPP is your friend.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Times; font-weight: normal; line-height: normal;"&gt;BOSH -&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, 'bitstream vera sans', clean, sans-serif; line-height: 16px;"&gt;&amp;nbsp;&lt;a href="http://xmpp.org/extensions/xep-0124.html"&gt;Bidirectional-streams Over&amp;nbsp;&lt;wbr&gt;&lt;/wbr&gt;Synchronous HTTP (&lt;b&gt;BOSH&lt;/b&gt;)&lt;/a&gt;&amp;nbsp;Good god don't actually read that - it's yer standard 'how the monkey do we do bi-directional async message passing over HTTP?' - the gory details do not concern us - it works. &amp;nbsp;Like &lt;a href="http://socket.io/"&gt;socket.io&lt;/a&gt; for web-based XMPP clients.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, 'bitstream vera sans', clean, sans-serif; line-height: 16px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, 'bitstream vera sans', clean, sans-serif; line-height: 16px;"&gt;It is expected your know your way around authenticating your webapp (or desktop app) via Facebook. &amp;nbsp;&lt;a href="http://developers.facebook.com/docs/"&gt;Here is where to get started.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;User Allows your website to host FB Chat&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-size: 13px; font-weight: normal;" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-size: 13px; font-weight: normal;" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;This is your standard FB authentication as documented&amp;nbsp;&lt;a data-mce-href="http://developers.facebook.com/docs/authentication/" href="http://developers.facebook.com/docs/authentication/" title="Facebook Auth"&gt;here&lt;/a&gt;&amp;nbsp;- just make sure to request the 'xmpp_login' permission. &amp;nbsp;I would also recommend getting the 'offline_access' permission while yer at it.&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" data-mce-style="font-size: 13px; font-weight: normal;" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Install a BOSH server&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;I'm going to use '&lt;a href="http://code.google.com/p/node-xmpp-bosh/"&gt;node-xmpp-bosh&lt;/a&gt;' in keeping with the NodeJS theme BUT any old BOSH server will do (&lt;a href="http://blog.jwchat.org/jhb/"&gt;here's one written in Java&lt;/a&gt;&amp;nbsp;if that's how you roll). &amp;nbsp;This guy will route XMPP messages between your Javascript XMPP client back and forth to Facebook (or any other XMPP server). &amp;nbsp;This thing can be treated just as a service that needs to be started once &amp;amp; forgotten.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-size: 13px; font-weight: normal;" style="font-size: 13px; font-weight: normal;"&gt;% npm install&amp;nbsp;node-xmpp-bosh&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif; font-size: small;"&gt;You do NOT need to edit its configuration file in&amp;nbsp;/etc/bosh.conf.js - in fact you probably should not change anything in there  Frankly to us this thing is just a black box. &amp;nbsp;Here are the most important configuration bits:&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif; font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;port: 5280,&lt;br /&gt;  host: '0.0.0.0',&lt;br /&gt;  path: /^\/http-bind\/$/&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;So it's going to listen on localhost on port 5280 and expects requests of the form /http-bind/* - basically nothing you need to worry about.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;You can then either run it in 'standalone' mode - you can start it when your webserver boots just like any other service or start it from the comand line or from within your NodeJS code.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Note is does NOT need to run as root - it's basically a webserver that listens on port 5280 and that's about it.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;For grins here's how to start it from within your NodeJS code:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;var nxb     = require('node-xmpp-bosh'),&lt;br /&gt;    bosh_server = nxb.start({&lt;br /&gt;        port: 5280,&lt;br /&gt;        no_tls_domains: [ 'chat.facebook.com' ]&lt;br /&gt;    });&lt;/pre&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: small; font-weight: normal;"&gt;Note Facebook's chat servers do NOT support TLS - so if you are running any other BOSH server ensure where ever the config option is to turn TLS off it's turned off for 'chat.facebook.com' .&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Client-side XMPP Library&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;We need a JS library that supports &lt;a href="http://developers.facebook.com/docs/chat/"&gt;Facebook's OAuth XMPP authentication&lt;/a&gt; -&amp;nbsp;&lt;a data-mce-href="http://blog.jwchat.org/jsjac/" href="http://blog.jwchat.org/jsjac/" title="JSJaC"&gt;Hey! Here's one Now!&lt;/a&gt;&amp;nbsp; JSJaC - besides having an insane name, has Facebook OAuth Authentication baked right in! &amp;nbsp;It also has a Facebook Authentication example in its&amp;nbsp;&lt;a data-mce-href="https://github.com/sstrigler/JSJaC/blob/master/examples/facebookclient.html" href="https://github.com/sstrigler/JSJaC/blob/master/examples/facebookclient.html" title="JSJaC FB Example"&gt;Facebook example&lt;/a&gt;.&lt;/div&gt;&lt;h2 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;&lt;h2 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;JSJaC Configuration&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;First you need to include the JSJaC Javascript on your page - remember the same origin policy - have your NodeJS webapp serve this file and we'll deal with proxying its messages below:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-size: 13px; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;script type="text/javascript" src="js/JSJaC.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Or wherever you wanna put it. &amp;nbsp;When you're ready to open up a chat connection to Facebook first we create a connection object telling JSJaC where to talk to:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;//Setting the XMPP connection configurations&lt;br /&gt;    var oArgs = {&lt;br /&gt;        //Set the http-binding address (typically /http-bind/ but changing it for grins&lt;br /&gt;        httpbase: '/fbchat',&lt;br /&gt;        //Set the Timerval&lt;br /&gt;        timerval: 2000&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    //Creation of the XMPP connection object&lt;br /&gt;    var con = new JSJaCHttpBindingConnection(oArgs);&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Once we're got a connection object we can attach event listeners for all interesting XMPP events - like new messages and people coming and going. &amp;nbsp;See the &lt;a href="http://blog.jwchat.org/jsjac-1.3.4/doc/"&gt;JSJaC documentation&lt;/a&gt; for more details.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;SO we've created our XMPP connection object - attached event handles for interesting events - now we can connect to Facebook's XMPP server:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;/* Setting the connection authType and the Facebook app configuration&lt;br /&gt; * that will be used to allow the user login inside the appication&lt;br /&gt; * and start to chat with his friends */&lt;br /&gt;var conArgs = {&lt;br /&gt;  //Setting the authorization type to "x-facebook-platform" - VERY IMPORTANT!!!!&lt;br /&gt;  authtype: 'x-facebook-platform',&lt;br /&gt;  //Setting the Facebook Application configuration&lt;br /&gt;  facebookApp: FB_APP_OBJECT&lt;br /&gt;};&lt;br /&gt;//Let's connect to Facebook server&lt;br /&gt;con.connect(conArgs);&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;First do NOT forget to set the 'authtype' key correctly!! &amp;nbsp;If you don't JSJaC will try to use standard XMPP authentication protocols and die an ugly death.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Second - what the heck is&amp;nbsp;&lt;span class="Apple-style-span" data-mce-style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;" style="font-family: Consolas, Monaco, monospace; line-height: 18px; white-space: pre;"&gt;FB_APP_OBJECT???&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;" style="font-family: Consolas, Monaco, monospace; line-height: 18px; white-space: pre;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Ok JSJaC (or ANY FB-compliant XMPP client) needs 3 things to authenticate to Facebook's XMPP server using OAuth:&lt;/div&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Yer Facebook API key&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Yer Facebook Application's Secret key&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;The Facebook Session key&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;These are supplied to JSJaC by an object having 3 corresponding functions which return those values:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;getApiKey()&lt;/li&gt;&lt;li&gt;getApiSecret()&lt;/li&gt;&lt;li&gt;getSession()&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;So those first 2 values are standard values you can get from your Facebook Application's page.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;The Session key is given by Facebook when your user logs into Facebook (&amp;amp; has granted your app the 'xmpp_login' permission. &amp;nbsp;Now I myself also request the 'offline_access' permission from Facebook so you only have to get this value once &amp;amp; then save it off somewhere for just this very moment. &amp;nbsp;I'm a&amp;nbsp;&lt;a data-mce-href="http://redis.io" href="http://redis.io/" title="Redis"&gt;Redis&lt;/a&gt;&amp;nbsp;man myself.)&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Your Facebook API key can be hard-coded into your Javascript safely HOWEVER your Application Secret parameter is supposed to be a SECRET so I would not recommend hard-coding that value into your Javascript.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;So you should max an Ajax call (ideally over SSL) to get your Application secret and you can grab the user's Session key while you're at it.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;ANYWAYS back to&amp;nbsp;&amp;nbsp;FB_APP_OBJECT. &amp;nbsp;FB_APP_OBJECT provides those 3 function mentioned above that provide those values.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Here's the easiest one possible (note all values are totally made up and will not work 'for reals'):&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;FB_APP_OBJECT = {&lt;br /&gt;&amp;nbsp; &amp;nbsp; getApiKey: function( ) { return 'j43983489fj3f498'; },&lt;br /&gt;&amp;nbsp; &amp;nbsp; getApiSecret: function() { return 'e09ef09kef09wefkefw'; },&lt;br /&gt;&amp;nbsp; &amp;nbsp; getSession(): function() { return '38328923dj239d8j2938dj'; }&lt;br /&gt;};&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Your FB_APP_OBJECT hopefully will be smarter than that!!! &amp;nbsp;So the client side is all done - now we need the server to deal with this...&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-weight: bold; line-height: 19px; white-space: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;NodeJS Proxy to BOSH Server&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-weight: bold; line-height: 19px; white-space: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-weight: bold; line-height: 19px; white-space: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 20px; font-weight: bold; line-height: 19px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Our JS XMPP client (JSJaC) can only talk to the server/port that served it - ye olde same origin policy. &amp;nbsp;However our NodeJS server in this case is serving this file SO we need to proxy JSJaC's HTTP requests over to our local XMPP BOSH server running on port 5280. &amp;nbsp;Of course you can proxy these requests to a BOSH server running anywhere - ours happens to be running locally.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Here's what our Connect-based NodeJS proxy code looks like:&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;span class="Apple-style-span" data-mce-style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;"&gt;     if (url.pathname == '/fbchat') {&lt;/span&gt;&lt;/div&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;// proxy these connections to localhost:5280&lt;br /&gt;            req.on('data', function(chunk) {&lt;br /&gt;                var options = {&lt;br /&gt;                    host: 'localhost',&lt;br /&gt;                    port: 5280,&lt;br /&gt;                    path: '/http-bind/',&lt;br /&gt;                    method: 'POST'&lt;br /&gt;                },&lt;br /&gt;                fb_req = http.request(options, function(fb_res) {&lt;br /&gt;                    fb_res.on('data', function(fb_data) {&lt;br /&gt;                        //console.log('xmpp response: ' + fb_data.toString());&lt;br /&gt;                        res.end(fb_data.toString());&lt;br /&gt;                    });&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                //console.log('xmpp request: ' + chunk.toString());&lt;br /&gt;                fb_req.end(chunk.toString());&lt;br /&gt;            });&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;}&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;pre style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; font: normal normal normal 12px/18px Consolas, Monaco, monospace; line-height: 19px;"&gt;&lt;/pre&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;So some interesting things here - the XMPP BOSH requests are all POSTs - so we only listen for those. &amp;nbsp;Also we've configured JSJaC to POST back to us a '/fbchat' - could be anything - like '/http-bind' is typical. &amp;nbsp;So as soon as we get POST data from JSJaC we send it to our BOSH server on port 5280 at '/http-bind/' and any data we get back from the BOSH server we pass back to JSJaC.&lt;/div&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h1&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Fire It All Up&lt;/span&gt;&lt;/h1&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;SO fire up our NodeJS server - that will start our BOSH server listening on port 5280. &amp;nbsp;It will serve the JSJaC.js seed file. &amp;nbsp;It should also give JSJaC our Facebook Application secret and the user session for when our user is ready to chat via some Ajax happiness. &amp;nbsp;Obviously anyone can still see these values so SSL for them would be nice any another smart way to get our value out to JSJaC.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;User visits our site, gives us permissions to use Facebook chat, which also gives us our Session key that JSJaC needs. &amp;nbsp;Our NodeJS app proxyies JSJaC BOSH POSTs over to our BOSH server and proxies any replies back. &amp;nbsp;Now can then connect to Facebook's chat server and respond to events and send messages all via JSJaC's APIs. &amp;nbsp;And life is good!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h1 style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Wrapping Up&lt;/span&gt;&lt;/h1&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Now you can write a sweet chat UI (or not!) for your site and users can chat with all their Facebook friends without ever having to leave your wonderful site!!&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Since JSJaC is an all-purpose XMPP client your users can also connect to any other XMPP server/chat.&lt;/div&gt;&lt;div style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;"&gt;Have fun and I hope you enjoyed my VERY FIRST BLOG POST!!! FTW!!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8153350445724118154-1320435006518029977?l=randomgoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://randomgoo.blogspot.com/feeds/1320435006518029977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://randomgoo.blogspot.com/2011/07/adding-facebook-chat-to-your-nodejs.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1320435006518029977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8153350445724118154/posts/default/1320435006518029977'/><link rel='alternate' type='text/html' href='http://randomgoo.blogspot.com/2011/07/adding-facebook-chat-to-your-nodejs.html' title='Adding Facebook Chat To Your NodeJS Site'/><author><name>zzo</name><uri>http://www.blogger.com/profile/16847792526106692652</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/-Z-WmoxASwcA/ThvO6y7gAnI/AAAAAAAAABk/zHdzsaSKT6M/s220/IMG_0266.jpg'/></author><thr:total>3</thr:total></entry></feed>
