class BrokerEvents(object): def __init__(self, broker_uri, management_uri, log_level): self.log = Logger(name="BrokerEvents", level=log_level) self.log.debug("broker_uri='{}'", broker_uri) self.channel = Channel(broker_uri) self.subscription = Subscription(self.channel) self.subscription.subscribe(topic="binding.*") self.log.debug("management_uri='{}'", management_uri) self.consumers = self.query_consumers_http(management_uri) def run(self): while True: msg = self.channel.consume() self.log.debug("topic='{}' metadata={}", msg.topic, msg.metadata) if msg.metadata["destination_kind"] != "queue" or \ msg.metadata["source_name"] != "is": continue event = msg.topic.split('.')[-1] topic = msg.metadata["routing_key"] queue = msg.metadata["destination_name"] if event == "created": self.consumers.info[topic].consumers.append(queue) elif event == "deleted": self.consumers.info[topic].consumers.remove(queue) if len(self.consumers.info[topic].consumers) == 0: del self.consumers.info[topic] self.log.info("event='{}' topic='{}' queue='{}'", event, topic, queue) self.channel.publish( Message(content=self.consumers), topic="BrokerEvents.Consumers", ) @staticmethod def query_consumers_http(management_uri): reply = requests.get(management_uri + "/api/bindings") if reply.status_code != 200: why = "Failed to query management API, code={}".format( reply.status_code) raise RuntimeError(why) bindings = reply.json() bindings = [ b for b in bindings if b["destination_type"] == "queue" and b["source"] == "is" ] consumers = ConsumerList() for b in bindings: consumers.info[b["routing_key"]].consumers.append(b["destination"]) return consumers
class RobotGateway(object): def __init__(self, driver): self.driver = driver self.logger = Logger("RobotGateway") def get_config(self, field_selector, ctx): robot_config = RobotConfig() get_obj(self.driver.get_speed, robot_config.speed) return robot_config def set_config(self, robot_config, ctx): if robot_config.HasField("speed"): self.driver.set_speed(robot_config.speed) return Empty() def navigate_to(self, position, ctx): self.driver.navigate_to(position.x, position.y) return Empty() def move_to(self, pose, ctx): self.driver.move_to(pose.position.x, pose.position.y, pose.orientation.yaw) return Empty() def pause_awareness(self, req, ctx): self.driver.pause_awareness() return Empty() def resume_awareness(self, req, ctx): self.driver.resume_awareness() return Empty() def set_awareness(self, req, ctx): self.driver.set_awareness(req["enabled"]) return Empty() #def set_awareness_off(self, req, ctx): # self.driver.set_awareness_off() # return Empty() def run(self, id, broker_uri): service_name = "RobotGateway.{}".format(id) channel = Channel(broker_uri) server = ServiceProvider(channel) logging = LogInterceptor() server.add_interceptor(logging) server.delegate(topic=service_name + ".GetConfig", request_type=FieldSelector, reply_type=RobotConfig, function=self.get_config) server.delegate(topic=service_name + ".SetConfig", request_type=RobotConfig, reply_type=Empty, function=self.set_config) server.delegate(topic=service_name + ".NavigateTo", request_type=Position, reply_type=Empty, function=self.navigate_to) server.delegate(topic=service_name + ".MoveTo", request_type=Pose, reply_type=Empty, function=self.move_to) server.delegate(topic=service_name + ".PauseAwareness", request_type=Empty, reply_type=Empty, function=self.pause_awareness) server.delegate(topic=service_name + ".ResumeAwareness", request_type=Empty, reply_type=Empty, function=self.resume_awareness) server.delegate(topic=service_name + ".SetAwareness", request_type=Struct, reply_type=Empty, function=self.set_awareness) #server.delegate( # topic=service_name + ".SetAwarenessOff", # request_type=Empty, # reply_type=Empty, # function=self.set_awareness_off) self.logger.info("Listening for requests") while True: pose = self.driver.get_base_pose() frameTransList = FrameTransformations() frameTransList.tfs.extend([pose]) self.logger.debug("Publishing pose") channel.publish(Message(content=frameTransList), topic=service_name + ".FrameTransformations") try: message = channel.consume(timeout=0) if server.should_serve(message): server.serve(message) except socket.timeout: pass
class RequestManager: def __init__(self, channel, max_requests, min_requests=None, log_level=Logger.INFO, zipkin_exporter=None): if min_requests is None: min_requests = max_requests if min_requests < 0: min_requests = 0 if min_requests > max_requests: raise Exception("'min_requests' must be lower than 'max_requests'") self._channel = channel self._subscription = Subscription(self._channel) self._do_tracing = zipkin_exporter is not None self._zipkin_exporter = zipkin_exporter self._log = Logger(name='RequestManager') self._log.set_level(level=log_level) self._min_requests = min_requests self._max_requests = max_requests self._can_request = True self._requests = {} def can_request(self): return self._can_request def all_received(self): return len(self._requests) == 0 def request(self, content, topic, timeout_ms, metadata=None): if not self.can_request(): raise Exception( "Can't request more than {}. Use 'RequestManager.can_request' " "method to check if you can do requests.") tracer = Tracer( exporter=self._zipkin_exporter) if self._do_tracing else None span = tracer.start_span(name='request') if self._do_tracing else None msg = Message(content=content) msg.topic = topic msg.reply_to = self._subscription msg.timeout = timeout_ms / 1000.0 self._log.debug("[Sending] metadata={}, cid={}", metadata, msg.correlation_id) if self._do_tracing: for key, value in (metadata or {}).items(): span.add_attribute(key, value) tracer.end_span() msg.inject_tracing(span) self._publish(msg, metadata) if len(self._requests) >= self._max_requests: self._can_request = False def consume_ready(self, timeout=1.0): received_msgs = [] # wait for new message try: stated_at = now() while True: _timeout = max(0.0, stated_at + timeout - now()) msg = self._channel.consume(timeout=_timeout) if msg.status.ok() and msg.has_correlation_id(): cid = msg.correlation_id if cid in self._requests: received_msgs.append( (msg, self._requests[cid]["metadata"])) del self._requests[cid] except socket.timeout: pass # check for timeouted requests for cid in self._requests.keys(): timeouted_msg = self._requests[cid]["msg"] if timeouted_msg.deadline_exceeded(): msg = Message() msg.body = timeouted_msg.body msg.topic = timeouted_msg.topic msg.reply_to = self._subscription msg.timeout = timeouted_msg.timeout metadata = self._requests[cid]["metadata"] del self._requests[cid] self._log.debug("[Retring] metadata={}, cid={}", metadata, msg.correlation_id) self._publish(msg, metadata) if not self._can_request and len(self._requests) <= self._min_requests: self._can_request = True return received_msgs def _publish(self, msg, metadata): self._channel.publish(message=msg) self._requests[msg.correlation_id] = { "msg": msg, "metadata": metadata, }