class Topic(object): def __init__(self, name, message, publisher_queue=100): self.message = message self.name = resolve_name(name) self.publisher = Publisher(self.name, self.message, queue_size=publisher_queue) self.subscribers = {} def __del__(self): self.close() def close(self): self.publisher.unregister() for (handler, subscriber) in self.subscribers.items(): subscriber.unregister() def publish(self, message): self.publisher.publish(message) def subscribe(self, handler): self.subscribers[handler] = Subscriber(self.name, self.message, handler) def unsubscribe(self, handler): del self.subscribers[handler]
class MultiPublisher(): """ Keeps track of the clients that are using a particular publisher. Provides an API to publish messages and register clients that are using this publisher """ def __init__(self, topic, msg_type=None, latched_client_id=None, queue_size=100): """ Register a publisher on the specified topic. Keyword arguments: topic -- the name of the topic to register the publisher to msg_type -- (optional) the type to register the publisher as. If not provided, an attempt will be made to infer the topic type latch -- (optional) if a client requested this publisher to be latched, provide the client_id of that client here Throws: TopicNotEstablishedException -- if no msg_type was specified by the caller and the topic is not yet established, so a topic type cannot be inferred TypeConflictException -- if the msg_type was specified by the caller and the topic is established, and the established type is different to the user-specified msg_type """ # First check to see if the topic is already established topic_type = get_topic_type(topic)[0] # If it's not established and no type was specified, exception if msg_type is None and topic_type is None: raise TopicNotEstablishedException(topic) # Use the established topic type if none was specified if msg_type is None: msg_type = topic_type # Load the message class, propagating any exceptions from bad msg types msg_class = ros_loader.get_message_class(msg_type) # Make sure the specified msg type and established msg type are same if topic_type is not None and topic_type != msg_class._type: raise TypeConflictException(topic, topic_type, msg_class._type) # Create the publisher and associated member variables self.clients = {} self.latched_client_id = latched_client_id self.topic = topic self.msg_class = msg_class self.publisher = Publisher(topic, msg_class, latch=(latched_client_id != None), queue_size=queue_size) self.listener = PublisherConsistencyListener() self.listener.attach(self.publisher) def unregister(self): """ Unregisters the publisher and clears the clients """ self.publisher.unregister() self.clients.clear() def verify_type(self, msg_type): """ Verify that the publisher publishes messages of the specified type. Keyword arguments: msg_type -- the type to check this publisher against Throws: Exception -- if ros_loader cannot load the specified msg type TypeConflictException -- if the msg_type is different than the type of this publisher """ if not ros_loader.get_message_class(msg_type) is self.msg_class: raise TypeConflictException(self.topic, self.msg_class._type, msg_type) return def publish(self, msg): """ Publish a message using this publisher. Keyword arguments: msg -- the dict (json) message to publish Throws: Exception -- propagates exceptions from message conversion if the provided msg does not properly conform to the message type of this publisher """ # First, check the publisher consistency listener to see if it's done if self.listener.attached and self.listener.timed_out(): self.listener.detach() # Create a message instance inst = self.msg_class() # Populate the instance, propagating any exceptions that may be thrown message_conversion.populate_instance(msg, inst) # Publish the message self.publisher.publish(inst) def register_client(self, client_id): """ Register the specified client as a client of this publisher. Keyword arguments: client_id -- the ID of the client using the publisher """ self.clients[client_id] = True def unregister_client(self, client_id): """ Unregister the specified client from this publisher. If the specified client_id is not a client of this publisher, nothing happens. Keyword arguments: client_id -- the ID of the client to remove """ if client_id in self.clients: del self.clients[client_id] def has_clients(self): """ Return true if there are clients to this publisher. """ return len(self.clients) != 0
class MultiPublisher(): """ Keeps track of the clients that are using a particular publisher. Provides an API to publish messages and register clients that are using this publisher """ def __init__(self, topic, msg_type=None, latched_client_id=None, queue_size=100): """ Register a publisher on the specified topic. Keyword arguments: topic -- the name of the topic to register the publisher to msg_type -- (optional) the type to register the publisher as. If not provided, an attempt will be made to infer the topic type latch -- (optional) if a client requested this publisher to be latched, provide the client_id of that client here Throws: TopicNotEstablishedException -- if no msg_type was specified by the caller and the topic is not yet established, so a topic type cannot be inferred TypeConflictException -- if the msg_type was specified by the caller and the topic is established, and the established type is different to the user-specified msg_type """ # First check to see if the topic is already established topic_type = get_topic_type(topic)[0] # If it's not established and no type was specified, exception if msg_type is None and topic_type is None: raise TopicNotEstablishedException(topic) # Use the established topic type if none was specified if msg_type is None: msg_type = topic_type # Load the message class, propagating any exceptions from bad msg types msg_class = ros_loader.get_message_class(msg_type) # Make sure the specified msg type and established msg type are same if topic_type is not None and topic_type != msg_class._type: raise TypeConflictException(topic, topic_type, msg_class._type) # Create the publisher and associated member variables self.clients = {} self.latched_client_id = latched_client_id self.topic = topic self.msg_class = msg_class self.publisher = Publisher(topic, msg_class, latch=(latched_client_id!=None), queue_size=queue_size) self.listener = PublisherConsistencyListener() self.listener.attach(self.publisher) def unregister(self): """ Unregisters the publisher and clears the clients """ self.publisher.unregister() self.clients.clear() def verify_type(self, msg_type): """ Verify that the publisher publishes messages of the specified type. Keyword arguments: msg_type -- the type to check this publisher against Throws: Exception -- if ros_loader cannot load the specified msg type TypeConflictException -- if the msg_type is different than the type of this publisher """ if not ros_loader.get_message_class(msg_type) is self.msg_class: raise TypeConflictException(self.topic, self.msg_class._type, msg_type) return def publish(self, msg): """ Publish a message using this publisher. Keyword arguments: msg -- the dict (json) message to publish Throws: Exception -- propagates exceptions from message conversion if the provided msg does not properly conform to the message type of this publisher """ # First, check the publisher consistency listener to see if it's done if self.listener.attached and self.listener.timed_out(): self.listener.detach() # Create a message instance inst = self.msg_class() # Populate the instance, propagating any exceptions that may be thrown message_conversion.populate_instance(msg, inst) # Publish the message self.publisher.publish(inst) def register_client(self, client_id): """ Register the specified client as a client of this publisher. Keyword arguments: client_id -- the ID of the client using the publisher """ self.clients[client_id] = True def unregister_client(self, client_id): """ Unregister the specified client from this publisher. If the specified client_id is not a client of this publisher, nothing happens. Keyword arguments: client_id -- the ID of the client to remove """ if client_id in self.clients: del self.clients[client_id] def has_clients(self): """ Return true if there are clients to this publisher. """ return len(self.clients) != 0