1. Szymon Wróblewski
  2. pygnetic

Commits

Szymon Wróblewski  committed 039abab

created Server class, moved Connection and Receiver to connection module, removed ReceiverManager

  • Participants
  • Parent commits edc588a
  • Branches default

Comments (0)

Files changed (8)

File pygame_network/client.py

View file
 import logging
-from weakref import WeakKeyDictionary, WeakValueDictionary
-from functools import partial
 import enet
 from packet import PacketManager
+from connection import Connection
 
 _logger = logging.getLogger(__name__)
 
-# dummy events
-def _connected_event(connection): pass
-def _disconnected_event(connection): pass
-def _received_event(connection, channel, packet, packet_id): pass
-def _response_event(connection, channel, packet, packet_id): pass
-
-STATE_ACKNOWLEDGING_CONNECT = enet.PEER_STATE_ACKNOWLEDGING_CONNECT
-STATE_ACKNOWLEDGING_DISCONNECT = enet.PEER_STATE_ACKNOWLEDGING_DISCONNECT
-STATE_CONNECTED = enet.PEER_STATE_CONNECTED
-STATE_CONNECTING = enet.PEER_STATE_CONNECTING
-STATE_CONNECTION_PENDING = enet.PEER_STATE_CONNECTION_PENDING
-STATE_CONNECTION_SUCCEEDED = enet.PEER_STATE_CONNECTION_SUCCEEDED
-STATE_DISCONNECTED = enet.PEER_STATE_DISCONNECTED
-STATE_DISCONNECTING = enet.PEER_STATE_DISCONNECTING
-STATE_DISCONNECT_LATER = enet.PEER_STATE_DISCONNECT_LATER
-STATE_ZOMBIE = enet.PEER_STATE_ZOMBIE
-
 
 class Client(object):
     def __init__(self, connections_limit=1, channel_limit=0, in_bandwidth=0, out_bandwidth=0):
         address = enet.Address(address, port)
         peer = self.host.connect(address, channels, packet_manager.get_hash())
         peer.data = peer_id
-        connection = Connection(peer, packet_manager)
+        connection = Connection(self, peer, packet_manager)
         self._peers[peer_id] = connection
         return connection
 
                 _logger.info('Connected to %s', event.peer.address)
             elif event.type == enet.EVENT_TYPE_DISCONNECT:
                 self._peers[event.peer.data]._disconnect()
+                del self._peers[event.peer.data]
                 _logger.info('Disconnected from %s', event.peer.address)
-                del self._peers[event.peer.data]
             elif event.type == enet.EVENT_TYPE_RECEIVE:
                 self._peers[event.peer.data]._receive(event.packet.data, event.channelID)
                 _logger.info('Received data from %s', event.peer.address)
             event = host.check_events()
-
-
-class Connection(object):
-    """Class allowing to send messages and packets
-
-    peer - connection to send packet over
-    channel - channel of connection
-
-    example:
-        client = Client()
-        # chat_msg packet is defined in packets module
-        client.net_chat_msg('Tom', 'Test message')
-        # alternative
-        client.send(packets.chat_msg('Tom', 'Test message'))
-    """
-
-    def __init__(self, peer, packet_manager=PacketManager):
-        self.peer = peer
-        self._packet_cnt = 0
-        self._packet_manager = packet_manager
-
-    def __del__(self):
-        self.peer.disconnect_now()
-
-    def __getattr__(self, name):
-        parts = name.split('_', 1)
-        if len(parts) == 2 and parts[0] == 'net' and\
-                parts[1] in self._packet_manager._packet_names:
-            p = partial(self._send, self._packet_manager.get_by_name(parts[1]))
-            p.__doc__ = "Send %s packet to remote host\n\n"\
-                "Host.net_%s: return packet_id" % \
-                (parts[1], self._packet_manager._packet_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))
-
-    def send(self, packet, *args, **kwargs):
-        """Send packet to remote host
-
-        Client.send(packet, *args, **kwargs): return int
-
-        packet - class created by PacketManager.register or packet name
-
-        args and kwargs are used to initialize packet object.
-        Returns packet id which can be used to retrieve response from
-        Pygame event queue if sending was successful.
-        """
-        if isinstance(packet, basestring):
-            packet = self._packet_manager.get_by_name(packet)
-        self._send(packet, *args, **kwargs)
-
-    def _send(self, packet, *args, **kwargs):
-        _, channel, flags = self._packet_manager.get_params(packet)
-        flags = kwargs.get('flags', flags)
-        channel = kwargs.get('channel', channel)
-        packet_id = self._packet_cnt = self._packet_cnt + 1
-        packet = packet(*args, **kwargs)
-        data = self._packet_manager.pack(packet_id, packet)
-        if self.peer.send(channel, enet.Packet(data, flags)) == 0:
-            return packet_id
-
-    def _receive(self, data, channel):
-        packet_id, packet = self._packet_manager.unpack(data)
-        _received_event(self, channel, packet, packet_id)
-        ReceiverManager.on_recive(self, channel, packet_id, packet)
-
-    def _connect(self):
-        _connected_event(self)
-        ReceiverManager.on_connect(self)
-
-    def _disconnect(self):
-        _disconnected_event(self)
-        ReceiverManager.on_disconnect(self)
-
-    def disconnect(self):
-        self.peer.disconnect()
-
-    def disconnect_later(self):
-        self.peer.disconnect_later()
-
-    @property
-    def state(self):
-        return self.peer.state
-
-    @property
-    def address(self):
-        return self.peer.address
-
-
-class ReceiverManager(object):
-    _receivers = WeakKeyDictionary()
-
-    @classmethod
-    def register(cls, obj):
-        cls._receivers[obj] = None
-
-    @classmethod
-    def on_recive(cls, connection, channel, packet_id, packet):
-        name = packet.__class__.__name__
-        for obj in cls._receivers:
-            if obj.connection == connection:
-                getattr(obj, 'net_' + name, obj.on_recive)(channel, packet_id, packet)
-
-    @classmethod
-    def on_connect(cls, connection):
-        for obj in cls._receivers:
-            if obj.connection == connection:
-                obj.on_connect()
-
-    @classmethod
-    def on_disconnect(cls, connection):
-        for obj in cls._receivers:
-            if obj.connection == connection:
-                obj.on_disconnect()
-
-
-class Receiver(object):
-    connection = None
-
-    def __init__(self, *args, **kwargs):
-        super(Receiver, self).__init__(*args, **kwargs)
-        ReceiverManager.register(self)
-
-    def on_connect(self):
-        pass
-
-    def on_disconnect(self):
-        pass
-
-    def on_recive(self, channel, packet_id, packet):
-        pass

File pygame_network/connection.py

View file
+from weakref import WeakKeyDictionary, proxy
+from functools import partial
+import enet
+from packet import PacketManager
+
+# dummy events
+def _connected_event(connection): pass
+def _disconnected_event(connection): pass
+def _received_event(connection, channel, packet, packet_id): pass
+def _response_event(connection, channel, packet, packet_id): pass
+
+STATE_ACKNOWLEDGING_CONNECT = enet.PEER_STATE_ACKNOWLEDGING_CONNECT
+STATE_ACKNOWLEDGING_DISCONNECT = enet.PEER_STATE_ACKNOWLEDGING_DISCONNECT
+STATE_CONNECTED = enet.PEER_STATE_CONNECTED
+STATE_CONNECTING = enet.PEER_STATE_CONNECTING
+STATE_CONNECTION_PENDING = enet.PEER_STATE_CONNECTION_PENDING
+STATE_CONNECTION_SUCCEEDED = enet.PEER_STATE_CONNECTION_SUCCEEDED
+STATE_DISCONNECTED = enet.PEER_STATE_DISCONNECTED
+STATE_DISCONNECTING = enet.PEER_STATE_DISCONNECTING
+STATE_DISCONNECT_LATER = enet.PEER_STATE_DISCONNECT_LATER
+STATE_ZOMBIE = enet.PEER_STATE_ZOMBIE
+
+
+class Connection(object):
+    """Class allowing to send messages and packets
+
+    peer - connection to send packet over
+    channel - channel of connection
+
+    example:
+        client = Client()
+        # chat_msg packet is defined in packets module
+        client.net_chat_msg('Tom', 'Test message')
+        # alternative
+        client.send(packets.chat_msg('Tom', 'Test message'))
+    """
+
+    def __init__(self, parent, peer, packet_manager=PacketManager):
+        self.parent = proxy(parent)
+        self.peer = peer
+        self._packet_cnt = 0
+        self._packet_manager = packet_manager
+        self._receiver = None
+
+    def __del__(self):
+        self.peer.disconnect_now()
+
+    def __getattr__(self, name):
+        parts = name.split('_', 1)
+        if len(parts) == 2 and parts[0] == 'net' and\
+                parts[1] in self._packet_manager._packet_names:
+            p = partial(self._send, self._packet_manager.get_by_name(parts[1]))
+            p.__doc__ = "Send %s packet to remote host\n\n"\
+                "Host.net_%s: return packet_id" % \
+                (parts[1], self._packet_manager._packet_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))
+
+    def send(self, packet, *args, **kwargs):
+        """Send packet to remote host
+
+        Client.send(packet, *args, **kwargs): return int
+
+        packet - class created by PacketManager.register or packet name
+
+        args and kwargs are used to initialize packet object.
+        Returns packet id which can be used to retrieve response from
+        Pygame event queue if sending was successful.
+        """
+        if isinstance(packet, basestring):
+            packet = self._packet_manager.get_by_name(packet)
+        self._send(packet, *args, **kwargs)
+
+    def _send(self, packet, *args, **kwargs):
+        _, channel, flags = self._packet_manager.get_params(packet)
+        flags = kwargs.get('flags', flags)
+        channel = kwargs.get('channel', channel)
+        packet_id = self._packet_cnt = self._packet_cnt + 1
+        packet = packet(*args, **kwargs)
+        data = self._packet_manager.pack(packet_id, packet)
+        if self.peer.send(channel, enet.Packet(data, flags)) == 0:
+            return packet_id
+
+    def _receive(self, data, channel):
+        packet_id, packet = self._packet_manager.unpack(data)
+        _received_event(self, channel, packet, packet_id)
+        if self._receiver is not None:
+            name = 'net_' + packet.__class__.__name__
+            getattr(self._receiver, name, self._receiver.on_recive)(channel, packet_id, packet)
+
+    def _connect(self):
+        _connected_event(self)
+        if self._receiver is not None:
+            self._receiver.on_connect()
+
+    def _disconnect(self):
+        _disconnected_event(self)
+        if self._receiver is not None:
+            self._receiver.on_disconnect()
+
+    def disconnect(self):
+        self.peer.disconnect()
+
+    def disconnect_later(self):
+        self.peer.disconnect_later()
+
+    @property
+    def state(self):
+        return self.peer.state
+
+    @property
+    def address(self):
+        return self.peer.address
+
+
+class Receiver(object):
+    def __init__(self, connection, *args, **kwargs):
+        super(Receiver, self).__init__(*args, **kwargs)
+        connection._receiver = proxy(self)
+        self.connection = connection
+
+    def on_connect(self):
+        pass
+
+    def on_disconnect(self):
+        pass
+
+    def on_recive(self, channel, packet_id, packet):
+        pass

File pygame_network/event.py

View file
 import pygame
 from pygame.event import Event
 from pygame.locals import USEREVENT
-import client
+import connection
 
 NETWORK = USEREVENT + 1
 NET_CONNECTED = 0
         #'connection': proxy(connection)
         'connection': connection
     }))
-client._connected_event = _connected_event
+connection._connected_event = _connected_event
 
 
 def _disconnected_event(connection):
         #'connection': proxy(connection)
         'connection': connection
     }))
-client._disconnected_event = _disconnected_event
+connection._disconnected_event = _disconnected_event
 
 
 def _received_event(connection, channel, packet, packet_id):
         'p_id': packet_id,
         'p_type': packet.__class__
     }))
-client._received_event = _received_event
+connection._received_event = _received_event
 
 
 def _response_event(connection, channel, packet, packet_id):
         'p_id': packet_id,
         'p_type': packet.__class__
     }))
-client._response_event = _response_event
+connection._response_event = _response_event

File pygame_network/packet.py

View file
     _packet_params = WeakKeyDictionary()  # mapping packet -> type_id, send par
     _type_id_cnt = 0
     _frozen = False
+    _hash = None
 
     def __init__(self):
         # override class variables with instance variables
         self._packet_params = cls._packet_params.copy()
         self._type_id_cnt = cls._type_id_cnt
         self._frozen = False
+        self._hash = None
 
     @classmethod
     def register(cls, name, field_names, channel=0, flags=enet.PACKET_FLAG_RELIABLE):
     @classmethod
     def get_hash(cls):
         if cls._frozen:
-            ids = cls._packet_types.keys()
-            ids.sort()
-            l = list()
-            for i in ids:
-                p = cls._packet_types[i]
-                l.append((i, p.__name__, p._fields))
-            return hash(tuple(l)) & 0xffffffff
-            # should be the same on 32 & 64 platforms
+            if cls._hash is None:
+                ids = cls._packet_types.keys()
+                ids.sort()
+                l = list()
+                for i in ids:
+                    p = cls._packet_types[i]
+                    l.append((i, p.__name__, p._fields))
+                # should be the same on 32 & 64 platforms
+                cls._hash = hash(tuple(l)) & 0xffffffff
+            return cls._hash
         else:
             _logger.warning('Attempt to get hash of not frozen PacketManager')
 
 
-connect_request = PacketManager.register('connect_request', (
-    'packets_hash',
-))
 update_remoteobject = PacketManager.register('update_remoteobject', (
     'type_id',
     'obj_id',

File pygame_network/server.py

View file
+import logging
+import enet
+from packet import PacketManager
+from connection import Connection
+
+_logger = logging.getLogger(__name__)
+
+
+class Server(object):
+    packet_manager = PacketManager
+    receiver = None
+
+    def __init__(self, address, port, connections_limit=4, channel_limit=0, in_bandwidth=0, out_bandwidth=0):
+        address = enet.Address(address, port)
+        self.host = enet.Host(address, connections_limit, channel_limit, in_bandwidth, out_bandwidth)
+        self._peers = {}
+        self._peer_cnt = 0
+        self.packet_manager._frozen = True
+
+    def step(self, timeout=0):
+        if len(self._peers) == 0:
+            return
+        host = self.host
+        event = host.service(timeout)
+        while event is not None:
+            if event.type == enet.EVENT_TYPE_CONNECT:
+                if event.data == self.packet_manager.get_hash():
+                    peer_id = self._peer_cnt = self._peer_cnt + 1
+                    peer_id = str(peer_id)
+                    event.peer.data = peer_id
+                    connection = Connection(self, event.peer, self.packet_manager)
+                    self._peers[peer_id] = connection
+                    # TODO: add receiver
+                    connection._connect()
+                    _logger.info('Connection with %s accepted', event.peer.address)
+                else:
+                    event.peer.data = 'N'
+                    event.peer.disconnect()
+                    _logger.warning('Connection with %s refused, incompatible packets set', event.peer.address)
+            elif event.type == enet.EVENT_TYPE_DISCONNECT:
+                if event.peer.data != 'N':
+                    self._peers[event.peer.data]._disconnect()
+                    del self._peers[event.peer.data]
+                _logger.info('Disconnected from %s', event.peer.address)
+            elif event.type == enet.EVENT_TYPE_RECEIVE:
+                self._peers[event.peer.data]._receive(event.packet.data, event.channelID)
+                _logger.info('Received data from %s', event.peer.address)
+            event = host.check_events()

File test_client_1.py

View file
     client.step()
     if counter < MSG_NUMBER and connection.state == enet.PEER_STATE_CONNECTED:
         msg = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz', 10))
-        print("%s: out: %r" % (connection.peer.address, msg))
+        print("%s: out: %r" % (connection.address, msg))
         connection.net_echo(msg)
         counter += 1

File test_client_2.py

View file
 logging.basicConfig(level=logging.DEBUG)
 
 
-class EchoReceiver(pygame_network.client.Receiver):
+class EchoReceiver(pygame_network.connection.Receiver):
     def __init__(self, connection):
-        super(EchoReceiver, self).__init__()
-        self.connection = connection
+        super(EchoReceiver, self).__init__(connection)
         self.connected = None
         self.counter = 10
 
     def step(self):
         if self.counter > 0 and self.connected == True:
             msg = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz', 10))
-            print("%s: out: %r" % (self.connection.peer.address, msg))
+            print("%s: out: %r" % (self.connection.address, msg))
             self.connection.net_echo(msg)
             self.counter -= 1
 

File test_client_3.py

View file
     run = True
     limit = True
     packets = {}
+
     while run:
         events = pygame.event.get()
         for e in events:
             if e.type == KEYDOWN:
                 if e.key == K_SPACE:
                     if connection is not None:
-                        if connection.state == pygame_network.client.STATE_CONNECTED:
+                        if connection.state == pygame_network.connection.STATE_CONNECTED:
                             connection.disconnect_later()
                             connection_status(screen, (140, 38), False)
                     else:
                         packet_status(screen, (110, 62), packets)
             if e.type == QUIT or e.type == KEYDOWN and e.key == K_ESCAPE:
                 run = False
-        if len(packets) < 10 and connection is not None and connection.state == pygame_network.client.STATE_CONNECTED:
+        if len(packets) < 10 and connection is not None and connection.state == pygame_network.connection.STATE_CONNECTED:
             msg = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz', 10))
             p_id = connection.net_echo(msg)
             packets[p_id] = [msg, None]