Source code for pygnetic.connection

# -*- coding: utf-8 -*-
"""
Module containing base class for adapters representing network connections.
"""

import re
import logging
from weakref import proxy
from functools import partial
import event

_logger = logging.getLogger(__name__)


[docs]class Connection(object): """Class allowing to send messages :param parent: parent :class:`~.client.Client` or :class:`~.server.Server` :param conn_obj: connection object :param message_factory: :class:`~.message.MessageFactory` object """ address = ('', '') # \ connected = False # / default values, should be overridden by adapter class __id_cnt = 0 def __init__(self, parent, conn_obj, message_factory, *args, **kwargs): super(Connection, self).__init__(*args, **kwargs) self.parent = proxy(parent) self.message_factory = message_factory self.message_factory.reset_context(self) self.handlers = [] self.data_sent = 0 self.data_received = 0 self.messages_sent = 0 self.messages_received = 0 self.id = self.__class__.__id_cnt = self.__id_cnt + 1 self._key = None def __getattr__(self, name): parts = name.split('_', 1) if (len(parts) == 2 and parts[0] == 'net' and parts[1] in self.message_factory._message_names): p = partial(self._send_message, self.message_factory.get_by_name(parts[1])) p.__doc__ = "Send %s message to remote host\n\nHost.net_%s" % ( parts[1], self.message_factory._message_names[parts[1]].__doc__) # add new method so __getattr__ is no longer needed setattr(self, name, p) return p else: raise AttributeError("'%s' object has no attribute '%s'" % (type(self).__name__, name))
[docs] def send(self, message, *args, **kwargs): """Send message to remote host. :param message: class created by :meth:`~.message.MessageFactory.register` or message name :param args: parameters used to initialize message object :param kwargs: keyword parameters used to initialize message object """ if isinstance(message, basestring): message = self.message_factory.get_by_name(message) self._send_message(message, *args, **kwargs)
def _send_message(self, message, *args, **kwargs): name = message.__name__ params = self.message_factory.get_params(message) try: message_ = message(*args, **kwargs) except TypeError, e: e, f = re.findall(r'[^_a-z](\d+)', e.message, re.I) raise TypeError('%s takes exactly %d arguments (%d given)' % (message.__doc__, int(e) - 1, int(f) - 1)) data = self.message_factory.pack(message_) _logger.info('#%s Sent %s message', self.id, name) self.data_sent += len(data) self.messages_sent += 1 return self._send_data(data, **params) def _send_data(self, data, channel=0, **kwargs): raise NotImplementedError('Should be implemented by adapter class') def _receive(self, data, **kwargs): self.data_received += len(data) for message in self.message_factory.unpack_all(data, self): self.messages_received += 1 name = message.__class__.__name__ _logger.info('#%s Received %s message', self.id, name) event.received(self, message) for h in self.handlers: getattr(h, 'net_' + name, h.on_recive)(message, **kwargs) def _connect(self): _logger.info('#%s Connected to %s', self.id, self.address) event.connected(self) for h in self.handlers: h.on_connect() def _disconnect(self): _logger.info('#%s Disconnected from %s', self.id, self.address) event.disconnected(self) for h in self.handlers: h.on_disconnect() self.parent._remove(self._key)
[docs] def disconnect(self, *args): """Request a disconnection. :param args: additional arguments for :term:`network adapter` """ raise NotImplementedError('Should be implemented by adapter class')
[docs] def add_handler(self, handler): """Add new Handler to handle messages. :param handler: instance of :class:`~.handler.Handler` subclass """ self.handlers.append(handler) handler.connection = proxy(self)