From 64a5d8e56c713fcb9a27deabe41fbd9c0072ede2 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 2 May 2019 11:21:24 +0200 Subject: [PATCH] feat(client): append serial agent to client API (#74) --- client.py | 44 +++++++++++++++++++++++++++----------------- img/threading.png | Bin 12466 -> 14286 bytes operators.py | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/client.py b/client.py index 34c6ee7..58bbefd 100644 --- a/client.py +++ b/client.py @@ -10,19 +10,19 @@ from random import randint import copy import queue -import zmq +# import zmq lock = threading.Lock() try: from .libs import umsgpack - # from .libs import zmq + from .libs import zmq from .libs import dump_anything from . import helpers from . import message except: # Server import from libs import umsgpack - # from libs import zmq + from libs import zmq from libs import dump_anything import helpers import message @@ -63,28 +63,36 @@ class State(Enum): class RCFClient(object): ctx = None pipe = None - agent = None + net_agent = None def __init__(self): self.ctx = zmq.Context() self.pipe, peer = zpipe(self.ctx) - self.queue = queue.Queue() - self.agent = threading.Thread( - target=rcf_client_agent, args=(self.ctx, peer, self.queue), name="net-agent") - self.agent.daemon = True - self.agent.start() - # self.sync_agent = threading.Thread( - # target=rcf_sync_agent, args=(self.ctx, self.pipe), name="sync-agent") - # self.sync_agent.daemon = True - # self.sync_agent.start() + self.serial_pipe, serial_peer = zpipe(self.ctx) + serial_in, net_in = zpipe(self.ctx) + self.tasks = queue.Queue() + + # Database and connexion agent + self.net_agent = threading.Thread( + target=rcf_client_agent, args=(self.ctx, peer, self.tasks), name="net-agent") + self.net_agent.daemon = True + self.net_agent.start() + + # Local data translation agent + self.serial_agent = threading.Thread( + target=serialization_agent, args=(self.ctx, serial_peer, self.tasks), name="serial-agent") + self.serial_agent.daemon = True + self.serial_agent.start() + def connect(self, id, address, port): self.pipe.send_multipart([b"CONNECT", (id.encode() if isinstance( id, str) else id), (address.encode() if isinstance( address, str) else address), b'%d' % port]) + def init(self): - """Set new value in distributed hash table - Sends [SET][key][value] to the agent + """ + Scene initialisation """ self.pipe.send_multipart( [b"INIT"]) @@ -100,6 +108,7 @@ class RCFClient(object): """Set new value in distributed hash table Sends [SET][key][value] to the agent """ + self.pipe.send_multipart( [b"SET", umsgpack.packb(key), (umsgpack.packb(value) if value else umsgpack.packb('None')),umsgpack.packb(override)]) @@ -125,7 +134,7 @@ class RCFClient(object): return umsgpack.unpackb(reply[0]) def exit(self): - if self.agent.is_alive(): + if self.net_agent.is_alive(): self.disconnect() # Disconnect time @@ -476,7 +485,7 @@ class SerializationAgent(object): self.pipe.send_multipart([b"DONE"]) -def serialization_agent(ctx, pipe): +def serialization_agent(ctx, pipe, tasks): agent = SerializationAgent(ctx, pipe) global stop @@ -496,6 +505,7 @@ def serialization_agent(ctx, pipe): if agent.pipe in items: agent.control_message() + # TODO : Fill tasks class RCFSyncAgent(object): ctx = None diff --git a/img/threading.png b/img/threading.png index dd54520e3b922741e3946a7e1d6066f239f8a3e6..d0d5d2b42ffd85bdf5392154582b1a35f181dfde 100644 GIT binary patch literal 14286 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 Kxv~eA&;BpQO#TZ1 literal 12466 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