From d400883be1791f7752aa90963b393e3f145c1624 Mon Sep 17 00:00:00 2001 From: Jaculabilis Date: Sat, 23 Sep 2017 21:06:47 -0500 Subject: [PATCH] Add rudimentary networking abilities --- server.py | 32 ------------------- src/Fishtank.py | 43 ++++++++++++++++++++++++++ src/__init__.py | 0 src/entity/Entity.py | 25 +++++++++++++++ src/entity/Tube.py | 22 ++++++++++++++ src/entity/__init__.py | 0 src/entity/dummy/DebugJumper.py | 41 +++++++++++++++++++++++++ src/entity/dummy/DebugWaiter.py | 19 ++++++++++++ src/entity/dummy/__init__.py | 0 src/network/NetworkGate.py | 19 ++++++++++++ src/network/__init__.py | 0 src/server.py | 54 +++++++++++++++++++++++++++++++++ 12 files changed, 223 insertions(+), 32 deletions(-) delete mode 100644 server.py create mode 100644 src/Fishtank.py create mode 100644 src/__init__.py create mode 100644 src/entity/Entity.py create mode 100644 src/entity/Tube.py create mode 100644 src/entity/__init__.py create mode 100644 src/entity/dummy/DebugJumper.py create mode 100644 src/entity/dummy/DebugWaiter.py create mode 100644 src/entity/dummy/__init__.py create mode 100644 src/network/NetworkGate.py create mode 100644 src/network/__init__.py create mode 100644 src/server.py diff --git a/server.py b/server.py deleted file mode 100644 index d98c929..0000000 --- a/server.py +++ /dev/null @@ -1,32 +0,0 @@ -import sys -import zmq -import time - -if sys.argv[1] == "send": - PORT = int(sys.argv[2]) - DEST = int(sys.argv[3]) - sys.stdout.write("Using port {}\n".format(PORT)) - sys.stdout.write("Connecting to port {}\n".format(DEST)) - - context = zmq.Context() - socket = context.socket(zmq.REQ) - socket.connect("tcp://localhost:{}".format(DEST)) - - while True: - socket.send(b"Gentlemen.") - message = socket.recv() - sys.stdout.write("Response: {}\n".format(message)) - -if sys.argv[1] == "recv": - PORT = int(sys.argv[2]) - sys.stdout.write("Using port {}\n".format(PORT)) - - context = zmq.Context() - socket = context.socket(zmq.REP) - socket.bind("tcp://*:{}".format(PORT)) - - while True: - message = socket.recv() - sys.stdout.write("Received message: {}\n".format(message)) - time.sleep(1) - socket.send(b"Received") \ No newline at end of file diff --git a/src/Fishtank.py b/src/Fishtank.py new file mode 100644 index 0000000..7ca2a5c --- /dev/null +++ b/src/Fishtank.py @@ -0,0 +1,43 @@ +import sys +import time +import json + +class Fishtank(): + def __init__(self, recv_queue): + self._entities = [] + self._to_remove = [] + self._recv_queue = recv_queue + + def run(self): + while True: + # Delete flagged entities + if self._to_remove: + for entity in self._to_remove: + self._entities.remove(entity) + self._to_remove = [] + # Update and draw + for entity in self._entities: + entity.update() + for entity in self._entities: + entity.draw() + #time.sleep(1) + # Intake queue + if not self._recv_queue.empty(): + serial = self._recv_queue.get(False) + sys.stdout.write("Fishtank dequeued a {}\n".format(serial["class"])) + mod = __import__(serial["module"], fromlist=[serial["class"]]) + klass = getattr(mod, serial["class"]) + e = klass.deserialize(serial) + self.add_entity(e) + + def add_entity(self, entity): + entity._fishtank = self + self._entities.append(entity) + sys.stdout.write("Added: {}\n".format(repr(entity))) + + def remove_entity(self, entity): + if entity not in self._entities: + sys.stderr.write( + "WARN: remove called for entity '{}', but it isn't in the eneityt list\n".format(entity.__name__)) + return + self._to_remove.append(entity) \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/entity/Entity.py b/src/entity/Entity.py new file mode 100644 index 0000000..bc7ad90 --- /dev/null +++ b/src/entity/Entity.py @@ -0,0 +1,25 @@ +import sys + +class Entity(object): + def __init__(self): + pass + + def __repr__(self): + return "[Entity]" + + def serialize(self): + return { + "module":"entity.Entity", + "class":"Entity" + } + + @staticmethod + def deserialize(serial): + e = Entity() + return e + + def update(self): + pass + + def draw(self): + pass \ No newline at end of file diff --git a/src/entity/Tube.py b/src/entity/Tube.py new file mode 100644 index 0000000..50af4d4 --- /dev/null +++ b/src/entity/Tube.py @@ -0,0 +1,22 @@ +import sys +from entity.Entity import Entity + +class Tube(Entity): + def __init__(self, network_gate): + Entity.__init__(self) + self._gate = network_gate + self._inbox = [] + + def __repr__(self): + return "[Tube gate={} inbox={}]".format(repr(self._gate), repr(self._inbox)) + + def accept(self, entity): + self._fishtank.remove_entity(entity) + self._inbox.append(entity) + + def update(self): + Entity.update(self) + if self._inbox: + entity = self._inbox.pop(0) + sys.stdout.write("Sending: {}\n".format(repr(entity))) + self._gate.transmit(entity.serialize()) \ No newline at end of file diff --git a/src/entity/__init__.py b/src/entity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/entity/dummy/DebugJumper.py b/src/entity/dummy/DebugJumper.py new file mode 100644 index 0000000..7f2dafd --- /dev/null +++ b/src/entity/dummy/DebugJumper.py @@ -0,0 +1,41 @@ +import sys +from entity.Entity import Entity +from entity.Tube import Tube + +class DebugJumper(Entity): + def __init__(self, message): + Entity.__init__(self) + self._message = message + self._counter = 0 + + def __repr__(self): + return "[DebugJumper message='{}' counter={}]".format(self._message, self._counter) + + def serialize(self): + sup = Entity.serialize(self) + sup.update({ + "module":"entity.dummy.DebugJumper", + "class":"DebugJumper", + "message":self._message, + "counter":self._counter + }) + return sup + + @staticmethod + def deserialize(serial): + e = DebugJumper(serial["message"]) + e._counter = serial["counter"] + return e + + def update(self): + Entity.update(self) + self._counter += 1 + if self._counter % 5 == 0: + for entity in self._fishtank._entities: + if type(entity) is Tube: + entity.accept(self) + break + + def draw(self): + Entity.draw(self) + sys.stdout.write(self._message + " ({})\n".format(self._counter)) \ No newline at end of file diff --git a/src/entity/dummy/DebugWaiter.py b/src/entity/dummy/DebugWaiter.py new file mode 100644 index 0000000..743610f --- /dev/null +++ b/src/entity/dummy/DebugWaiter.py @@ -0,0 +1,19 @@ +import sys +from entity.Entity import Entity + +class DebugWaiter(Entity): + def __init__(self, message): + Entity.__init__(self) + self._message = message + self._counter = 0 + + def __repr__(self): + return "[DebugWaiter message='{}' counter={}]".format(self._message, self._counter) + + def update(self): + Entity.update(self) + self._counter += 1 + + def draw(self): + Entity.draw(self) + sys.stdout.write(self._message + " ({})\n".format(self._counter)) \ No newline at end of file diff --git a/src/entity/dummy/__init__.py b/src/entity/dummy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/network/NetworkGate.py b/src/network/NetworkGate.py new file mode 100644 index 0000000..8d8ccf4 --- /dev/null +++ b/src/network/NetworkGate.py @@ -0,0 +1,19 @@ +import sys +import zmq +import json + +class NetworkGate(): + def __init__(self, address, port): + self._address = address + self._port = port + context = zmq.Context() + self._socket = context.socket(zmq.REQ) + self._socket.connect("tcp://{}:{}".format(address, port)) + + def __repr__(self): + return "[NetworkGate {}:{}]".format(self._address, self._port) + + def transmit(self, serial): + s = json.dumps(serial) + self._socket.send_string(s) + message = self._socket.recv() \ No newline at end of file diff --git a/src/network/__init__.py b/src/network/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/server.py b/src/server.py new file mode 100644 index 0000000..7b4d45e --- /dev/null +++ b/src/server.py @@ -0,0 +1,54 @@ +import sys +import zmq +import json +import time +from multiprocessing import Process, Queue +from Fishtank import Fishtank + +def socket_listener(port, recv_queue): + sys.stdout.write("Socket listener starting...\n") + context = zmq.Context() + socket = context.socket(zmq.REP) + socket.bind("tcp://*:{}".format(port)) + + while True: + message = socket.recv() + response = b"Undefined response" + try: + serial = json.loads(message) + if "class" in serial: + sys.stdout.write("Listener received a {}\n".format(serial["class"])) + recv_queue.put(serial, False) + response = b"Received" + except: + response = b"Error" + socket.send(response) + +def main(): + port = int(sys.argv[1]) + sys.stdout.write("Launching on port {}\n".format(port)) + # Spawn the socket thread + q = Queue() + socket_proc = Process(target=socket_listener, args=(port,q)) + socket_proc.start() + sys.stdout.write("Socket thread started\n") + time.sleep(1) + # Build the world + fishtank = Fishtank(q) + for i in range(1, len(sys.argv)): + if sys.argv[i] == "-w": + from entity.dummy.DebugWaiter import DebugWaiter + fishtank.add_entity(DebugWaiter("DebugWaiter")) + if sys.argv[i] == "-j": + from entity.dummy.DebugJumper import DebugJumper + fishtank.add_entity(DebugJumper("DebugJumper")) + if sys.argv[i] == "-t": + pipe_port = int(sys.argv[i+1]) + from network.NetworkGate import NetworkGate + network_gate = NetworkGate("localhost", pipe_port) + from entity.Tube import Tube + fishtank.add_entity(Tube(network_gate)) + fishtank.run() + +if __name__ == "__main__": + main() \ No newline at end of file