def test_peek_one_item_one_queue(self):
     value = 5
     queue = FifoQueue()
     queue.enqueue(value)
     peeked_value = queue.peek()
     self.assertEqual(1, queue.size)
     self.assertEqual(5, peeked_value)
Exemplo n.º 2
0
    def __init__(self, port, bridge_port=None,
                 queue_in_size=DEFAULT_IN_SIZE,
                 queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on. bridge_port is used
        for briding to an existing serial-forward (such as that
        provided by sim-sf).

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specified that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        # maintained with callbacks from InjectSock, etc.
        self.map = {}
        self.upstream = []
        self.bridge_source = None

        # of (client, packet)
        # where client is the source, or None if from the proxy source
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
#        if bridge_port is not None:
#            self._init_bridge(("127.0.0.1", bridge_port))

        self.thread = None
 def test_dequeue_one_item_on_queue(self):
     value = 5
     queue = FifoQueue()
     queue.enqueue(value)
     removed_item = queue.dequeue()
     self.assertEqual(0, queue.size)
     self.assertEqual(5, removed_item)
 def test_enqueue_two_items(self):
     value1, value2 = 5, 10
     queue = FifoQueue()
     queue.enqueue(value1)
     queue.enqueue(value2)
     self.assertEqual(2, queue.size)
     self.assertEqual(5, queue.ll.head.value)
     self.assertEqual(10, queue.ll.tail.value)
Exemplo n.º 5
0
    def trade_ledger(self):
        instrument_queues = {}
        order_pairs = {}
        for o in self.orders:
            if o.instrument not in instrument_queues:
                instrument_queues[o.instrument] = (FifoQueue(), FifoQueue()
                                                   )  # (longs, shorts)
            longs, shorts = instrument_queues[o.instrument]
            if o.quantity < 0:
                shorts.put(o)
            else:
                longs.put(o)

        # match up the longs and shorts
        for inst in instrument_queues.keys():
            longs, shorts = instrument_queues[inst]
            open_close_order_pairs = []
            while not longs.empty() and not shorts.empty():
                long, short = longs.get(), shorts.get()
                open_order, close_order = (long, short) if long.execution_end_time() < short.execution_end_time() \
                    else (short, long)
                open_close_order_pairs.append((open_order, close_order))

            # handle unmatched longs or shorts i.e. positions currently open
            while not longs.empty() or not shorts.empty():
                unclosed_open_order = longs.get(
                ) if not longs.empty() else shorts.get()
                open_close_order_pairs.append((unclosed_open_order, None))
            order_pairs[inst] = open_close_order_pairs

        trade_df = []
        for inst in order_pairs.keys():
            for open_order, close_order in [(o, c)
                                            for o, c in order_pairs[inst]]:
                if close_order:
                    end_dt = close_order.execution_end_time()
                    end_value = close_order.executed_price
                    status = 'closed'
                else:
                    end_dt = None
                    end_value = None
                    status = 'open'
                start_dt, open_value = open_order.execution_end_time(
                ), open_order.executed_price
                long_or_short = np.sign(open_order.quantity)
                trade_df.append(
                    (inst, start_dt, end_dt, open_value, end_value,
                     long_or_short, status, (end_value - open_value) *
                     long_or_short if status == 'closed' else None))
        return pd.DataFrame(trade_df,
                            columns=[
                                'Instrument', 'Open', 'Close', 'Open Value',
                                'Close Value', 'Long Short', 'Status',
                                'Trade PnL'
                            ])
Exemplo n.º 6
0
    def __init__(self,
                 port=None,
                 queue_in_size=DEFAULT_IN_SIZE,
                 queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on.

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specifies that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        self.connection_map = {}  # connection => connection
        self.clients = []  # connections that want messages
        self.server_map = ServerMap()

        self.trigger = None
        self.trigger_magic = None  # must be matched to accept trigger

        # of (client, message, handler)
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        # PST: could possibly use UNIX sockets when not windows
        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
        self.thread = None

        # setup basic handlers
        def message_rejected(client, message):
            print "MessageRejected(Dummy Handler) {%s}" % message

        def mapped_name(client, message):
            print "MappedName: %s -> %d" % (message.name, message.id)
            client.map.add_resolution(message.name, message.id)

        self.server_map.set_handler(MessageRejected, message_rejected)
        self.server_map.set_handler(MappedName, mapped_name)
 def test_peek_multiple_items_on_queue(self):
     value1, value2, value3 = 5, 10, 15
     queue = FifoQueue()
     queue.enqueue(value1)
     queue.enqueue(value2)
     queue.enqueue(value3)
     peeked_item = queue.peek()
     self.assertEqual(3, queue.size)
     self.assertEqual(5, peeked_item)
Exemplo n.º 8
0
    def breadth_first_search(self):
        visited_nodes = []
        # Use a queue to keep track of all the nodes you need to visit
        node_queue = FifoQueue()

        # Set starting point as no root node
        current_node = self.edges[0].node_from
        visited_nodes.append(current_node)

        while current_node:
            new_edge = self._return_new_edge(current_node, visited_nodes)
            if new_edge:
                visited_nodes.append(new_edge.node_to)
                node_queue.enqueue(new_edge.node_to)
            else:
                current_node = node_queue.dequeue()

        visited_node_values = [node.value for node in visited_nodes]

        return visited_node_values
 def test_dequeue_multiple_items_on_queue(self):
     value1, value2, value3 = 5, 10, 15
     queue = FifoQueue()
     queue.enqueue(value1)
     queue.enqueue(value2)
     queue.enqueue(value3)
     removed_item1 = queue.dequeue()
     removed_item2 = queue.dequeue()
     removed_item3 = queue.dequeue()
     self.assertEqual(0, queue.size)
     self.assertEqual(5, removed_item1)
     self.assertEqual(10, removed_item2)
     self.assertEqual(15, removed_item3)
Exemplo n.º 10
0
    def __init__(self, port=None, queue_in_size=DEFAULT_IN_SIZE, queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on.

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specifies that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        self.connection_map = {}  # connection => connection
        self.clients = []  # connections that want messages
        self.server_map = ServerMap()

        self.trigger = None
        self.trigger_magic = None  # must be matched to accept trigger

        # of (client, message, handler)
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        # PST: could possibly use UNIX sockets when not windows
        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
        self.thread = None

        # setup basic handlers
        def message_rejected(client, message):
            print "MessageRejected(Dummy Handler) {%s}" % message

        def mapped_name(client, message):
            print "MappedName: %s -> %d" % (message.name, message.id)
            client.map.add_resolution(message.name, message.id)

        self.server_map.set_handler(MessageRejected, message_rejected)
        self.server_map.set_handler(MappedName, mapped_name)
Exemplo n.º 11
0
 def test_enqueue_three_items(self):
     value1, value2, value3 = 5, 10, 15
     queue = FifoQueue()
     queue.enqueue(value1)
     queue.enqueue(value2)
     queue.enqueue(value3)
     self.assertEqual(3, queue.size)
     self.assertEqual(5, queue.ll.head.value)
     self.assertEqual(15, queue.ll.tail.value)
Exemplo n.º 12
0
class Scheduler:
    def __init__(self):
        self.fifo_queue = FifoQueue()
        self.priority_queue = PriorityQueue()

    # enfileira processo se a fila nao estiver lotada (1000)
    def queueProcess(self, process):
        if (process.priority == 0):
            result = self.fifo_queue.push(process)
        else:
            result = self.priority_queue.push(process)
        return result

    # escalona o processo com maior prioridade para a CPU
    def scheduleProcess(self):
        if (not self.fifo_queue.is_empty()):
            process = self.fifo_queue.pop()
        else:
            process = self.priority_queue.pop()
        return process

    def preemptProcess(self, process, globalTime):
        if (process.priority > 0):  #se o processo eh de usuário
            if ((not self.fifo_queue.is_empty())
                    and (globalTime >= self.fifo_queue.pick().timeOfArrival)
                ):  # se chegou um proc de tempo real
                if (process.priority > 1):  # se a prioridade ja nao eh máxima
                    process.priority -= 1  # aumenta a prioridade
                self.priority_queue.push(
                    process)  # volta pra fila com sua respectiva prioridade
                process = self.fifo_queue.pop(
                )  # pega o processo de tempo real prioritario
            elif ((not self.priority_queue.is_empty())
                  and (globalTime >= self.priority_queue.pick().timeOfArrival)
                  and
                  (process.priority > self.priority_queue.pick().priority)):
                if (process.priority > 1):  # se a prioridade ja nao eh máxima
                    process.priority -= 1  # aumenta a prioridade
                self.priority_queue.push(
                    process)  # volta pra fila com sua respectiva prioridade
                process = self.priority_queue.pop(
                )  # pega o processo de usuario prioritario
        return process
Exemplo n.º 13
0
class Inject(asyncore.dispatcher):
    """
    Select-dispatch to move packets across sf-compatible streams.
    """

    log = logging.getLogger(__name__)

    def __init__(self, port, bridge_port=None,
                 queue_in_size=DEFAULT_IN_SIZE,
                 queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on. bridge_port is used
        for briding to an existing serial-forward (such as that
        provided by sim-sf).

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specified that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        # maintained with callbacks from InjectSock, etc.
        self.map = {}
        self.upstream = []
        self.bridge_source = None

        # of (client, packet)
        # where client is the source, or None if from the proxy source
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
#        if bridge_port is not None:
#            self._init_bridge(("127.0.0.1", bridge_port))

        self.thread = None


    def _init_server(self, server_addr):
        """
        Setup server socket.
        """
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.bind(server_addr)
        self.listen(CONNECTION_QUEUE_SIZE)
        self.map[self] = self


    def _init_bridge(self, bridge_addr):
        """
        Setup bridge socket.
        """
        source = InjectDownstream(sf_inject=self)
        source.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        source.connect(bridge_addr)
        # sim-sf will block until it receives the serial-forward
        # version and, since it (sf.process()) does not perform a GIL
        # release, this thread will never resume. This will ensure
        # that the sim-sf serial forwarder doesn't hang (here) by
        # forcing data onto the wire.
        source.send(SFCLIENT_MAGIC)
        self.bridge_source = source


    def _init_trigger(self, server_addr):
        """
        Setup trigger socket.

        The trigger is used to interrupt the asyncore loop and force
        examination of the message queue.
        """
        trigger = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        trigger.connect(server_addr)
        trigger.shutdown(socket.SHUT_RD)
        # How the handle_accept identifies this as a trigger. Very
        # important to prevent blocking with handle_accept+sync_read.
        trigger.send(TRIGGER_MAGIC)
        self.trigger = trigger


    def packet_read(self, conn, packet):
        """
        Read in a packet and dispatch -- asyncore callback.
        """
        if conn == self.bridge_source:
            # TODO: fix (huh?)
            self.send_packet_upstream(packet)
        else:
            self.q_in.fifo_put((conn, packet))
            # foward to motes (should be filtered)
            if self.bridge_source:
                self.bridge_source.write_packet(packet)

            
    def handle_accept(self):
        """
        Process new connections (sf-client or trigger) -- asyncore
        callback.
        """
        client, addr = self.accept()
        # Determine who connected and if they look valid. This is done
        # first to siphon off the 'trigger' handler. It also blocks.
        magic = sync_read(client, 2)

        if is_trigger(magic):
            InjectTrigger(sf_inject=self, socket=client)

        elif is_sfclient(magic):
            InjectUpstream(sf_inject=self, socket=client)
            client.send(SFCLIENT_MAGIC)

        else:
            warn(InvalidVersionWarning())
            client.close()


    def attach_conn(self, conn):
        """
        Attach a connections.
        """
        if not conn in self.map:
            if isinstance(conn, InjectUpstream):
                self.upstream.append(conn)
            self.map[conn] = conn


    def detach_conn(self, conn):
        """
        Remove a connection.
        """
        if conn in self.upstream:
            self.upstream.remove(conn)
        del(self.map[conn])

    #
    # Internal
    #

    def _message_to_packet(self, msg, dest=0xFFFF, group=0xAA):
        """
        Wraps a message in an AM (Serial) packet.
        """
        payload = msg.dataGet()
        am_type = msg.amType()
        pkt = SerialPacket(None)
        pkt.set_header_dest(dest)
        pkt.set_header_group(group)
        pkt.set_header_type(int(am_type))
        pkt.set_header_length(len(payload))
        # first byte, always 0, identifies as AM packet
        return chr(0) + pkt.dataGet()[0:pkt.offset_data(0)] + payload


    def _send_queued_packets(self):
        """
        Flush all queued out packets onto the wire.
        """
        while not self.q_out.empty():
            (client, message) = self.q_out.get()
            serial_packet = self._message_to_packet(message)
            if client is not None:
                # send to specific connection
                client.write_packet(serial_packet)
            else:
                # send to all upstream connections
                for conn in self.upstream:
                    conn.write_packet(serial_packet)


    def _thread_pump(self):
        """
        Pump that runs inside the dispatch thread. This never normally
        terminates.
        """
        self.log.debug("Pump started")
        while True:
            asyncore.loop(SELECT_IDLE_SECONDS, False, self.map, 1)
            self._send_queued_packets()


    #
    # Public
    #

    def read_packets(self):
        """
        Returns a list of (client, packet) for all incoming packets.

        The packets are removed from the incoming queue and have the
        AM (Serial) header stripped.
        """
        read = []
        while not self.q_in.empty():
            (client, data) = self.q_in.get()
            read.append((client, data[8:]))
        return read


    def inject(self, message, target=None):
        """
        Inject a message.

        The message is sent to target. If target is None the message
        is sent to everyone. This is safe to call outside the event
        thread.
        """
        self.q_out.fifo_put((target, message))
        self.trigger.send("t")


    def start(self):
        """
        Spawn a thread and start running the injection bridge.

        Returns self.
        """
        def launcher():
            "Terminate on pump exception"
            try:
                self._thread_pump()
            except:
                traceback.print_exc()
                print >>sys.stderr, "!!! INJECTOR TERMINATED !!!"
                os._exit(1)

        self.thread = thread.start_new_thread(launcher, ())
        return self
Exemplo n.º 14
0
 def __init__(self):
     self.fifo_queue = FifoQueue()
     self.priority_queue = PriorityQueue()
Exemplo n.º 15
0
class ProtoServer(asyncore.dispatcher):
    """
    Server for ProtoMap.
    """

    log = logging.getLogger(__name__)

    def __init__(self, port=None, queue_in_size=DEFAULT_IN_SIZE, queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on.

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specifies that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        self.connection_map = {}  # connection => connection
        self.clients = []  # connections that want messages
        self.server_map = ServerMap()

        self.trigger = None
        self.trigger_magic = None  # must be matched to accept trigger

        # of (client, message, handler)
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        # PST: could possibly use UNIX sockets when not windows
        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
        self.thread = None

        # setup basic handlers
        def message_rejected(client, message):
            print "MessageRejected(Dummy Handler) {%s}" % message

        def mapped_name(client, message):
            print "MappedName: %s -> %d" % (message.name, message.id)
            client.map.add_resolution(message.name, message.id)

        self.server_map.set_handler(MessageRejected, message_rejected)
        self.server_map.set_handler(MappedName, mapped_name)

    def _init_server(self, server_addr):
        """
        Setup server socket.
        """
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.bind(server_addr)
        self.listen(CONNECTION_QUEUE_SIZE)
        self.connection_map[self] = self

    def _init_trigger(self, server_addr):
        """
        Setup trigger socket.

        The trigger is used to interrupt the asyncore loop and force
        examination of the outbound message queue. (This is because
        ``threading'' in Python 2.6 and before is absolutely soupy.)
        """
        assert not self.trigger

        trigger = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        trigger.connect(server_addr)
        trigger.shutdown(socket.SHUT_RD)
        # to identify as trigger
        self.trigger_magic = "TRIGGER:%08x" % random.randint(0, 0xFFFFFFFF)
        trigger.send(self.trigger_magic)
        self.trigger = trigger

    def packet_read(self, conn, raw_packet):
        """
        Read in a packet and dispatch -- asyncore callback.
        """
        packet = Packet.decode(raw_packet)
        print "packet in with protocol"

        if Packet.is_named(packet.protocol):
            # protocol is named, resolve id first
            name = packet.protocol
            id = self.server_map.resolve_id(name)

            if id:
                named = MappedName()
                named.name = name
                named.id = id
                msg = Message(0, named)
                self.q_out.fifo_put((conn, msg))
            else:
                print "unmapped name: " + str(name)
                rejected = MessageRejected()
                rejected.id = 0
                rejected.reason = rejected.UNMAPPED_NAME
                rejected.message = "Unmapped name: '%s'" % name
                msg = Message(0, rejected)
                self.q_out.fifo_put((conn, msg))
                # stop processing
                return

        else:
            # just take id
            id = packet.protocol

        # this seems slightly silly in the case where the message was
        # a named message (it shouldn't hurt though)
        name = self.server_map.resolve_name(id)

        if not name:
            # if the reverse name lookup fails
            print "unmapped id: " + str(id)
            rejected = MessageRejected()
            rejected.id = 0
            rejected.reason = rejected.UNMAPPED_ID
            rejected.message = "Unmapped ID: %d" % id
            msg = Message(0, rejected)
            self.q_out.fifo_put((conn, msg))
            # stop processing
            return

        protobuf_class = self.server_map.resolve_protobuffer(name)
        assert protobuf_class

        protobuf = protobuf_class()
        protobuf.ParseFromString(packet.payload)
        message = Message(packet.track_id, protobuf, name=name)
        print "have protobuf: {" + str(protobuf) + "}"

        self.q_in.fifo_put((conn, message))

    def handle_accept(self):
        """
        Process new connections (asyncore callback).
        """
        client, addr = self.accept()
        holding = Holding(PROTOMAP_MAGIC, self, client, self.trigger_magic)
        self.attach_connection(holding)

    def attach_connection(self, new_conn):
        """
        Attach a new connection.
        """
        self.alter_connection(None, new_conn)

    def alter_connection(self, old_conn, new_conn):
        """
        Alter an existing connection handler; if new_conn is None the
        connection is closed. The old_conn, if any, is removed.
        """
        if old_conn and new_conn:
            # prevent socket-swapping
            assert old_conn.socket is new_conn.socket

        # remove existing (if any)
        if old_conn in self.connection_map:
            del self.connection_map[old_conn]
            if old_conn in self.clients:
                self.clients.remove(old_conn)

        # attach new (if any)
        if new_conn:
            self.connection_map[new_conn] = new_conn
            if isinstance(new_conn, ProtoClient):
                self.clients.append(new_conn)
        elif old_conn:
            # no new_conn, but old_conn -- close connection
            old_conn.close()

    def connection_closed(self, conn):
        """
        Remove a connection.
        """
        self.log.debug("Connection closed")
        if conn in self.clients:
            self.clients.remove(conn)

        del self.connection_map[conn]

    #
    # Internal
    #

    # PST- can avoid this and keep asyncore loop tighter?
    # PST- could possibly send packet to closed connection
    def _send_queued_packets(self):
        """
        Flush all queued out packets onto the wire.
        """

        def send(client, message):
            protocol = client.map.resolve_id(message.name) or message.name
            packet = message.encode(protocol)
            print "writing packet " + str(protocol)
            client.write_packet(packet)

        while not self.q_out.empty():
            client, message = self.q_out.get()
            if client:
                send(client, message)
            else:
                for client in self.clients:
                    send(client, message)

    def _thread_pump(self):
        """
        Pump that runs inside the dispatch thread. This never normally
        terminates.
        """
        self.log.debug("Pump started")
        while True:
            asyncore.loop(SELECT_IDLE_SECONDS, False, self.connection_map, 1)
            self._send_queued_packets()

    #
    # Public
    #

    def process_messages(self):
        """
        Invoke handlers for messages in the incoming queue.

        This method should be invoked in the thread where the handlers
        are to be executed.
        """
        while not self.q_in.empty():
            client, message = self.q_in.get()
            handler = self.server_map.resolve_handler(message.name)
            handler(client, message)

    def write(self, message, target=None):
        """
        Write a message.

        The message is sent to target. If target is None the message
        is sent to all connected clients. This method is safe to call
        outside the event thread.
        """
        self.q_out.fifo_put((target, message))
        self.trigger.send("t")

    def start(self):
        """
        Spawn a thread and start running the server.

        Returns self.
        """

        def launcher():
            "Terminate on pump exception"
            try:
                self._thread_pump()
            except:
                traceback.print_exc()
                print >> sys.stderr, "!!! ProtoServer Terminated !!!"
                os._exit(1)

        self.thread = thread.start_new_thread(launcher, ())
        return self
Exemplo n.º 16
0
 def test_peek_no_items_on_queue(self):
     queue = FifoQueue()
     peeked_value = queue.peek()
     self.assertEqual(0, queue.size)
     self.assertEqual(None, peeked_value)
Exemplo n.º 17
0
 def test_queue_create(self):
     queue = FifoQueue()
     self.assertEqual(0, queue.size)
Exemplo n.º 18
0
 def test_enqueue_one_item(self):
     value = 5
     queue = FifoQueue()
     queue.enqueue(value)
     self.assertEqual(1, queue.size)
     self.assertEqual(5, queue.ll.head.value)
Exemplo n.º 19
0
 def test_dequeue_no_items_on_queue(self):
     queue = FifoQueue()
     removed_item = queue.dequeue()
     self.assertEqual(0, queue.size)
     self.assertEqual(None, removed_item)
Exemplo n.º 20
0
class ProtoServer(asyncore.dispatcher):
    """
    Server for ProtoMap.
    """

    log = logging.getLogger(__name__)

    def __init__(self,
                 port=None,
                 queue_in_size=DEFAULT_IN_SIZE,
                 queue_out_size=DEFAULT_OUT_SIZE):
        """
        Initialize.

        port specifies the IP port to listen on.

        queue_in_size and queue_out_size limit the maximum number of
        queued elements. A size of zero specifies that there is no
        limit. When the queues fill up a warning is generated and the
        oldest element is dropped.
        """
        asyncore.dispatcher.__init__(self)

        self.connection_map = {}  # connection => connection
        self.clients = []  # connections that want messages
        self.server_map = ServerMap()

        self.trigger = None
        self.trigger_magic = None  # must be matched to accept trigger

        # of (client, message, handler)
        self.q_in = FifoQueue(queue_in_size)
        # of (target, packet)
        # where target is a client to send to, or None to send to all
        self.q_out = FifoQueue(queue_out_size)

        # PST: could possibly use UNIX sockets when not windows
        self._init_server(("", port))
        self._init_trigger(("127.0.0.1", port))
        self.thread = None

        # setup basic handlers
        def message_rejected(client, message):
            print "MessageRejected(Dummy Handler) {%s}" % message

        def mapped_name(client, message):
            print "MappedName: %s -> %d" % (message.name, message.id)
            client.map.add_resolution(message.name, message.id)

        self.server_map.set_handler(MessageRejected, message_rejected)
        self.server_map.set_handler(MappedName, mapped_name)

    def _init_server(self, server_addr):
        """
        Setup server socket.
        """
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.bind(server_addr)
        self.listen(CONNECTION_QUEUE_SIZE)
        self.connection_map[self] = self

    def _init_trigger(self, server_addr):
        """
        Setup trigger socket.

        The trigger is used to interrupt the asyncore loop and force
        examination of the outbound message queue. (This is because
        ``threading'' in Python 2.6 and before is absolutely soupy.)
        """
        assert not self.trigger

        trigger = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        trigger.connect(server_addr)
        trigger.shutdown(socket.SHUT_RD)
        # to identify as trigger
        self.trigger_magic = "TRIGGER:%08x" % random.randint(0, 0xffffffff)
        trigger.send(self.trigger_magic)
        self.trigger = trigger

    def packet_read(self, conn, raw_packet):
        """
        Read in a packet and dispatch -- asyncore callback.
        """
        packet = Packet.decode(raw_packet)
        print "packet in with protocol"

        if Packet.is_named(packet.protocol):
            # protocol is named, resolve id first
            name = packet.protocol
            id = self.server_map.resolve_id(name)

            if id:
                named = MappedName()
                named.name = name
                named.id = id
                msg = Message(0, named)
                self.q_out.fifo_put((conn, msg))
            else:
                print "unmapped name: " + str(name)
                rejected = MessageRejected()
                rejected.id = 0
                rejected.reason = rejected.UNMAPPED_NAME
                rejected.message = "Unmapped name: '%s'" % name
                msg = Message(0, rejected)
                self.q_out.fifo_put((conn, msg))
                # stop processing
                return

        else:
            # just take id
            id = packet.protocol

        # this seems slightly silly in the case where the message was
        # a named message (it shouldn't hurt though)
        name = self.server_map.resolve_name(id)

        if not name:
            # if the reverse name lookup fails
            print "unmapped id: " + str(id)
            rejected = MessageRejected()
            rejected.id = 0
            rejected.reason = rejected.UNMAPPED_ID
            rejected.message = "Unmapped ID: %d" % id
            msg = Message(0, rejected)
            self.q_out.fifo_put((conn, msg))
            # stop processing
            return

        protobuf_class = self.server_map.resolve_protobuffer(name)
        assert protobuf_class

        protobuf = protobuf_class()
        protobuf.ParseFromString(packet.payload)
        message = Message(packet.track_id, protobuf, name=name)
        print "have protobuf: {" + str(protobuf) + "}"

        self.q_in.fifo_put((conn, message))

    def handle_accept(self):
        """
        Process new connections (asyncore callback).
        """
        client, addr = self.accept()
        holding = Holding(PROTOMAP_MAGIC, self, client, self.trigger_magic)
        self.attach_connection(holding)

    def attach_connection(self, new_conn):
        """
        Attach a new connection.
        """
        self.alter_connection(None, new_conn)

    def alter_connection(self, old_conn, new_conn):
        """
        Alter an existing connection handler; if new_conn is None the
        connection is closed. The old_conn, if any, is removed.
        """
        if old_conn and new_conn:
            # prevent socket-swapping
            assert old_conn.socket is new_conn.socket

        # remove existing (if any)
        if old_conn in self.connection_map:
            del self.connection_map[old_conn]
            if old_conn in self.clients:
                self.clients.remove(old_conn)

        # attach new (if any)
        if new_conn:
            self.connection_map[new_conn] = new_conn
            if isinstance(new_conn, ProtoClient):
                self.clients.append(new_conn)
        elif old_conn:
            # no new_conn, but old_conn -- close connection
            old_conn.close()

    def connection_closed(self, conn):
        """
        Remove a connection.
        """
        self.log.debug("Connection closed")
        if conn in self.clients:
            self.clients.remove(conn)

        del self.connection_map[conn]

    #
    # Internal
    #

    # PST- can avoid this and keep asyncore loop tighter?
    # PST- could possibly send packet to closed connection
    def _send_queued_packets(self):
        """
        Flush all queued out packets onto the wire.
        """
        def send(client, message):
            protocol = client.map.resolve_id(message.name) or message.name
            packet = message.encode(protocol)
            print "writing packet " + str(protocol)
            client.write_packet(packet)

        while not self.q_out.empty():
            client, message = self.q_out.get()
            if client:
                send(client, message)
            else:
                for client in self.clients:
                    send(client, message)

    def _thread_pump(self):
        """
        Pump that runs inside the dispatch thread. This never normally
        terminates.
        """
        self.log.debug("Pump started")
        while True:
            asyncore.loop(SELECT_IDLE_SECONDS, False, self.connection_map, 1)
            self._send_queued_packets()

    #
    # Public
    #

    def process_messages(self):
        """
        Invoke handlers for messages in the incoming queue.

        This method should be invoked in the thread where the handlers
        are to be executed.
        """
        while not self.q_in.empty():
            client, message = self.q_in.get()
            handler = self.server_map.resolve_handler(message.name)
            handler(client, message)

    def write(self, message, target=None):
        """
        Write a message.

        The message is sent to target. If target is None the message
        is sent to all connected clients. This method is safe to call
        outside the event thread.
        """
        self.q_out.fifo_put((target, message))
        self.trigger.send('t')

    def start(self):
        """
        Spawn a thread and start running the server.

        Returns self.
        """
        def launcher():
            "Terminate on pump exception"
            try:
                self._thread_pump()
            except:
                traceback.print_exc()
                print >> sys.stderr, "!!! ProtoServer Terminated !!!"
                os._exit(1)

        self.thread = thread.start_new_thread(launcher, ())
        return self