socketio.namespace

Namespace initialization

You can override this method:

Event flow

This is an attempt at catching the gotchas of the Socket.IO protocol, which, for historical reasons, sometimes have weird event flow.

The first function to fire is initialize(), which will be called only if there is an incoming packet for the Namespace. A successful javascript call to io.connect() is not sufficient for gevent-socketio to trigger the creation of a Namespace object. Some event has to flow from the client to the server. The connection will appear to have succeeded from the client’s side, but that is because gevent-socketio maintains the virtual socket up and running before it hits your application. This is why it is a good pratice to send a packet (often a login, or subscribe or connect JSON event, with io.emit() in the browser).

If you’re using the GLOBAL_NS, the recv_connect() will not fire on your namespace, because when the connection is opened, there is no such packet sent. The connect packet is only sent over (and explicitly sent) by the javascript client when it tries to communicate with some “non-global” namespaces. That is why it is recommended to always use namespaces, to avoid having a different behavior for your different namespaces. It also makes things explicit in your application, when you have something such as /chat, or /live_data. Before a certain version of Socket.IO, there was only a global namespace, and so this behavior was kept for backwards compatibility.

Then flows the normal events, back and forth as described elsewhere (elsewhere??).

Upon disconnection, here is what happens: [INSERT HERE the details flow of disconnection handling, events fired, physical closing of the connection and ways to terminate a socket, when is the Namespace killed, the state of the spawn’d processes for each Namespace and each virtsocket. This really needs to be done, and I’d appreciate having people investigate this thoroughly]

There you go :)

Namespace instance properties

BaseNamespace.session

The session is a simple dict that is created with each Socket instance, and is copied to each Namespace created under it. It is a general purpose store for any data you want to associated with an open Socket.

BaseNamespace.request

This is the request object (or really, any object) that you have passed as the request parameter to the socketio_manage() function.

BaseNamespace.ns_name

The name of the namespace, like /chat or the empty string, for the “global” namespace.

BaseNamespace.environ

The environ WSGI dictionary, as it was received upon reception of the first request that established the virtual Socket. This will never contain the subsequent environ for the next polling, so beware when using cookie-based sessions (like Beaker).

BaseNamespace.socket

A reference to the Socket instance this namespace is attached to.

Sending data

Functions to send data through the socket:

Dealing with incoming data

BaseNamespace.exception_handler_decorator(fn)

This method can be a static, class or bound method (that is, with @staticmethod, @classmethod or without). It receives one single parameter, and that parameter will be the function the framework is trying to call because some information arrived from the remote client, for instance: on_* and recv_* functions that you declared on your namespace.

The decorator is also used to wrap called to self.spawn(self.job_something), so that if anything happens after you’ve spawn’d a greenlet, it will still catch it and handle it.

It should return a decorator with exception handling properly dealt with. For example:

import traceback, sys
import logging
def exception_handler_decorator(self, fn):
    def wrap(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except Exception, e:
            stack = traceback.format_exception(*sys.exc_info())
            db.Evtrack.write("socketio_exception",
                             {"error": str(e),
                              "trace": stack},
                             self.request.email)
            logging.getLogger('exc_logger').exception(e)
    return wrap

You would override this method only if you are not completely satisfied with the automatic dispatching to on_-prefixed methods. You could then implement your own dispatch. See the source code for inspiration.

Process management

Managing the different callbacks, greenlets and tasks you spawn from this namespace:

ACL system

The ACL system grants access to the different on_*() and recv_*() methods of your subclass.

Developers will normally override get_initial_acl() to return a list of the functions they want to initially open. Usually, it will be an on_connect event handler, that will perform authentication and/or authorization, set some variables on the Namespace, and then open up the rest of the Namespace using lift_acl_restrictions() or more granularly with add_acl_method() and del_acl_method(). It is also possible to check these things inside initialize() when, for example, you have authenticated a Global Namespace object, and you want to re-use those credentials or authentication infos in a new Namespace:

# GLOBAL_NS = ''

class MyNamespace(BaseNamespace):
    ...
    def initialize(self):
        self.my_auth = MyAuthObjet()
        if self.socket[GLOBAL_NS].my_auth.logged_in == True:
            self.my_auth.logged_in = True

The content of the ACL is a list of strings corresponding to the full name of the methods defined on your subclass, like: "on_my_event" or "recv_json".

This function is used internally, but can be useful to the developer:

This is the attribute where the allowed methods are stored, as a list of strings, or a single None:

.. autoattribute:: allowed_methods

Low-level methods

Packet dispatching methods. These functions are normally not overriden if you are satisfied with the normal dispatch behavior: