class Publisher(object): def __init__(self, name="(publisher-only)"): self.name = name address = self._get_address() try: self.connection = Connection(address, whoiam=name) self._log(syslog.LOG_DEBUG, "Stablished a connection with the notifier server (%s)." % esc(str(address))) except: self._log(syslog.LOG_ERR, "Error when creating a connection with the notifier server (%s): %s." % esc(str(address), traceback.format_exc())) raise self.connection.send_object(pack_message(message_type='introduce_myself', name=name)) self._safe_topics = set() def publish(self, topic, data): if topic not in self._safe_topics: fail_if_topic_isnt_valid(topic, allow_empty=False) self._safe_topics.add(topic) #self._log(syslog.LOG_DEBUG, "Sending publication of an event with topic '%s'." % esc(topic)) self.connection.send_object(pack_message(message_type='publish', topic=topic, obj=data, dont_pack_object=False)) #self._log(syslog.LOG_DEBUG, "Publication of an event sent.") def close(self, *args, **kargs): self.connection.close() def _get_address(self): import os, ConfigParser script_home = os.path.abspath(os.path.dirname(__file__)) parent = os.path.pardir # TODO This shouldn't be hardcoded! config_file = os.path.join(script_home, parent, parent, parent, "config", "publish_subscribe.cfg") config = ConfigParser.SafeConfigParser(defaults={ 'wait_on_address': "localhost", 'wait_on_port': "5555", }) config.read([config_file]) if not config.has_section("notifier"): config.add_section("notifier") address = (config.get("notifier", 'wait_on_address'), config.getint("notifier", 'wait_on_port')) return address def __repr__(self): return "Endpoint (%s)" % self.name def _log(self, level, message): #TODO remove the "%" stuff over an unknow string (not local string) header = "%s: " % esc(repr(self)) message = header + message syslog.syslog(level, message) return message
class _Endpoint(threading.Thread): def __init__(self, socket, notifier, codename): threading.Thread.__init__(self) self.connection = Connection(socket) self.is_finished = False self.notifier = notifier self.codename = codename self.name = "" self.start() def _is_valid_message(self, message_type, message_body): if not message_type in ("subscribe", "publish", "unsubscribe", "introduce_myself"): return False return True def _process_message(self, message_type, message_body): if message_type == "publish": topic, raw_obj = unpack_message_body(message_type, message_body, dont_unpack_object=True) self.notifier.distribute_event(topic, raw_obj) elif message_type == "unsubscribe": topic = unpack_message_body(message_type, message_body) self.notifier.unsubscribe_me(topic, self) elif message_type == "introduce_myself": self.name = unpack_message_body(message_type, message_body) self._log(syslog.LOG_NOTICE, "Introduced himself as '%s'." % esc(self.name)) elif message_type == "subscribe": topic = unpack_message_body(message_type, message_body) self.notifier.register_subscriber(topic, self) else: self._log(syslog.LOG_ERR, "Invalid message. Unknown type: '%s'." % esc(message_type)) raise Exception("Invalid message.") def run(self): try: while not self.connection.end_of_the_communication: message_type, message_body = self.connection.receive_object() self._process_message(message_type, message_body) self._log(syslog.LOG_NOTICE, "The connection was closed by the other point of the connection.") except: self._log(syslog.LOG_ERR, "An exception has occurred when receiving/processing the messages: %s." % esc(traceback.format_exc())) finally: self.is_finished = True def send_event(self, topic, obj_raw): try: self.connection.send_object(pack_message(message_type="publish", topic=topic, obj=obj_raw, dont_pack_object=True)) except: self._log(syslog.LOG_ERR, "An exception when sending a message to it: %s." % esc(traceback.format_exc())) self.is_finished = True def close(self): self._log(syslog.LOG_NOTICE, "Closing the connection with the endpoint.") self.is_finished = True self.connection.close() self._log(syslog.LOG_NOTICE, "Connection closed") def __repr__(self): return "%s%s%s" % (self.codename, ((" (%s)" % self.name) if self.name else ""), (" [dead]" if self.is_finished else "")) def _log(self, level, message): message = ("%s: " % esc(repr(self))) + message syslog.syslog(level, message)