def service_internal(self, service, msg, clear): """Handle internal service according to 8/MMI specification""" returncode = b"501" if b"mmi.service" == service: name = msg[-1] returncode = b"200" if name in self.services else b"404" if b"mmi.services" == service: name = msg[-1] sl = [] for serv in self.services: sl.append(serv.decode()) returncode = json.dumps({'services': sl}).encode() logging.warning('mmi.services : {0}'.format(returncode)) if b"mmi.workers" == service: name = msg[-1] wl = [] for w in self.workers: wl.append(w.decode()) returncode = json.dumps({'workers': wl}).encode() logging.warning('mmi.services : {0}'.format(returncode)) msg[-1] = returncode # insert the protocol header and service name after the routing envelope ([client, '']) msg = msg[:2] + [IDP.C_CLIENT, service] + msg[2:] if self.verbose: logging.info("I: sending MMI reply") dump(msg) if clear: self.socketclear.send(msg) else: self.socketcurve.send(msg)
def send_to_worker(self, worker, command, option, msg=None): """Send message to worker. If message is provided, sends that message. """ if msg is None: msg = [] elif not isinstance(msg, list): msg = [msg] # Stack routing and protocol envelopes to start of message # and routing envelope if option is not None: msg = [option] + msg msg = [worker.address, b'', IDP.W_WORKER, command] + msg if self.verbose: logging.info("I: sending %r to worker", command) dump(msg) if (worker.clear): self.socketclear.send(msg) else: self.socketcurve.send(msg)
def recv(self): try: items = self.poller.poll(self.timeout) except KeyboardInterrupt: return None # interrupted if items: msg = self.client.recv() if self.verbose: logging.info("I: received reply:") dump(msg) # Don't try to handle errors, just assert noisily assert len(msg) >= 4 msg.pop(0) header = msg.pop(0) assert IDP.C_CLIENT == header msg.pop(0) # popping reply service reply = msg else: reply = None return reply
def send(self, service, request): """Send request to broker and get reply by hook or crook. Takes ownership of request message and destroys it when sent. Returns the reply message or None if there was no reply. """ if not isinstance(request, list): request = [request] request = [b'', IDP.C_CLIENT, service] + request if self.verbose: logging.info("I: send request to '%s' service: ", service) dump(request) self.client.send(request)
def send(self, service, request): """Send request to broker and get reply by hook or crook. Takes ownership of request message and destroys it when sent. Returns the reply message or None if there was no reply. """ if not isinstance(request, list): request = [request] request = [IDP.C_CLIENT, service] + request if self.verbose: logging.info("I: send request to '%s' service: ", service) dump(request) reply = None retries = self.retries while retries > 0: self.client.send(request) try: items = self.poller.poll(self.timeout) except KeyboardInterrupt: break # interrupted if items: msg = self.client.recv() if self.verbose: logging.info("I: received reply:") dump(msg) # Don't try to handle errors, just assert noisily assert len(msg) >= 3 header = msg.pop(0) assert IDP.C_CLIENT == header reply_service = msg.pop(0) assert service == reply_service reply = msg break else: if retries: logging.warn("W: no reply, reconnecting...") self.reconnect_to_broker() else: logging.warn("W: permanent error, abandoning") break retries -= 1 return reply
def send_to_broker(self, command, option=None, msg=None): """Send message to broker. If no msg is provided, creates one internally """ if msg is None: msg = [] elif not isinstance(msg, list): msg = [msg] if option: msg = [option] + msg msg = [b'', IDP.W_WORKER, command] + msg if self.verbose: logging.info("I: sending %s to broker", command) dump(msg) self.worker.send(msg)
def route(self, socket, clear=None): msg = socket.recv() sender = msg.pop(0) if self.verbose: logging.info("I: received message from: {0}".format(sender)) dump(msg) empty = msg.pop(0) assert empty == b'' header = msg.pop(0) if (IDP.C_CLIENT == header): self.process_client(sender, msg, clear) elif (IDP.W_WORKER == header): self.process_worker(sender, msg, clear) else: logging.error("E: invalid message:") dump(msg)
def route(self, socket, clear=None): msg = socket.recv(copy=False) sender = msg.pop(0).buffer if self.nolegacy: sender = sender.toreadonly() else: sender = sender.tobytes() if self.verbose: logging.info("I: received message from: {0}".format(sender)) dump(msg) empty = msg.pop(0) assert empty.buffer == b'' header = msg.pop(0) if (IDP.C_CLIENT == header.buffer): self.process_client(sender, msg, clear) elif (IDP.W_WORKER == header.buffer): self.process_worker(sender, msg, clear) else: logging.error("E: invalid message:") dump(msg)
def process_worker(self, sender, msg, clear): """Process message sent to us by a worker.""" assert len(msg) >= 1 # At least, command command = msg.pop(0) worker_ready = sender in self.workers worker = self.require_worker(sender, clear) if (IDP.W_REPLY == command): if (worker_ready): # Remove & save client return envelope and insert the # protocol header and service name, then rewrap envelope. client = msg.pop(0) empty = msg.pop(0) # ? msg = [client, b'', IDP.C_CLIENT, worker.service.name] + msg self.socketclear.send(msg) self.worker_waiting(worker) else: logging.warning( 'IDP.W_REPLY expected, got: {0} from {1}'.format( command, worker.identity)) self.delete_worker(worker, True) elif (IDP.W_REPLY_CURVE == command): if (worker_ready): # Remove & save client return envelope and insert the # protocol header and service name, then rewrap envelope. client = msg.pop(0) empty = msg.pop(0) # ? msg = [client, b'', IDP.C_CLIENT, worker.service.name] + msg self.socketcurve.send(msg) self.worker_waiting(worker) else: logging.warning( 'IDP.W_REPLY expected, got: {0} from {1}'.format( command, worker.identity)) self.delete_worker(worker, True) elif (IDP.W_READY == command): assert len(msg) >= 1 # At least, a service name service = msg.pop(0) # Not first command in session or Reserved service name if (worker_ready or service.startswith(self.INTERNAL_SERVICE_PREFIX)): logging.warning( 'Not first command in session or Reserved service name: {0}' .format(worker.identity)) self.delete_worker(worker, True) else: # Attach worker to service and mark as idle logging.warning('Attaching: {0}'.format(worker.identity)) worker.service = self.require_service(service) self.worker_waiting(worker) elif (IDP.W_HEARTBEAT == command): if (worker_ready): worker.expiry = time.time() + 1e-3 * self.HEARTBEAT_EXPIRY else: logging.warning( 'Received Heartbeat from unintialized Worker: {0}'.format( worker.identity)) self.delete_worker(worker, True) elif (IDP.W_DISCONNECT == command): logging.warning('Received disconnect: {0}'.format(worker.identity)) self.delete_worker(worker, False) else: logging.error("E: invalid message:") dump(msg)
def recv(self, reply=None): """Send reply, if any, to broker and wait for next request.""" # Format and send the reply if we were provided one assert reply is not None or not self.expect_reply if reply is not None: if (self.reply_to_clear is not None): reply = [self.reply_to_clear, b''] + reply self.send_to_broker(IDP.W_REPLY, msg=reply) elif (self.reply_to_curve is not None): reply = [self.reply_to_curve, b''] + reply self.send_to_broker(IDP.W_REPLY_CURVE, msg=reply) else: logging.error('Missing Reply!') self.expect_reply = True while True: # Poll socket for a reply, with timeout try: items = self.poller.poll(self.timeout) except KeyboardInterrupt: break # Interrupted if items: msg = self.worker.recv() if self.verbose: logging.info("I: received message from broker: ") dump(msg) self.liveness = self.HEARTBEAT_LIVENESS # Don't try to handle errors, just assert noisily assert len(msg) >= 3 empty = msg.pop(0) assert empty == b'' header = msg.pop(0) assert header == IDP.W_WORKER command = msg.pop(0) if command == IDP.W_REQUEST: # We should pop and save as many addresses as there are # up to a null part, but for now, just save one... self.reply_to_clear = msg.pop(0) self.reply_to_curve = None # pop empty empty = msg.pop(0) assert empty == b'' self.last_message = time.time() return msg # We have a request to process elif command == IDP.W_REQUEST_CURVE: # We should pop and save as many addresses as there are # up to a null part, but for now, just save one... self.reply_to_clear = None self.reply_to_curve = msg.pop(0) # pop empty empty = msg.pop(0) assert empty == b'' self.last_message = time.time() return msg # We have a request to process elif command == IDP.W_HEARTBEAT: logging.debug('Received W_HEARTBEAT: {0}'.format( self.service)) # Do nothing for heartbeats pass elif command == IDP.W_DISCONNECT: logging.warning('Received W_DISCONNECT!') self.reconnect_to_broker() else: logging.error("E: invalid input message: ") dump(msg) else: self.liveness -= 1 if self.liveness == 0: logging.warn("Disconnected from broker - retrying...") try: if self.worker: self.poller.unregister(self.worker.socket) self.worker.close() self.worker = None time.sleep(1e-3 * self.reconnect) except KeyboardInterrupt: break self.reconnect_to_broker() if self.idle_timeout: now = time.time() if now - self.last_message >= self.idle_timeout: self.alive = False logging.warning('Worker has been idle for too much time') break # Send HEARTBEAT if it's time if time.time() > self.heartbeat_at: self.send_to_broker(IDP.W_HEARTBEAT) self.heartbeat_at = time.time() + 1e-3 * self.heartbeat logging.warn("W: interrupt received, killing worker...") return None