|
| 1 | +# 2012 CodeMash HTML5 Precompiler |
| 2 | +Contributors: Brandon Satrom, Clark Sell |
| 3 | + |
| 4 | +Tags: HTML5, JavaScript, WebSockets |
| 5 | + |
| 6 | +- - - |
| 7 | +## Abstract |
| 8 | + |
| 9 | +In this lab we're going to work through building a realtime chat system leveraging WebSockets. |
| 10 | + |
| 11 | +- - - |
| 12 | +## What will you learn? |
| 13 | + |
| 14 | +In this lab you will learn the basics for creating and consuming a WebSocket. |
| 15 | + |
| 16 | +* How to open a connection |
| 17 | +* How to host an endpoint |
| 18 | +* How to broadcast a message across multiple clients |
| 19 | +* How to send a message |
| 20 | + |
| 21 | +**note** Given the state of the WebSocket Spec and each browser implementation of the spec we're going to developer against an open source library called Socket.IO. The Socket.IO API is very close to the current web socket spec. |
| 22 | + |
| 23 | +- - - |
| 24 | +## Prerequisites |
| 25 | + |
| 26 | +In this purposes of this lab we're going to use node.js for the server side of our WebSocket endpoints. |
| 27 | + |
| 28 | +If you need to install node.js, visit http://nodejs.org/#download. |
| 29 | + |
| 30 | +- - - |
| 31 | +## Dependencies |
| 32 | + |
| 33 | +Once node.js is installed, there are a number of modules we need to install to run. |
| 34 | + |
| 35 | +* socket.io |
| 36 | +* socket.io-client |
| 37 | +* node-static |
| 38 | +* coffee-script |
| 39 | +* jasmine-node |
| 40 | + |
| 41 | +To keep the source base as small as possible these libraries we're not added to source control. At the root you will find `./package.json`, this is our NPM ( node.js package manager ) dependency file. To install run the following command, assuming your root is at the root. |
| 42 | + |
| 43 | + npm install ./ |
| 44 | + |
| 45 | +- - - |
| 46 | +## The Lab |
| 47 | + |
| 48 | +There are two files, we will spend all of our time in: |
| 49 | + |
| 50 | + ./server.js ( or if you prefer CoffeeScript server.coffee ) |
| 51 | + ./view/default.html |
| 52 | + |
| 53 | +`./server.js` is our **server** side of our WebSockets. `Server.js` is what we will run in node.js. `./view/default.html` is our **client side** of things. For purposes of this demo we will also host our view in node.js. |
| 54 | + |
| 55 | +We're going to build a very simple chat application. |
| 56 | + |
| 57 | +- - - |
| 58 | +### Before we get started |
| 59 | + |
| 60 | +In order to save time on the lab and focus on the core of WebSockets, the majority of the "setup" code has been done. By setup we're referring to creating an http server, assigning ports and starting listeners. Feel free to look things over and see how they are setup. |
| 61 | + |
| 62 | +- - - |
| 63 | +### Step #1, Setting up the server connection |
| 64 | + |
| 65 | +With the server setup the first event that we need to wire up is the `connection`. `connection` is the first thing that gets fired when a client tries to make a connection. |
| 66 | + |
| 67 | +Let's add our first event handler for the connection event. |
| 68 | + |
| 69 | + io.sockets.on('connection', function(socket) { |
| 70 | + |
| 71 | + }); |
| 72 | + |
| 73 | +Let's also add a simple statement to that function which just logs to the console. |
| 74 | + |
| 75 | + util.puts('>> in connection event'); |
| 76 | + |
| 77 | + |
| 78 | +### Step #2, Setting up the client connection |
| 79 | + |
| 80 | +With our server now waiting for a connection we can open `./view/default.html` create our connection. |
| 81 | + |
| 82 | + var webSocket = new io.connect('http://localhost:8080'); |
| 83 | + |
| 84 | +Doing so will create a connection to our server. Like the server there is an event called `connect` that we can listen on and notify our user we've been connected. Let's add an event handler for `connect`. |
| 85 | + |
| 86 | + |
| 87 | + webSocket.on('connect', function() { |
| 88 | + $('#systemMessages').append('<li>Connected to the server.</li>'); |
| 89 | + }); |
| 90 | + |
| 91 | +### Step 3, Does it work? |
| 92 | + |
| 93 | +Open your terminal and get located to the root of the lab. To start our server let's now fire up node.js. |
| 94 | + |
| 95 | + > node ./server.js |
| 96 | + |
| 97 | +If everything has been done correctly, node should emit a message like such: |
| 98 | + |
| 99 | + >> the http server is @ 8080 |
| 100 | + |
| 101 | +Now let's open any browser and browse to: |
| 102 | + |
| 103 | + http://localhost:8080/default.html |
| 104 | + |
| 105 | +After a second or so, we should see the following message: |
| 106 | + |
| 107 | + Connected to the server. |
| 108 | + |
| 109 | +**for fun** try a number of different browsers and browser versions. If you have IE, start going backwards. You should notice that regardless of versions, the connection still happens. |
| 110 | + |
| 111 | +This works all in part due to Socket.IO. Socket.IO has built in a number of different "WebSocket" like techniques such as long polling, to enable a "WebSocket" like experience regardless of browser versioning, i.e. polyfilling. |
| 112 | + |
| 113 | +Try opening a number of different browser windows as well. You should see them all connect with no problems. |
| 114 | + |
| 115 | +### Step 4, disconnect |
| 116 | + |
| 117 | +Just like connecting, we have disconnecting and that event is known as `disconnect`. It only seems proper to enable that next. |
| 118 | + |
| 119 | +On our server lets add our `disconnect` function. |
| 120 | + |
| 121 | + socket.on('disconnect', function() { |
| 122 | + util.puts('>> disconnect called'); |
| 123 | + |
| 124 | + io.sockets.emit('message', 'i am outty'); |
| 125 | + }); |
| 126 | + |
| 127 | +And on the client. |
| 128 | + |
| 129 | + webSocket.on('disconnect', function() { |
| 130 | + $('#systemMessages').append('<li>Disconnected from the server.</li>'); |
| 131 | + }); |
| 132 | + |
| 133 | +Restart\Rerun and when you kill either side ( browser or server ) you should now see the disconnect message display. |
| 134 | + |
| 135 | +### Step 5. Send a message |
| 136 | + |
| 137 | +Once a client get's created let's send a message to **only** that client that just connected. Let's welcome them and ask for their name. |
| 138 | + |
| 139 | +On the server in the connect function lets send the following two messages: |
| 140 | + |
| 141 | + socket.send('Welcome to the awesome chat server.'); |
| 142 | + socket.send('Please Enter Your Name'); |
| 143 | + |
| 144 | +More on the name request later. |
| 145 | + |
| 146 | +Restart\Rerun. No messages! We have nothing on the client side to accept those messages. |
| 147 | + |
| 148 | +### SideNote |
| 149 | + |
| 150 | +We have now seen `io.sockets.emit` and `socket.send`. Basically `emit` will broadcast to **any** client connected while `send` will **only** send to the direct connection. |
| 151 | + |
| 152 | +### Step 6, the message |
| 153 | + |
| 154 | +The default message event is called `message`. On our client let's add an event listener for it. |
| 155 | + |
| 156 | + webSocket.on('message', function(message) { |
| 157 | + $('#recievedMessages').append('<li>' + message + '</li>'); |
| 158 | + }); |
| 159 | + |
| 160 | +Restart\Rerun and you should now see the connect message from the server. |
| 161 | + |
| 162 | +### Step 7, echo message |
| 163 | + |
| 164 | +At this point we have successfully connected both the client and server together, and event sent a message from the server to the client. |
| 165 | + |
| 166 | +Now lets send a message to the server, and have the server echo it back to us. |
| 167 | + |
| 168 | +On the client, let's add a `click` handler for for the `#echo` button where we send whatever was contained in the textbox `#sendMessage`. |
| 169 | + |
| 170 | +`webSocket.emit` is the function we will call, and it takes the event name, and a message. |
| 171 | + |
| 172 | + $('#echo').bind('click', function() { |
| 173 | + |
| 174 | + var message = $('#sendMessage').val(); |
| 175 | + webSocket.emit('echo', message); |
| 176 | + |
| 177 | + $('#sendMessage').val(''); |
| 178 | + }); |
| 179 | + |
| 180 | +### Step 8, accepting messages on the server |
| 181 | + |
| 182 | +As with step 6 we now need to add an event handler on the server for that event `echo`, otherwise it will never get handled. |
| 183 | + |
| 184 | + socket.on('echo', function(message) { |
| 185 | + util.puts('>> echo called: ' + message); |
| 186 | + socket.send('echo: ' + message); |
| 187 | + }); |
| 188 | + |
| 189 | +Restart\Rerun and you should see your client's connect, and be able to send the server messages while having the server bounce them back. |
| 190 | + |
| 191 | +You should open a few browsers windows and try it too. |
| 192 | + |
| 193 | +### Step 9, chat it up |
| 194 | + |
| 195 | +Now we just need to send and receive chat messages. Since the client is already receiving messages on the `message` event we will continue to use that event. |
| 196 | + |
| 197 | +To send a chat message let's add another event handler for the `#submit` button. Just like the `echo` message we will grab the text and `emit` the message but this time we will emit it on the `message` event. |
| 198 | + |
| 199 | + $('#submit').bind('click', function() { |
| 200 | + |
| 201 | + var message = $('#sendMessage').val(); |
| 202 | + webSocket.emit('message', message); |
| 203 | + |
| 204 | + $('#sendMessage').val(''); |
| 205 | + }); |
| 206 | + |
| 207 | +Now we need to implement `message` event on the server. If you remember in the start of the lab, we sent a message to the user asking for their name. Let's create a simple function to check for the user's name and `emit` a message saying they have entered the chat. |
| 208 | + |
| 209 | + var userName, checkForName; |
| 210 | + userName = undefined; |
| 211 | + |
| 212 | + checkForName = function(userNameInput) { |
| 213 | + if (userName === void 0) { |
| 214 | + userName = userNameInput; |
| 215 | + io.sockets.emit('message', userName + ' has entered chat'); |
| 216 | + } |
| 217 | + }; |
| 218 | + |
| 219 | +Lastly it's time to implement `message`. Nothing really different than in our previous steps except for the fact we will call our `checkForName` function and modify the incoming message adding the name while broadcasting it to everyone connected. |
| 220 | + |
| 221 | + socket.on('message', function(message) { |
| 222 | + var chatMessage; |
| 223 | + util.puts('>> message called: ' + message); |
| 224 | + checkForName(message); |
| 225 | + |
| 226 | + chatMessage = userName + ': ' + message; |
| 227 | + io.sockets.emit('message', chatMessage); |
| 228 | + }); |
| 229 | + |
| 230 | +Restart\Rerun and we should now have a simple chat server. |
| 231 | + |
| 232 | +### Extra Credit. |
| 233 | + |
| 234 | +Play around with creating your own custom events sending things back and forth from the server to the clients. |
| 235 | + |
| 236 | +- - - |
| 237 | +## Resources |
| 238 | + |
| 239 | +* W3C WebSocket Standard: http://dev.w3.org/html5/websockets/ |
| 240 | +* IETF WebSocket Protocol Spec: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-09 |
| 241 | +* HTML5 Labs: http://html5labs.com, http://html5labs.interoperabilitybridges.com/prototypes/websockets/websockets/info |
| 242 | +* node.js: http://nodejs.org/ |
| 243 | +* Socket.IO: http://socket.io/ |
| 244 | +* Pusher: http://pusher.com/ |
| 245 | +* CoffeeScript: http://coffeescript.org/ |
| 246 | + |
| 247 | +github |
| 248 | + |
| 249 | +* socket.io https://github.com/LearnBoost/socket.io-client |
| 250 | +* socket.io-client https://github.com/LearnBoost/socket.io-client |
| 251 | + |
0 commit comments