comparison 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
comparison
equal deleted inserted replaced
3119:790489521b15 3120:0c29155ac68b
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 2
4 # SAT: a jabber client 3 # SAT: a jabber client
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) 4 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
6 5
7 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
20 from glob import glob 19 from glob import glob
21 import sys 20 import sys
22 import os.path 21 import os.path
23 import uuid 22 import uuid
24 import sat 23 import sat
25 from sat.core.i18n import _, languageSwitch 24 from sat.core.i18n import _, D_, languageSwitch
26 from sat.core import patches 25 from sat.core import patches
27 patches.apply() 26 patches.apply()
28 from twisted.application import service 27 from twisted.application import service
29 from twisted.internet import defer 28 from twisted.internet import defer
30 from twisted.words.protocols.jabber import jid 29 from twisted.words.protocols.jabber import jid
170 self.bridge.register_method("sessionInfosGet", self.getSessionInfos) 169 self.bridge.register_method("sessionInfosGet", self.getSessionInfos)
171 self.bridge.register_method("namespacesGet", self.getNamespaces) 170 self.bridge.register_method("namespacesGet", self.getNamespaces)
172 self.bridge.register_method("imageCheck", self._imageCheck) 171 self.bridge.register_method("imageCheck", self._imageCheck)
173 self.bridge.register_method("imageResize", self._imageResize) 172 self.bridge.register_method("imageResize", self._imageResize)
174 173
175 self.memory.initialized.addCallback(self._postMemoryInit) 174 self.memory.initialized.addCallback(lambda __: defer.ensureDeferred(self._postMemoryInit()))
176 175
177 @property 176 @property
178 def version(self): 177 def version(self):
179 """Return the short version of SàT""" 178 """Return the short version of SàT"""
180 return C.APP_VERSION 179 return C.APP_VERSION
200 199
201 @property 200 @property
202 def bridge_name(self): 201 def bridge_name(self):
203 return os.path.splitext(os.path.basename(self.bridge.__file__))[0] 202 return os.path.splitext(os.path.basename(self.bridge.__file__))[0]
204 203
205 def _postMemoryInit(self, ignore): 204 async def _postMemoryInit(self):
206 """Method called after memory initialization is done""" 205 """Method called after memory initialization is done"""
207 self.common_cache = cache.Cache(self, None) 206 self.common_cache = cache.Cache(self, None)
208 log.info(_("Memory initialised")) 207 log.info(_("Memory initialised"))
209 try: 208 try:
210 self._import_plugins() 209 self._import_plugins()
216 reason=str(e).decode("utf-8", "ignore") 215 reason=str(e).decode("utf-8", "ignore")
217 ) 216 )
218 ) 217 )
219 sys.exit(1) 218 sys.exit(1)
220 self._addBaseMenus() 219 self._addBaseMenus()
220
221 self.initialised.callback(None) 221 self.initialised.callback(None)
222 log.info(_("Backend is ready")) 222 log.info(_("Backend is ready"))
223
224 # profile autoconnection must be done after self.initialised is called because
225 # startSession waits for it.
226 autoconnect_dict = await self.memory.storage.getIndParamValues(
227 category='Connection', name='autoconnect_backend',
228 )
229 profiles_autoconnect = [p for p, v in autoconnect_dict.items() if C.bool(v)]
230 if not self.trigger.point("profilesAutoconnect", profiles_autoconnect):
231 return
232 if profiles_autoconnect:
233 log.info(D_(
234 "Following profiles will be connected automatically: {profiles}"
235 ).format(profiles= ', '.join(profiles_autoconnect)))
236 connect_d_list = []
237 for profile in profiles_autoconnect:
238 connect_d_list.append(defer.ensureDeferred(self.connect(profile)))
239
240 if connect_d_list:
241 results = await defer.DeferredList(connect_d_list)
242 for idx, (success, result) in enumerate(results):
243 if not success:
244 profile = profiles_autoconnect[0]
245 log.warning(
246 _("Can't autoconnect profile {profile}: {reason}").format(
247 profile = profile,
248 reason = result)
249 )
223 250
224 def _addBaseMenus(self): 251 def _addBaseMenus(self):
225 """Add base menus""" 252 """Add base menus"""
226 encryption.EncryptionHandler._importMenus(self) 253 encryption.EncryptionHandler._importMenus(self)
227 254
405 defers_list.append(defer.maybeDeferred(unload)) 432 defers_list.append(defer.maybeDeferred(unload))
406 return defers_list 433 return defers_list
407 434
408 def _connect(self, profile_key, password="", options=None): 435 def _connect(self, profile_key, password="", options=None):
409 profile = self.memory.getProfileName(profile_key) 436 profile = self.memory.getProfileName(profile_key)
410 return self.connect(profile, password, options) 437 return defer.ensureDeferred(self.connect(profile, password, options))
411 438
412 def connect(self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES): 439 async def connect(
440 self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES):
413 """Connect a profile (i.e. connect client.component to XMPP server) 441 """Connect a profile (i.e. connect client.component to XMPP server)
414 442
415 Retrieve the individual parameters, authenticate the profile 443 Retrieve the individual parameters, authenticate the profile
416 and initiate the connection to the associated XMPP server. 444 and initiate the connection to the associated XMPP server.
417 @param profile: %(doc_profile)s 445 @param profile: %(doc_profile)s
425 @raise exceptions.PasswordError: Profile password is wrong 453 @raise exceptions.PasswordError: Profile password is wrong
426 """ 454 """
427 if options is None: 455 if options is None:
428 options = {} 456 options = {}
429 457
430 def connectProfile(__=None): 458 await self.memory.startSession(password, profile)
431 if self.isConnected(profile): 459
432 log.info(_("already connected !")) 460 if self.isConnected(profile):
433 return True 461 log.info(_("already connected !"))
434 462 return True
435 if self.memory.isComponent(profile): 463
436 d = xmpp.SatXMPPComponent.startConnection(self, profile, max_retries) 464 if self.memory.isComponent(profile):
437 else: 465 await xmpp.SatXMPPComponent.startConnection(self, profile, max_retries)
438 d = xmpp.SatXMPPClient.startConnection(self, profile, max_retries) 466 else:
439 return d.addCallback(lambda __: False) 467 await xmpp.SatXMPPClient.startConnection(self, profile, max_retries)
440 468
441 d = self.memory.startSession(password, profile) 469 return False
442 d.addCallback(connectProfile)
443 return d
444 470
445 def disconnect(self, profile_key): 471 def disconnect(self, profile_key):
446 """disconnect from jabber server""" 472 """disconnect from jabber server"""
447 # FIXME: client should not be deleted if only disconnected 473 # FIXME: client should not be deleted if only disconnected
448 # it shoud be deleted only when session is finished 474 # it shoud be deleted only when session is finished