From 5b868287d5e71e27ed3d39f2de457954e60660be Mon Sep 17 00:00:00 2001 From: David Rousselie Date: Tue, 13 May 2008 19:42:07 +0200 Subject: [PATCH] Some refactoring in presence module darcs-hash:20080513174207-86b55-fddead25458026a8ad8de05455a6e1070f19b3ce.gz --- src/jcl/jabber/command.py | 21 ++-- src/jcl/jabber/component.py | 181 ++++++++++++------------------ src/jcl/jabber/presence.py | 37 +++--- src/jcl/jabber/tests/command.py | 44 ++++---- src/jcl/jabber/tests/component.py | 4 +- 5 files changed, 126 insertions(+), 161 deletions(-) diff --git a/src/jcl/jabber/command.py b/src/jcl/jabber/command.py index 97be09a..74ed301 100644 --- a/src/jcl/jabber/command.py +++ b/src/jcl/jabber/command.py @@ -74,7 +74,7 @@ class CommandError(Exception): """ Exception.__init__(self) self.type = error_type - + class CommandManager(object): """Handle Ad-Hoc commands""" @@ -110,7 +110,7 @@ class CommandManager(object): for command_name in self.commands.keys(): (must_be_admin, to_jid_re) = self.commands[command_name] if to_jid_re.match(unicode(to_jid)) and \ - (not must_be_admin or + (not must_be_admin or (must_be_admin and self.component.is_admin(jid))): command_desc = self.get_command_desc(command_name, lang_class) @@ -274,7 +274,10 @@ class CommandManager(object): "feature-not-implemented")] except CommandError, error: return [info_query.make_error_response(error.type)] - except Exception: + except Exception, exception: + self.__logger.error("Unknown error while executing " + + str(short_node) + " command: ", + exc_info=True) return [info_query.make_error_response("service-unavailable")] def add_actions(self, command_node, actions, default_action_idx=0): @@ -700,7 +703,7 @@ class JCLCommandManager(CommandManager): for account_name in session_context["account_names"]: name, user_jid = self.get_name_and_jid(account_name) _account = account.get_account(user_jid, name) - result += self.component.account_manager.send_presence_unavailable( + result += self.component.account_manager.get_account_presence_unavailable( _account) command_node.setProp("status", STATUS_COMPLETED) return (None, result) @@ -1248,12 +1251,13 @@ class JCLCommandManager(CommandManager): to_jid=user.jid, body=announcement)) command_node.setProp("status", STATUS_COMPLETED) - def delayed_restart(self, delay): + def delayed_shutdown(self, delay): threading.Event().wait(delay) self.component.running = False - restart_thread = threading.Thread(target=lambda : delayed_restart(self, delay), - name="TimerThread") - restart_thread.start() + shutdown_thread = threading.Thread(\ + target=lambda : delayed_shutdown(self, delay), + name="TimerThread") + shutdown_thread.start() return (None, result) def execute_get_last_error_1(self, info_query, session_context, @@ -1321,4 +1325,3 @@ class CommandDiscoGetItemsHandler(DiscoHandler): to_jid=info_query.get_to(), disco_items=disco_obj, lang_class=lang_class)] - diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py index 192ac5c..356c5c7 100644 --- a/src/jcl/jabber/component.py +++ b/src/jcl/jabber/component.py @@ -218,11 +218,7 @@ class AccountManager(object): try: getattr(_account, "populate_handler")() except Exception, exception: - typ, value, stack = sys.exc_info() - self.__logger.error(\ - "Error in timer thread\n%s\n%s" - % (exception, "".join(traceback.format_exception - (typ, value, stack, 5)))) + self.__logger.error("Error in timer thread:", exc_info=True) result.extend(self.send_error_from_account(_account, exception)) @@ -337,27 +333,85 @@ class AccountManager(object): return [] ###### presence generic handlers ###### - def send_presence_all(self, presence): + def get_presence_all(self, presence): """Send presence to all account. Optimized to use only one sql request""" result = [] model.db_connect() - # Explicit reference to account table (clauseTables) to use - # "user_jid" column with Account subclasses for user in account.get_all_users(): - result.extend(self.send_presence(self.component.jid, - user.jid, - presence)) + result.extend(self.get_presence(self.component.jid, + user.jid, + presence)) for _account in account.get_all_accounts(): - result.extend(getattr(self, "send_presence_" + + result.extend(getattr(self, "get_account_presence_" + presence)(_account)) model.db_disconnect() return result + def get_root_presence(self, to_jid, presence_type, + show=None, status=None): + result = self.get_presence(self.component.jid, to_jid, + presence_type, show=show, + status=status) + for legacy_jid in account.get_legacy_jids(unicode(to_jid.bare())): + result.append(Presence(from_jid=legacy_jid.jid, + to_jid=to_jid, + show=show, + status=status, + stanza_type=presence_type)) + return result + + def get_presence(self, from_jid, to_jid, presence_type, + status=None, show=None): + """Send presence stanza""" + return [Presence(from_jid=from_jid, + to_jid=to_jid, + status=status, + show=show, + stanza_type=presence_type)] + + def get_account_presence_probe(self, _account): + """Send presence probe to account's user""" + return self.get_presence(from_jid=_account.jid, + to_jid=_account.user.jid, + presence_type="probe") + + def get_account_presence_unavailable(self, _account): + """Send unavailable presence to account's user""" + _account.status = account.OFFLINE + return self.get_presence(from_jid=_account.jid, + to_jid=_account.user.jid, + presence_type="unavailable") + + def get_account_presence_available(self, _account, lang_class): + """Send available presence to account's user and ask for password + if necessary""" + result = [] + model.db_connect() + _account.default_lang_class = lang_class + old_status = _account.status + _account.status = account.ONLINE + if _account.error is not None: + _account.status = account.DND + elif not _account.enabled: + _account.status = account.XA + result.extend(self.get_presence(from_jid=_account.jid, + to_jid=_account.user.jid, + status=_account.status_msg, + show=_account.status, + presence_type="available")) + if hasattr(_account, 'store_password') \ + and hasattr(_account, 'password') \ + and _account.store_password == False \ + and old_status == account.OFFLINE \ + and _account.password == None : + result.extend(self.ask_password(_account, lang_class)) + model.db_disconnect() + return result def probe_all_accounts_presence(self): """Send presence probe to all registered accounts""" - return self.send_presence_all("probe") + return self.get_presence_all("probe") ###### Utils methods ###### def list_accounts(self, bare_from_jid, account_class=None, @@ -469,78 +523,6 @@ class AccountManager(object): """Compose account jid from account name""" return name + u"@" + unicode(self.component.jid) - def send_presence_probe(self, _account): - """Send presence probe to account's user""" - return [Presence(from_jid=_account.jid, - to_jid=_account.user.jid, - stanza_type="probe")] - - def send_presence_unavailable(self, _account): - """Send unavailable presence to account's user""" - model.db_connect() - _account.status = account.OFFLINE - result = [Presence(from_jid=_account.jid, - to_jid=_account.user.jid, - stanza_type="unavailable")] - model.db_disconnect() - return result - - def send_root_presence(self, to_jid, presence_type, - show=None, status=None): - result = self.send_presence(self.component.jid, to_jid, - presence_type, show=show, - status=status) - result.extend(self.send_root_presence_legacy(to_jid, - presence_type, - show=show, - status=status)) - return result - - def send_presence(self, from_jid, to_jid, presence_type, status=None, show=None): - """Send presence stanza""" - return [Presence(from_jid=from_jid, - to_jid=to_jid, - status=status, - show=show, - stanza_type=presence_type)] - - def send_presence_available(self, _account, show, lang_class): - """Send available presence to account's user and ask for password - if necessary""" - result = [] - model.db_connect() - _account.default_lang_class = lang_class - old_status = _account.status - if show is None: - _account.status = account.ONLINE - else: - _account.status = show - result.append(Presence(from_jid=_account.jid, - to_jid=_account.user.jid, - status=_account.status_msg, - show=show, - stanza_type="available")) - if hasattr(_account, 'store_password') \ - and hasattr(_account, 'password') \ - and _account.store_password == False \ - and old_status == account.OFFLINE \ - and _account.password == None : - result.extend(self.ask_password(_account, lang_class)) - model.db_disconnect() - return result - - def send_root_presence_legacy(self, to_jid, presence_type, - status=None, show=None): - """Send presence from legacy JID""" - result = [] - for legacy_jid in account.get_legacy_jids(unicode(to_jid.bare())): - result.append(Presence(from_jid=legacy_jid.jid, - to_jid=to_jid, - show=show, - status=status, - stanza_type=presence_type)) - return result - def ask_password(self, _account, lang_class): """Send a Jabber message to ask for account password """ @@ -685,7 +667,7 @@ class JCLComponent(Component, object): self.running = False if self.stream and not self.stream.eof \ and self.stream.socket is not None: - presences = self.account_manager.send_presence_all("unavailable") + presences = self.account_manager.get_presence_all("unavailable") self.send_stanzas(presences) self.wait_event.set() timer_thread.join(JCLComponent.timeout) @@ -718,10 +700,7 @@ class JCLComponent(Component, object): self.handle_tick() self.__logger.debug(".") except Exception, exception: - type, value, stack = sys.exc_info() - self.__logger.error("Error in timer thread\n%s\n%s" - % (exception, "".join(traceback.format_exception - (type, value, stack, 5)))) + self.__logger.error("Error in timer thread:", exc_info=True) self.queue.put(exception) self.__logger.info("Timer thread terminated...") @@ -853,11 +832,9 @@ class JCLComponent(Component, object): result += handler_result break except Exception, e: - error_type, value, stack = sys.exc_info() self.__logger.error("Error with handler " + str(handler) + - " with " + str(stanza) + "\n%s\n%s" - % (e, "".join(traceback.format_exception - (error_type, value, stack, 5)))) + " with " + str(stanza) + ": ", + exc_info=True) result += [Message(from_jid=stanza.get_to(), to_jid=stanza.get_from(), stanza_type="error", @@ -1067,15 +1044,9 @@ class JCLComponent(Component, object): action) self.send_stanzas(result) except: - type, value, stack = sys.exc_info() self.__logger.error("Error in command " + str(command_node) + - " with " + str(info_query) + "\n%s" - % ("".join(traceback.format_exception - (type, value, stack, 5)))) - print("Error in command " + str(command_node) + - " with " + str(info_query) + "\n%s" - % ("".join(traceback.format_exception - (type, value, stack, 5)))) + " with " + str(info_query) + ":", + exc_info=True) return 1 ########################################################################### @@ -1084,10 +1055,7 @@ class JCLComponent(Component, object): def send_error(self, _account, exception): """ """ self.send_stanzas(self.account_manager.send_error_from_account(_account, exception)) - type, value, stack = sys.exc_info() - self.__logger.debug("Error: %s\n%s" - % (exception, "".join(traceback.format_exception - (type, value, stack, 5)))) + self.__logger.debug("Error: ", exc_info=True) def get_config_parameter(self, section, parameter): if self.config is not None \ @@ -1159,4 +1127,3 @@ class JCLComponent(Component, object): Called regularly """ raise NotImplementedError - diff --git a/src/jcl/jabber/presence.py b/src/jcl/jabber/presence.py index f9be953..07afb30 100644 --- a/src/jcl/jabber/presence.py +++ b/src/jcl/jabber/presence.py @@ -69,7 +69,7 @@ class DefaultUnsubscribeHandler(Handler): class AccountPresenceHandler(Handler): filter = jabber.get_account_filter - + def get_account_presence(self, stanza, lang_class, _account): raise NotImplemented @@ -82,15 +82,8 @@ class AccountPresenceHandler(Handler): class AccountPresenceAvailableHandler(AccountPresenceHandler): def get_account_presence(self, stanza, lang_class, _account): - show_status = account.ONLINE - if _account.error is not None: - show_status = account.DND - elif not _account.enabled: - show_status = account.XA - return self.component.account_manager.send_presence_available(\ - _account, - show_status, - lang_class) + return self.component.account_manager.get_account_presence_available(\ + _account, lang_class) class RootPresenceHandler(AccountPresenceHandler): filter = jabber.get_accounts_root_filter @@ -109,15 +102,16 @@ class RootPresenceHandler(AccountPresenceHandler): if accounts_length > 0: result.extend(self.get_root_presence(stanza, lang_class, accounts_length)) return result - + class RootPresenceAvailableHandler(RootPresenceHandler, AccountPresenceAvailableHandler): def get_root_presence(self, stanza, lang_class, nb_accounts): from_jid = stanza.get_from() - result = self.component.account_manager.send_root_presence(from_jid, - "available", - "online", - str(nb_accounts) + - lang_class.message_status) + result = self.component.account_manager.get_root_presence(\ + from_jid, + "available", + "online", + str(nb_accounts) + + lang_class.message_status) user = account.get_user(unicode(from_jid.bare())) if not user.has_received_motd: user.has_received_motd = True @@ -127,16 +121,17 @@ class RootPresenceAvailableHandler(RootPresenceHandler, AccountPresenceAvailable to_jid=from_jid, body=motd)) return result - + class AccountPresenceUnavailableHandler(AccountPresenceHandler): def get_account_presence(self, stanza, lang_class, _account): - return self.component.account_manager.send_presence_unavailable(_account) + return self.component.account_manager.get_account_presence_unavailable(\ + _account) -class RootPresenceUnavailableHandler(RootPresenceHandler, AccountPresenceUnavailableHandler): +class RootPresenceUnavailableHandler(RootPresenceHandler, AccountPresenceUnavailableHandler): def get_root_presence(self, stanza, lang_class, nb_accounts): - return self.component.account_manager.send_root_presence(stanza.get_from(), - "unavailable") + return self.component.account_manager.get_root_presence(\ + stanza.get_from(), "unavailable") class AccountPresenceSubscribeHandler(Handler): """""" diff --git a/src/jcl/jabber/tests/command.py b/src/jcl/jabber/tests/command.py index 251ed5f..38bac63 100644 --- a/src/jcl/jabber/tests/command.py +++ b/src/jcl/jabber/tests/command.py @@ -423,14 +423,14 @@ class CommandManager_TestCase(unittest.TestCase): def test_multi_step_command_error_in_command(self): """ - Test if the multi steps method catch the CommandError exception + Test if the multi steps method catch the CommandError exception and translate it into an IQ error """ self.command_manager = MockCommandManager() def execute_command1(info_query, session_context, command_node, lang_class): raise CommandError("feature-not-implemented") - + self.command_manager.__dict__["execute_command1_1"] = execute_command1 info_query = Iq(stanza_type="set", from_jid="user@test.com", @@ -442,7 +442,7 @@ class CommandManager_TestCase(unittest.TestCase): info_query, "command1", None) result_iq = result[0].xmlnode self.assertTrue(jcl.tests.is_xml_equal(\ - u"" + "" + "" - + "service will be restarted in 0 second", + + "service will be restarted in 1 second", result_iq, True, test_sibling=False)) result_iq = result[2].xmlnode self.assertTrue(jcl.tests.is_xml_equal(\ u"" - + "service will be restarted in 0 second", + + "service will be restarted in 1 second", result_iq, True, test_sibling=False)) context_session = self.command_manager.sessions[session_id][1] self.assertEquals(context_session["announcement"], - ["service will be restarted in 0 second"]) + ["service will be restarted in 1 second"]) self.assertEquals(context_session["delay"], - ["0"]) + ["1"]) def test_execute_restart_no_announcement(self): session_id = self._common_execute_restart() @@ -3059,7 +3059,7 @@ class JCLCommandManagerRestartCommand_TestCase(JCLCommandManagerTestCase): from_jid="admin@test.com", fields=[Field(field_type="list-multi", name="delay", - value=[0])]) + value=[1])]) result = self.command_manager.apply_command_action(\ info_query, "http://jabber.org/protocol/admin#restart", @@ -3085,7 +3085,7 @@ class JCLCommandManagerRestartCommand_TestCase(JCLCommandManagerTestCase): context_session = self.command_manager.sessions[session_id][1] self.assertFalse(context_session.has_key("announcement")) self.assertEquals(context_session["delay"], - ["0"]) + ["1"]) class JCLCommandManagerShutdownCommand_TestCase(JCLCommandManagerTestCase): """ @@ -3154,10 +3154,10 @@ class JCLCommandManagerShutdownCommand_TestCase(JCLCommandManagerTestCase): from_jid="admin@test.com", fields=[Field(field_type="list-multi", name="delay", - value=[0]), + value=[1]), Field(field_type="text-multi", name="announcement", - value=["service will be shutdown in 0 second"])]) + value=["service will be shutdown in 1 second"])]) result = self.command_manager.apply_command_action(\ info_query, "http://jabber.org/protocol/admin#shutdown", @@ -3185,20 +3185,20 @@ class JCLCommandManagerShutdownCommand_TestCase(JCLCommandManagerTestCase): u"" - + "service will be shutdown in 0 second", + + "service will be shutdown in 1 second", result_iq, True, test_sibling=False)) result_iq = result[2].xmlnode self.assertTrue(jcl.tests.is_xml_equal(\ u"" - + "service will be shutdown in 0 second", + + "service will be shutdown in 1 second", result_iq, True, test_sibling=False)) context_session = self.command_manager.sessions[session_id][1] self.assertEquals(context_session["announcement"], - ["service will be shutdown in 0 second"]) + ["service will be shutdown in 1 second"]) self.assertEquals(context_session["delay"], - ["0"]) + ["1"]) def test_execute_shutdown_no_announcement(self): session_id = self._common_execute_shutdown() @@ -3321,8 +3321,8 @@ def suite(): return test_suite if __name__ == '__main__': + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler()) if '-v' in sys.argv: - logger = logging.getLogger() - logger.addHandler(logging.StreamHandler()) logger.setLevel(logging.INFO) unittest.main(defaultTest='suite') diff --git a/src/jcl/jabber/tests/component.py b/src/jcl/jabber/tests/component.py index 5a34a5d..2dd2b5f 100644 --- a/src/jcl/jabber/tests/component.py +++ b/src/jcl/jabber/tests/component.py @@ -3071,7 +3071,7 @@ class AccountManager_TestCase(JCLTestCase): None) self.account_manager = self.comp.account_manager - def test_send_presence_all(self): + def test_get_presence_all(self): user1 = User(jid="test1@test.com") account11 = Account(user=user1, name="account11", @@ -3086,7 +3086,7 @@ class AccountManager_TestCase(JCLTestCase): account22 = Account(user=user2, name="account22", jid="account22@jcl.test.com") - result = self.account_manager.send_presence_all("unavailable") + result = self.account_manager.get_presence_all("unavailable") self.assertEquals(len(result), 6) self.assertEquals(result[0].get_from(), "jcl.test.com") self.assertEquals(result[0].get_to(), "test1@test.com")