diff sat/core/sat_main.py @ 3120:0c29155ac68b

core: backend autoconnection: A new Connection/autoconnect_backend param can be set for a profile or component to be started automatically with backend. This is specially useful for components, but can be useful for client profile too (e.g. on Android we need to start profile with backend to get notifications, this part will come with following commits). The new Sqlite.getIndParamValues method allows to retrieve the same parameters for all profiles.
author Goffi <goffi@goffi.org>
date Sat, 25 Jan 2020 21:08:32 +0100
parents 385fdd684f87
children 130f9cb6e0ab
line wrap: on
line diff
--- a/sat/core/sat_main.py	Sat Jan 25 21:08:29 2020 +0100
+++ b/sat/core/sat_main.py	Sat Jan 25 21:08:32 2020 +0100
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# -*- coding: utf-8 -*-
 
 # SAT: a jabber client
 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
@@ -22,7 +21,7 @@
 import os.path
 import uuid
 import sat
-from sat.core.i18n import _, languageSwitch
+from sat.core.i18n import _, D_, languageSwitch
 from sat.core import patches
 patches.apply()
 from twisted.application import service
@@ -172,7 +171,7 @@
         self.bridge.register_method("imageCheck", self._imageCheck)
         self.bridge.register_method("imageResize", self._imageResize)
 
-        self.memory.initialized.addCallback(self._postMemoryInit)
+        self.memory.initialized.addCallback(lambda __: defer.ensureDeferred(self._postMemoryInit()))
 
     @property
     def version(self):
@@ -202,7 +201,7 @@
     def bridge_name(self):
         return os.path.splitext(os.path.basename(self.bridge.__file__))[0]
 
-    def _postMemoryInit(self, ignore):
+    async def _postMemoryInit(self):
         """Method called after memory initialization is done"""
         self.common_cache = cache.Cache(self, None)
         log.info(_("Memory initialised"))
@@ -218,9 +217,37 @@
             )
             sys.exit(1)
         self._addBaseMenus()
+
         self.initialised.callback(None)
         log.info(_("Backend is ready"))
 
+        # profile autoconnection must be done after self.initialised is called because
+        # startSession waits for it.
+        autoconnect_dict = await self.memory.storage.getIndParamValues(
+            category='Connection', name='autoconnect_backend',
+        )
+        profiles_autoconnect = [p for p, v in autoconnect_dict.items() if C.bool(v)]
+        if not self.trigger.point("profilesAutoconnect", profiles_autoconnect):
+            return
+        if profiles_autoconnect:
+            log.info(D_(
+                "Following profiles will be connected automatically: {profiles}"
+                ).format(profiles= ', '.join(profiles_autoconnect)))
+        connect_d_list = []
+        for profile in profiles_autoconnect:
+            connect_d_list.append(defer.ensureDeferred(self.connect(profile)))
+
+        if connect_d_list:
+            results = await defer.DeferredList(connect_d_list)
+            for idx, (success, result) in enumerate(results):
+                if not success:
+                    profile = profiles_autoconnect[0]
+                    log.warning(
+                        _("Can't autoconnect profile {profile}: {reason}").format(
+                            profile = profile,
+                            reason = result)
+                    )
+
     def _addBaseMenus(self):
         """Add base menus"""
         encryption.EncryptionHandler._importMenus(self)
@@ -407,9 +434,10 @@
 
     def _connect(self, profile_key, password="", options=None):
         profile = self.memory.getProfileName(profile_key)
-        return self.connect(profile, password, options)
+        return defer.ensureDeferred(self.connect(profile, password, options))
 
-    def connect(self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES):
+    async def connect(
+        self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES):
         """Connect a profile (i.e. connect client.component to XMPP server)
 
         Retrieve the individual parameters, authenticate the profile
@@ -427,20 +455,18 @@
         if options is None:
             options = {}
 
-        def connectProfile(__=None):
-            if self.isConnected(profile):
-                log.info(_("already connected !"))
-                return True
+        await self.memory.startSession(password, profile)
+
+        if self.isConnected(profile):
+            log.info(_("already connected !"))
+            return True
 
-            if self.memory.isComponent(profile):
-                d = xmpp.SatXMPPComponent.startConnection(self, profile, max_retries)
-            else:
-                d = xmpp.SatXMPPClient.startConnection(self, profile, max_retries)
-            return d.addCallback(lambda __: False)
+        if self.memory.isComponent(profile):
+            await xmpp.SatXMPPComponent.startConnection(self, profile, max_retries)
+        else:
+            await xmpp.SatXMPPClient.startConnection(self, profile, max_retries)
 
-        d = self.memory.startSession(password, profile)
-        d.addCallback(connectProfile)
-        return d
+        return False
 
     def disconnect(self, profile_key):
         """disconnect from jabber server"""