Real-time Environments
with SocketIO
reproduced with the permission of Ryan Hestin
Hello! Today, we want to give everyone a bit of our behind-the-scenes as we rebuild MegaBits from the ground up. So let’s dive right in! To start off a series of related development articles, we will look into some of the design decisions behind the MegaBits backend being build on the NodeJS platform. Let’s start with some backend!
SocketIO is a framework for handling real-time, socket-based communication between many clients. It began in 2011 as a project for the then-newly-emerging NodeJS platform. While real-time communication wasn’t new to the internet, this set of tools allowed a developer to easily implement and manage many connections and quickly grew. Today, SocketIO features over 12,000 stars and 2,100 forks on GitHub. Guillermo Rauch (@rauchg), the creator and lead maintainer for the repository, was thrilled to finally announce the full 1.0 release of his brainchild framework in May 2014 after years of anticipation.
Ok, history lesson aside, let’s bring this a bit more into perspective. A majority of my first six weeks on the MegaBits squad has been dedicated to research of SocketIO (and other) frameworks. The major goal? To build an Environment Manager in preparation for our public beta.
“Environment Manager? WTF is that?”
I know, I hear you. Here’s a quick rundown of what this piece of the MegaBits system actually does:
In MegaBits, a player is dropped onto a map that corresponds to his/her location in the world. On this map, a collection of heal stations, items, and monsters all happily jump around. Now, let’s say your friend sitting next to you fires up the map and wants to check out what’s going on as well. You hold your phones side-by-side and, as expected, you both see the same world. Coincidently, you both happen to spot the exact same Bunbun on the map at the same moment, and you both go to tap it in order to battle it on your adventure to becoming MegaBits all stars! Woot! But wait, there’s a problem. You both can’t be fighting the same Bunbun at the same time! Only one player will be able to engage it, but how do the players’ phones know who will fight it? Even better, how will they know if someone else on the map is already engaged with it?! This is where the Environment Manager and SocketIO comes in…
We anticipate being able to handle all of the types of interactions amongst players in the game as a fully synchronized world! (Incoming nerd-speak…) But there are other more technical reasons, too! I’d like to share a few key features of SocketIO that will really help enable us to build out this aspect of the project.
First, there are some new additions to SocketIO’s scalability. SocketIO 1.0 introduced a new implementation of its pubsub that enables better clustering of servers handling requests. As we plan on having a growing user base, the ability to expand SocketIO’s functionality across many servers will ensure our players a seamless experience regardless of how many people are online at once. You read more about these changes here.
Second, there is a whole new underlying engine driving the communication layer of SocketIO, aptly named EngineIO. That means that now, in 1.0, EngineIO is code handling all the low level communication. At the same time, SocketIO itself is an abstract layer that handles all the higher level features and niceties that we’ve learned to love about SocketIO. A key implementation detail about EngineIO is how it handles the initial sequence of connection attempts between a client and the server. Before 1.0, SocketIO used to begin by immediately attempting to connect with a WebSocket and degrade down into XHR or JSONP long-polling. This was mildly troubling for us in the early research days since our clients were going to be connecting primarily over cellular connections which aren’t the most reliable. We would have to account for the very likely occurrence of lag times due to WebSocket failures. However, with 1.0, we were very pleased to see a reversal in the connection process. EngineIO now begins with XHR and JSONP long-polling right off the bat and will gracefully upgrade to a full WebSocket should the connection prove worthy. This was great news for us regarding our mobile user base.
In order to take advantage of SocketIO 1.0 in our iOS app, we needed to create an Objective-C compatible client. Enter SIOSocket, an Objective-C wrapper around the 1.0 version of the official SocketIO client. From the dev’s perspective: emitting and reacting to events. With the -on:do: method, connected sockets can perform a block whenever that event is fired. And with the -emit:… method, connected sockets can fire events to the server with any number of parameters. Under the hood, things get weird. Because we know we couldn’t do a better job of reimplementing all of the fine-tuning of the official SocketIO client, the Objective-C client simply uses it. To work this magic, the SIOSocket class creates a new UIWebView, renders out its JSContext, and uses it like a key/value store for native JavaScript processes. Whenever a new SIOSocket object is brought to life, its own JSContext creates an underlying io() object, which acts as a bridge between the developer’s iOS code and the running NodeJS app. Here’s an artist’s representation of what that might look like:
I hope this post provided a bit of behind-the-scenes looks into MegaBits development process and decisions! We look forward to pushing out our public beta and to providing all the players out there with the location based monster battle game you deserve!