Proxying WebSockets with Nginx and Socket.IO
Why would you want to proxy WebSockets through Nginx?
That’s probably the first question that comes to mind. Why would you want to proxy your websockets?
The answer is pretty simple. You want your Nginx to run on port 80 (duh) but you also want your WebSockets to go through port 80, right?
That way, you shouldn’t have any trouble connecting to a WebSocket server when you are behind a firewall.
The Problem
My problem was that my WebSocket server was running on port 5000. It would work when connecting to it from my localhost.
ws://localhost:5000
But when I wanted to push it to production and try it on my university’s network it wouldn’t work!
Obviously that was to be expected.
Our university’s network only allows a couple of ports through their firewall. Obviously port 80 was one of them and port 5000 was not.
Now the problem is that my server was already running Nginx on port 80. So obviously my WebSocket server couldn’t run on port 80.
And this is where proxying comes in play.
Using WebSocket proxying in Nginx I can keep my WebSocket server running on port 5000 and my Nginx on port 80.
All I had to do was configure my Nginx to start proxying WebSockets from port 80 (external) to port 5000 (internal).
After that, you can simply connect to
ws://yourhost.com:80 (You don’t have to specify the port if you’re using port 80, but I’m doing this anyway just to make it clear)
Let’s start doing stuff already!
Ok, so the first thing you need to know is that WebSocket proying is supported in Nginx since version 1.3.13 which is (as of this date) a development version.
So if you’re running Nginx in production, you might not want to upgrade just yet.
The first thing you want to do is open up the Nginx configuration file. I’m using nano (no VIM, sorry) for this.
Then find where you defined your virtual server and add the configuration needed to proxy websockets:
location /socket.io/ { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }
So, what exactly is happening here?
First, we define the route in which we want to work. When using Socket.io as the WebSocket server, all WebSocket traffic will normally go through the /socket.io/ route. e.g. http://michieldemey.be/socket.io/
(You can change this default route in socket.io’s configuration: https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO)
Anyway, my Nginx is running on port 80 (external) and I need to proxy all WebSocket traffic to port 8080 (internal).
We can specify this using “proxy_pass” setting.
As you can see in my configuration above, I’m proxying everything to http://localhost:8080. So now I’m proxying all WebSockets to my SebSocket server running on port 8080.
But that’s not all. You need to specify that you want to use HTTP 1.1, because WebSockets use the “Upgrade” header that’s only available in HTTP 1.1 and not HTTP 1.0.
The other two settings are basically just to fill in the Upgrade and Connection header. Leave it as is and it should work.
And that’s pretty much it!
So now I’m proxying WebSockets through port 80 to port 8080. And that without too much configuration.
For more information, check out Nginx’s official page on this topic: http://nginx.org/en/docs/http/websocket.html
Node.js and Socket.io – A basic chat application using websockets
Installation (Ubuntu & Windows)
I’m using an Ubuntu 12.04 LTS server, but any OS will do.
To install Node.js on Ubuntu, it’s fairly easy.
A few commands and you can start developing.
sudo apt-get install python-software-properties sudo add-apt-repository ppa:chris-lea/node.js sudo apt-get update sudo apt-get install nodejs npm
If you’re running Windows, you can simply use the installer.
Note that from here, I’ll be working on Ubuntu 12.04 using a terminal.
Downloading dependencies
I’m going to use Socket.io for cross-browser websockets, so we need to install this.
First, cd
to the directory of your application.
Then create a file called “package.json”. This file will tell us a bit about the application we’ll be writing.
Add the following content and save the file.
{ "name": "node-chat", "version": "0.0.1", "dependencies": { "express": "3.x", "socket.io": "latest" }, "engines": { "node": "0.8.x", "npm": "1.1.x" } }
Then we can install all of our dependencies automatically using npm
. (Node Packaged Modules)
npm install socket.io
This will fetch the dependencies that we’ve defined in our package.json file.
Currently, we’re using both Socket.io and Express.
Once that’s done you should have a new folder “node_modules”. Now we can create the actual application.
Getting stuff done (server-side)
Let’s first code the server. Create a new JavaScript file. I named mine “server.js”.
First let me show you what we will add to this file. I’ll explain it later.
var port = 5000; var app = require('express')(); var server = require('http').createServer(app); var io = require('socket.io').listen(server); console.log("Listening on port " + port); server.listen(port); // routing app.get('/', function (req, res) { res.sendfile(__dirname + '/chat.html'); }); // usernames which are currently connected to the chat var usernames = {}; io.sockets.on('connection', function (socket) { // when the client emits 'sendchat', this listens and executes socket.on('sendchat', function (data) { // we tell the client to execute 'updatechat' with 2 parameters io.sockets.emit('updatechat', socket.username, data); }); // when the client emits 'adduser', this listens and executes socket.on('adduser', function(username){ // we store the username in the socket session for this client socket.username = username; // add the client's username to the global list usernames[username] = username; // echo to client they've connected socket.emit('updatechat', 'SERVER', 'you have connected'); // echo globally (all clients) that a person has connected socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected'); // update the list of users in chat, client-side io.sockets.emit('updateusers', usernames); }); // when the user disconnects.. perform this socket.on('disconnect', function(){ // remove the username from global usernames list delete usernames[socket.username]; // update list of users in chat, client-side io.sockets.emit('updateusers', usernames); // echo globally that this client has left socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected'); }); });
It’s not that hard really.
First we define a few variables.
- A port number
- The application itself (using Express)
- A server that will listen to requests
- A socket.io variable that will handle websockets
- An array to keep the usernames of the connected users
Then make the server listen to incoming requests simply by calling
server.listen(port);
We then set the routing for our Express application.
This will send the chat.html file to the client when it tries to get the index page of our application.
// routing app.get('/', function (req, res) { res.sendfile(__dirname + '/chat.html'); });
Then we can start binding events.
Socket.io has a basic event “connection”. This will always trigger when a new user connects to the server.
io.sockets.on('connection', function (socket) { }
Inside that function, you can bind other events. Eventss can be user defined.
I’m not going to explain all of them.
Things should be pretty straightforward if you know that
socket.on('', function(data));
will bind to a certain event.io.sockets.emit('', data);
will send an event with data to everyone that’s currently connected.
On to the client
Again, I will first show you what’s in the “chat.html” file that our application will serve.
<script src="/socket.io/socket.io.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script> <script> var URL = window.location.protocol + "//" + window.location.host; console.log("Connecting to " + URL); var socket = io.connect(URL); // on connection to server, ask for user's name with an anonymous callback socket.on('connect', function(){ // call the server-side function 'adduser' and send one parameter (value of prompt) socket.emit('adduser', prompt("What's your name?")); }); // listener, whenever the server emits 'updatechat', this updates the chat body socket.on('updatechat', function (username, data) { $('#conversation').append('<b>'+username + ':</b> ' + data + '<br>'); }); // listener, whenever the server emits 'updateusers', this updates the username list socket.on('updateusers', function(data) { $('#users').empty(); $.each(data, function(key, value) { $('#users').append('<div>' + key + '</div>'); }); }); // on load of page $(function(){ // when the client clicks SEND $('#datasend').click( function() { var message = $('#data').val(); $('#data').val(''); // tell server to execute 'sendchat' and send along one parameter socket.emit('sendchat', message); }); // when the client hits ENTER on their keyboard $('#data').keypress(function(e) { if(e.which == 13) { $(this).blur(); $('#datasend').focus().click(); } }); }); </script> <div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;"> <b>USERS</b> <div id="users"></div> </div> <div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;"> <div id="conversation"></div> <input id="data" style="width:200px;" /> <input type="button" id="datasend" value="send" /> </div>
The HTML is not really important here.
Here we do pretty much the same thing as on the server.
Listening to events and sending events. It’s really not much more then that.
I’ll leave it up to you to figure out the client code. If you have some knowledge of JavaScript and JQuery, this should be easy.
Running your application
Just make sure you cd
into the directory where your application resides.
Then call
node server.js
Replacing server.js with the file where you’ve written your server code.
It should now run, and you can browse to your application using your favorite webbrowser. (Just remember to use to the correct port)
PostgreSQL driver for FuelPHP
Some kind of intro
I’m currently writing a web app using FuelPHP and hosted this on my web host.
However, I wanted to experiment with web application in the cloud. And I thought of Heroku.
Seeing as how Heroku was free for starting developers, I thought I’d give it a go!
Heroku, by default, gives you a PostgreSQL server that you can use. To be honest, I’ve never used PostgreSQL before, but I read about it. Did some research and decided to try it out in combination with FuelPHP.
FuelPHP can use a PostgreSQL by default, but it uses PDO, so you’re limited to basic database stuff. However if you want to use (more advanced) PostgreSQL specific features, you need a native PostgreSQL driver. Thankfully, someone else had already created one.
Here is the original code: https://launchpad.net/fuel-native-pgsql. However, his code requires you to “paste” the code in the core functionality of FuelPHP. That’s not how we do things around here. Doing some research (http://docs.fuelphp.com/general/extending_core.html#extend_from_packages) I thought it would be best to create a package for the native PostgreSQL driver that extends the original FuelPHP core. That way, you can simply load it from the configuration file and you won’t have any trouble when upgrading your FuelPHP core. (Unless FuelPHP makes some drastic changes.)
The actual package
It’s on GitHub, so feel free to contribute!
Download: https://github.com/MichielDeMey/fuel-postgresql
How to install
- Clone this repository
- Copy the “fuel-pgsql” folder to Fuel’s package folder
- Enable the package in the configuration file
- Edit your database configuration to use the PostgreSQL driver (
'type' => 'pgsql'
)
Create a basic HTML5 platformer with Crafty and Box2D – Part 3
Halt, brave adventurer!
This article requires some knowledge of JavaScript.
Documentation: JavaScript, Crafty, Box2DWeb (Basic Usage).
Github repo: Crafty Platformer Tutorial
Every game needs a hero.
A game wouldn’t be complete without a protagonist, right? So let us create one.
Though he’s not much of a hero, I’ll be using this Guinea pig.
And here’s an animated version. We won’t be using this gif though.
It will have to do for now. Feel free to create your own hero though. Just make sure you create a spritesheet of your hero.
The implementation.
The sprite
Save your spritesheet (or use mine) to your web/images/ folder and give it an appropriate name.
First, we will have to define the sprite in the sprites.js file. Following the example, you should have something like this:
images:{ 'ufo' : { 'file' : 'web/images/ufo.png', 'tile' : 211, 'tileh' : 117, 'elements': { 'ufo' : [0, 0] } }, 'guinea' : { 'file' : 'web/images/guineapig.png', 'tile' : 80, 'tileh' : 56, 'elements': { 'guinea' : [0, 0] } } }
NOTE: The “tile” property should be the width of a single frame of your animation. In my case it’s 80 pixels.
The entity
Now that Crafty knows which sprites to load, we can continue. Now we’ll create the entity.
Obviously we’re going to create it in the entities folder.
Create a new javascript file there. Mine’s called guineapig.js.
Let me first show you what’s in it. I’ll explain later.
GuineaPig = BaseEntity.extend({ defaults: { }, initialize: function(){ var model = this; var entity = Crafty.e("2D, " + gameContainer.conf.get('renderType') + ", guinea, SpriteAnimation"); entity .attr({x: ((Crafty.viewport.width/2) - (entity.w/2)), y: 0, z: 300}) .animate("walking", 0, 0, 2) .bind('EnterFrame', function(e){ this.animate("walking", 20); }) .setName('Guinea Pig'); entity.origin(entity.w/2, entity.h/2); model.set({'entity' : entity }); } });
So how does this all work?
First we need to extend the BaseEntity.
GuineaPig = BaseEntity.extend({ ... });
You will always have to do this when using Crafty’s Boilerplate. Don’t forget to name your entity as well. In my case GuineaPig.
Next up is the defaults. Here you can set properties of an entity. These will be Backbone properties from Backbone.js! Not Crafty properties.
defaults: { },
initialize: function(){ ... }
Everything in this function will be executed when the entity is first created. This will happen only once.
var model = this;
This is the variable that actually holds the Backbone object. You can use this variable to change the properties that you’ve defined in the defaults.
var entity = Crafty.e("2D, " + gameContainer.conf.get('renderType') + ", guinea, SpriteAnimation");
This is the actual entity itself. Note the “guinea” component, it has to be the same name as the sprite you defined in sprites.js.
Also the “SpriteAnimation” component is mandatory.
Next we set a few properties of our hero. I won’t go over all of them, just the special ones.
.animate("walking", 0, 0, 2)
With this one, we define the animation. Or in crafty terms: a “reel”.
The first parameter is the id of the reel.
The second one defines the x-value of the starting of the reel, unit is the width of our frame width. (It was 80 pixels, remember?)
The third parameter is the y-value. Unit is the height of our spritesheet.
And the fourth parameter is the end x position on the sprite map. In our case 2. (3 frames, but the index starts at 0 so it’s 2.)
Read more about it in their documentation: http://craftyjs.com/api/SpriteAnimation.html
.bind('EnterFrame', function(e){ this.animate("walking", 20); })
Now that we have defined the animation, we can use it. Just bind the animation to the EnterFrame event for now.
The first parameter is the reel id. As we have defined above.
The second parameter is actually the delay in-between frames. The unit is in milliseconds.
There, that’s it for our guinea pig. Now we just have to wrap it up.
Wrapping it up
Now that we have defined our hero, we still have to load it. This is done in our main scene.
var elements = [ "src/entities/ufo.js", "src/entities/guineapig.js", "src/interfaces/info.js" ];
Simply adding our script will load it.
But that’s not enough. One more thing to do.
We still have to initialize it.
//when everything is loaded, run the main scene require(elements, function() { //sc['ufo'] = new Ufo(); sc['guineapig'] = new GuineaPig(); infc['info'] = new Info(); });
Easy, no? All we had to do was create a new instance of our hero.
I’ve also commented out the UFO object since we won’t be needing it. That means it won’t be initialized.
This should be the end result.
That’s it for now. I will discuss how to add physics and move your hero later.
Create a basic HTML5 platformer with Crafty and Box2D – Part 2.5
Halt, brave adventurer!
This article requires some knowledge of JavaScript.
Documentation: JavaScript, Crafty, Box2DWeb (Basic Usage).
Github repo: Crafty Platformer Tutorial
A continuation of our previous quest.
Previously we created a simple level using Tiled and in this quest we will take it a bit further.
We are going to add physics to the game. This isn’t 1997, we have modern technologies nowadays so we’d better use them.
On the downside, it can be quite difficult to learn Box2D at first but it’s really fun once you get into it.
Let’s get magical!
While physics are nothing magical, they are rather fascinating. More then that, they give your game a more dynamic and realistic feeling.
Just don’t overdo it. Though physics being awesome, they do have a big impact on performance.
Enough loitering
For this tutorial we’ll need Box2dWeb and the CraftyBox2d component. Demos for Crafty’s CraftyBox2d component can be found on their GitHub page.
NOTE: If you’re interested in Box2d, I strongly recommend that you check out the demos. There is some interesting stuff in there.
Anyway, download Box2dWeb and the CraftyBox2d component.
I’m going to add the Box2dWeb library in the libs folder and the CraftyBox2d component in the components folder.
Now we just have to load both the library and the component in our JavaScript.
To load our library, we’ll have to add it to our index.html page. Very simple stuff.
<script src="src/libs/Box2dWeb-2.1.a.3.min.js"></script>
And our component, just like we did in part 2.
// array with local components var elements = [ "src/components/MouseHover.js?v="+version+"", "src/components/craftybox2d-release-uncompressed.js?v="+version+"", "src/components/tiledlevel-release-uncompressed.js?v="+version+"", "src/entities/base/BaseEntity.js?v="+version+"", ];
And now we’ve set up our physics world. Now we just have to initialize it and we should be ready to go.
Simply call the init function. This can either be in game.js or scenes/main.js depending on when you want the physics to be enabled.
I’ve initialized it in scenes/main.js.
Crafty.box2D.init(0, 10, 32, true);
USAGE:
The first parameter is the gravity along the x-axis. In this case 0, otherwise we would be pulled to the side.
The second parameter is the gravity along the y-axis. I’ve set it to 10. This will make all physics objects fall down.
The third parameter is the “pixel-to-meter” ratio. I’ve set it to 32. That means that 32 pixels = 1 meter in the game.
The fourth parameter will allow bodies to “sleep” when they are inactive. It’s best to leave this to true for performance.
Now we should be able to work with physics!
Applying the magic.
Now let’s go and add the physics to our level.
To do this, we’ll have to edit the TiledLevel component we used in part 2. Don’t worry, it’s nothing major.
Somewhere around line 18 you should see all the components of each of our tiles.
components = "2D, " + drawType + ", " + sName + ", MapTile";
Simply add the Box2D component.
components = "2D, " + drawType + ", " + sName + ", MapTile, Box2D";
One more thing and we’re done editing.
Simply define the Box2D properties of the entity. Around line 46 you’ll see that you can set properties of the tile entity.
Just add the folowing Box2d property and we should be good.
tile.box2d({ bodyType: 'static' }); //Add the physics!
Change ‘static’ to ‘dynamic’ to see the level collapse. Really fun!
(We won’t be using that though. Just set it back to static after you’ve done playing ;))
Though before you do that, you might want to create a floor in scenes/main.js that prevents anything from falling through.
// Create the floor var floor = Crafty.e("2D, Canvas, Box2D, death") .attr({ isFloor: true }) .setName("Box2D Floor") .box2d({ bodyType: 'static', shape: [[0, Crafty.viewport.height], [Crafty.viewport.width, Crafty.viewport.height]] });
That’s the end of todays quest.
Though before you go, I’d like to give you another tip.
TIP: Use Box2D’s debug view to see which objects have physics applied to them and other useful information.
//Start the Box2D debugger Crafty.box2D.showDebugInfo();
Categories
- Android (1)
- Flash (1)
- HTML5 (9)
- Programming (15)
- .Net Programming (3)
- Java (2)
- PHP (1)
- Web (11)