# `socketio.namespace`

class `socketio.namespace.``BaseNamespace`(environ, ns_name, request=None)

  The Namespace is the primary interface a developer will use to create a gevent-socketio-based application.

  You should create your own subclass of this class, optionally using one of the `socketio.mixins` provided (or your own), and define methods such as:

      1
      2
      3
      4
      5
      6

      def on_my_event(self, my_first_arg, my_second_arg):
          print "This is the my_first_arg object", my_first_arg
          print "This is the my_second_arg object", my_second_arg

      def on_my_second_event(self, whatever):
          print "This holds the first arg that was passed", whatever

  Handlers are automatically dispatched based on the name of the incoming event. For example, a ‘user message’ event will be handled by `on_user_message()`. To change this, override `process_event()`.

  We can also access the full packet directly by making an event handler that accepts a single argument named ‘packet’:

      1
      2
      3

      def on_third_event(self, packet):
          print "The full packet", packet
          print "See the BaseNamespace::call_method() method for details"

## Namespace initialization

> You can override this method:

> `BaseNamespace.``initialize`()

>   This is called right after `__init__`, on the initial creation of a namespace so you may handle any setup job you need.

>   Namespaces are created only when some packets arrive that ask for the namespace. They are not created altogether when a new `Socket` connection is established, so you can have many many namespaces assigned (when calling `socketio_manage()`) without clogging the memory.

>   If you override this method, you probably want to initialize the variables you’re going to use in the events handled by this namespace, setup ACLs, etc..

>   This method is called on all base classes following the method resolution order <http://docs.python.org/library/stdtypes.html?highlight=mro#class.__mro__> so you don’t need to call super() to initialize the mixins or other derived classes.

## 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:

> `BaseNamespace.``emit`(event, *args, **kwargs)

>   Use this to send a structured event, with a name and arguments, to the client.

>   By default, it uses this namespace’s endpoint. You can send messages on other endpoints with something like:

>   > `self.socket['/other_endpoint'].emit()`.

>   However, it is possible that the `'/other_endpoint'` was not initialized yet, and that would yield a `KeyError`.

>   The only supported `kwargs` is `callback`. All other parameters must be passed positionally.

>   Parameters:

>   - event – The name of the event to trigger on the other end.
>   - callback (callable) –

>     Pass in the callback keyword argument to define a call-back that will be called when the client acks.

>     This callback is slightly different from the one from `send()`, as this callback will receive parameters from the explicit call of the `ack()` function passed to the listener on the client side.

>     The remote listener will need to explicitly ack (by calling its last argument, a function which is usually called ‘ack’) with some parameters indicating success or error. The ‘ack’ packet coming back here will then trigger the callback function with the returned values.

> `BaseNamespace.``send`(message, json=False, callback=None)

>   Use send to send a simple string message.

>   If `json` is True, the message will be encoded as a JSON object on the wire, and decoded on the other side.

>   This is mostly for backwards compatibility. `emit()` is more fun.

>   Parameters: | callback (callable) – This is a callback function that will be called automatically by the client upon reception. It does not verify that the listener over there was completed with success. It just tells you that the browser got a hold of the packet.

> `BaseNamespace.``error`(error_name, error_message, msg_id=None, quiet=False)

>   Use this to use the configured `error_handler` yield an error message to your application.

>   Parameters:

>   - error_name – is a short string, to associate messages to recovery methods
>   - error_message – is some human-readable text, describing the error
>   - msg_id – is used to associate with a request
>   - quiet – specific to error_handlers. The default doesn’t send a message to the user, but shows a debug message on the developer console.

> `BaseNamespace.``disconnect`(silent=False)

>   Send a ‘disconnect’ packet, so that the user knows it has been disconnected (booted actually). This will trigger an onDisconnect() call on the client side.

>   Over here, we will kill all ``spawn``ed processes and remove the namespace from the Socket object.

>   Parameters: | silent – do not actually send the packet (if they asked for a disconnect for example), but just kill all jobs spawned by this Namespace, and remove it from the Socket.

## Dealing with incoming data

> `BaseNamespace.``recv_connect`()

>   Called the first time a client connection is open on a Namespace. This does not fire on the global namespace.

>   This allows you to do boilerplate stuff for the namespace like connecting to rooms, broadcasting events to others, doing authorization work, and tweaking the ACLs to open up the rest of the namespace (if it was closed at the beginning by having `get_initial_acl()` return only [‘recv_connect’])

>   Also see the different mixins (like RoomsMixin, BroadcastMixin).

> `BaseNamespace.``recv_message`(data)

>   This is more of a backwards compatibility hack. This will be called for messages sent with the original send() call on the client side. This is NOT the ‘message’ event, which you will catch with ‘on_message()’. The data arriving here is a simple string, with no other info.

>   If you want to handle those messages, you should override this method.

> `BaseNamespace.``recv_json`(data)

>   This is more of a backwards compatibility hack. This will be called for JSON packets sent with the original json() call on the JavaScript side. This is NOT the ‘json’ event, which you will catch with ‘on_json()’. The data arriving here is a python dict, with no event name.

>   If you want to handle those messages, you should override this method.

> `BaseNamespace.``recv_error`(packet)

>   Override this function to handle the errors we get from the client.

>   Parameters: | packet – the full packet.

> `BaseNamespace.``recv_disconnect`()

>   Override this function if you want to do something when you get a force disconnect packet.

>   By default, this function calls the `disconnect()` clean-up function. You probably want to call it yourself also, and put your clean-up routines in `disconnect()` rather than here, because that `disconnect()` function gets called automatically upon disconnection. This function is a pre-handle for when you get the disconnect packet.

> `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

> `BaseNamespace.``process_event`(packet)

>   This function dispatches `event` messages to the correct functions. You should override this method only if you are not satisfied with the automatic dispatching to `on_`-prefixed methods. You could then implement your own dispatch. See the source code for inspiration.

>   There are two ways to deal with callbacks from the client side (meaning, the browser has a callback waiting for data that this server will be sending back):

>   The first one is simply to return an object. If the incoming packet requested has an ‘ack’ field set, meaning the browser is waiting for callback data, it will automatically be packaged and sent, associated with the ‘ackId’ from the browser. The return value must be a sequence of elements, that will be mapped to the positional parameters of the callback function on the browser side.

>   If you want to know that you’re dealing with a packet that requires a return value, you can do those things manually by inspecting the `ack` and `id` keys from the `packet` object. Your callback will behave specially if the name of the argument to your method is `packet`. It will fill it with the unprocessed `packet` object for your inspection, like this:

>       def on_my_callback(self, packet):
>           if 'ack' in packet:
>               self.emit('go_back', 'param1', id=packet['id'])

> 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:

> `BaseNamespace.``spawn`(fn, *args, **kwargs)

>   Spawn a new process, attached to this Namespace.

>   It will be monitored by the “watcher” process in the Socket. If the socket disconnects, all these greenlets are going to be killed, after calling BaseNamespace.disconnect()

>   This method uses the `exception_handler_decorator`. See Namespace documentation for more information.

> `BaseNamespace.``kill_local_jobs`()

>   Kills all the jobs spawned with BaseNamespace.spawn() on a namespace object.

>   This will be called automatically if the `watcher` process detects that the Socket was closed.

## 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"`.

> `BaseNamespace.``get_initial_acl`()

>   ACL system: If you define this function, you must return all the ‘event’ names that you want your User (the established virtual Socket) to have access to.

>   If you do not define this function, the user will have free access to all of the `on_*()` and `recv_*()` functions, etc.. methods.

>   Return something like: `set(['recv_connect', 'on_public_method'])`

>   You can later modify this list dynamically (inside `on_connect()` for example) using:

>       self.add_acl_method('on_secure_method')

>   `self.request` is available in here, if you’re already ready to do some auth. check.

>   The ACLs are checked by the `process_packet()` and/or `process_event()` default implementations, before calling the class’s methods.

>   Beware, returning `None` leaves the namespace completely accessible.

>   The methods that are open are stored in the `allowed_methods` attribute of the `Namespace` instance.

> `BaseNamespace.``add_acl_method`(method_name)

>   ACL system: make the method_name accessible to the current socket

> `BaseNamespace.``del_acl_method`(method_name)

>   ACL system: ensure the user will not have access to that method.

> `BaseNamespace.``lift_acl_restrictions`()

>   ACL system: This removes restrictions on the Namespace’s methods, so that all the `on_*()` and `recv_*()` can be accessed.

> `BaseNamespace.``reset_acl`()

>   Resets ACL to its initial value (calling `get_initial_acl`()` and applying that again).

> 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:

> `BaseNamespace.``process_packet`(packet)

>   If you override this, NONE of the functions in this class will be called. It is responsible for dispatching to `process_event()` (which in turn calls `on_*()` and `recv_*()` methods).

>   If the packet arrived here, it is because it belongs to this endpoint.

>   For each packet arriving, the only possible path of execution, that is, the only methods that can be called are the following:

>   - recv_connect()
>   - recv_message()
>   - recv_json()
>   - recv_error()
>   - recv_disconnect()
>   - on_*()
> `BaseNamespace.``call_method_with_acl`(method_name, packet, *args)

>   You should always use this function to call the methods, as it checks if the user is allowed according to the ACLs.

>   If you override `process_packet()` or `process_event()`, you should definitely want to use this instead of `getattr(self, 'my_method')()`

> `BaseNamespace.``call_method`(method_name, packet, *args)

>   This function is used to implement the two behaviors on dispatched `on_*()` and `recv_*()` method calls.

>   Those are the two behaviors:

>   - If there is only one parameter on the dispatched method and it is named `packet`, then pass in the packet dict as the sole parameter.
>   - Otherwise, pass in the arguments as specified by the different `recv_*()` methods args specs, or the `process_event()` documentation.

>   This method will also consider the `exception_handler_decorator`. See Namespace documentation for details and examples.