def recv_server(number, bind, shape, verbosity, attrs): ''' A simple server to catch some TENS messages from flow and dump them. ''' import zmq from zio import Port, Message, Node from zio.flow import Flow log.level = getattr(logging, verbosity.upper(), "INFO") msg_attr = attrify(attrs) snode = Node("server") sport = snode.port("sport", zmq.SERVER) sport.bind(bind) snode.online() sflow = Flow(sport) bot = sflow.recv_bot() assert (bot) lobj = bot.label_object lobj["direction"] = "inject" bot.label_object = lobj sflow.send_bot(bot) log.debug('flow-recv-server: BOT handshake done') sflow.flush_pay() log.debug('flow-recv-server: looping') while True: msg = sflow.get(1000) log.info(f'flow-recv-server: {msg}') if not msg or 'EOT' == msg.label_object['flow']: log.debug('flow-recv-server: got EOT') sflow.send_eot() # answer break snode.offline() log.debug(f'flow-recv-server: end')
class TestFlow(unittest.TestCase): origin = 42 def setUp(self): self.snode = Node("server", self.origin) sport = self.snode.port("sport", zmq.SERVER) sport.bind() self.snode.online() self.sflow = Flow(sport) self.cnode = Node("client") cport = self.cnode.port("cport", zmq.CLIENT) cport.connect("server", "sport") self.cnode.online() self.cflow = Flow(cport) def test_conversation(self): # cflow is recver bot = Message(label='{"credit":2,"direction":"inject"}') self.cflow.send_bot(bot) bot = self.sflow.recv_bot(1000) assert (bot) assert (self.sflow.credit == 0) assert (self.sflow.total_credit == 2) # sflow is sender bot = Message(label='{"credit":2,"direction":"extract"}') self.sflow.send_bot(bot) bot = self.cflow.recv_bot(1000) assert (bot) assert (self.cflow.credit == 2) assert (self.cflow.total_credit == 2) self.cflow.flush_pay() assert (self.cflow.credit == 0) c = self.sflow.slurp_pay() assert (c == 2) assert (self.sflow.credit == 2) for count in range(10): # note, seqno normally should sequential self.sflow.put(Message(coord=CoordHeader(seqno=100 + count))) self.sflow.put(Message(coord=CoordHeader(seqno=200 + count))) dat = self.cflow.get() assert (dat.seqno == 100 + count) dat = self.cflow.get() assert (dat.seqno == 200 + count) # normally, when a flow explicitly sends EOT the other end # will recv the EOT when its trying to recv another message # (PAY or DAT). In this test things are synchronous and so we # explicitly recv_eot(). self.cflow.send_eot(Message()) surprise = self.sflow.recv_eot(1000) assert (surprise) self.sflow.send_eot(Message()) expected = self.cflow.recv_eot(1000) assert (expected) def test_flow_string(self): msg = Message(label='{"extra":42}') msg.label = stringify('DAT', **objectify(msg)) fobj = objectify(msg) assert (fobj["extra"] == 42) assert (fobj["flow"] == "DAT") def tearDown(self): self.cnode.offline() self.snode.offline() pass
def client_handler(ctx, pipe, bot, rule_object, writer_addr, broker_addr): '''Connect to and marshall messages between broker and writer sockets. Parameters ---------- bot : zio.Message The BOT message rule_object: dicionary A ruleset rule object. writer_addr :: string The address of the writer's PULL socket to connect. broker_addr : string The address of the broker's SERVER socket to connect. ''' # An HDF path to be added to every message we send to writer. mattr = message_to_dict(bot) rattr = dict(rule_object["attr"], **mattr) base_path = rule_object["grouppat"].format(**rattr) log.debug(f'client_handler(msg, "{base_path}", "{broker_addr}", "{writer_addr}")') log.debug(bot) pipe.signal() push = ctx.socket(PUSH) push.connect(writer_addr) sock = ctx.socket(CLIENT) port = Port("write-handler", sock) port.connect(broker_addr) port.online(None) flow = Flow(port) log.debug (f'writer({base_path}) send BOT to {broker_addr}') flow.send_bot(bot) # this introduces us to the server bot = flow.recv_bot() log.debug (f'writer({base_path}) got response:\n{bot}') flow.flush_pay() def push_message(m): log.debug (f'write_handler({base_path}) push {m}') attr = message_to_dict(m) attr['hdfgroup'] = base_path m.label = json.dumps(attr) push.send(m.encode()) push_message(bot) poller = Poller() poller.register(pipe, POLLIN) poller.register(sock, POLLIN) while True: for which,_ in poller.poll(): if not which: return if which == pipe: # signal exit log.debug ('write_handler pipe hit') return # o.w. we have flow try: msg = flow.get() except Exception as err: log.warning('flow.get error: %s %s' % (type(err),err)) continue if not msg: log.debug("write_handler: got EOT") flow.send_eot() # fixme: send an EOT also to push socket?. break push_message(msg) continue log.debug ('write_handler exiting') pipe.signal()