# HG changeset patch # User Goffi # Date 1481664468 -3600 # Node ID f413bfc244586b4099bcc3e0ec4b954a549776bb # Parent 52bd463e6fe7b81ea212b210a73430e649d94ebf bridge, quick_frontend: preparation for async bridge bridge can currently have sync and async methods. This commit prepare the transition to fully async bridges: - a new bridgeConnect method must be called to prepare the bridge - quick app, quick profile manager: changed sync calls to async ones - quick app: bridgeConnect can be called automatically or manually depending on connect_bridge parameter of QuickApp diff -r 52bd463e6fe7 -r f413bfc24458 frontends/src/bridge/dbus_bridge.py --- a/frontends/src/bridge/dbus_bridge.py Sun Dec 04 21:35:23 2016 +0100 +++ b/frontends/src/bridge/dbus_bridge.py Tue Dec 13 22:27:48 2016 +0100 @@ -60,7 +60,8 @@ class Bridge(BridgeFrontend): - def __init__(self): + + def bridgeConnect(self, callback, errback): try: self.sessions_bus = dbus.SessionBus() self.db_object = self.sessions_bus.get_object(const_INT_PREFIX, @@ -72,12 +73,13 @@ except dbus.exceptions.DBusException, e: if e._dbus_error_name in ('org.freedesktop.DBus.Error.ServiceUnknown', 'org.freedesktop.DBus.Error.Spawn.ExecFailed'): - raise BridgeExceptionNoService + errback(BridgeExceptionNoService()) elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) - raise BridgeInitError + errback(BridgeInitError) else: - raise e + errback(e) + callback() #props = self.db_core_iface.getProperties() def register_signal(self, functionName, handler, iface="core"): diff -r 52bd463e6fe7 -r f413bfc24458 frontends/src/quick_frontend/quick_app.py --- a/frontends/src/quick_frontend/quick_app.py Sun Dec 04 21:35:23 2016 +0100 +++ b/frontends/src/quick_frontend/quick_app.py Tue Dec 13 22:27:48 2016 +0100 @@ -54,9 +54,18 @@ def __init__(self, profile): self.profile = profile + self.connected = False self.whoami = None self.notifications = {} # key: bare jid or '' for general, value: notif data + @property + def autodisconnect(self): + try: + autodisconnect = self._autodisconnect + except AttributeError: + autodisconnect = False + return autodisconnect + def plug(self): """Plug the profile to the host""" # we get the essential params @@ -65,12 +74,22 @@ def _plug_profile_jid(self, jid_s): self.whoami = jid.JID(jid_s) # resource might change after the connection + self.bridge.isConnected(self.profile, callback=self._plug_profile_isconnected) + + def _plug_profile_isconnected(self, connected): + self.connected = connected + self.bridge.asyncGetParamA("autodisconnect", "Connection", profile_key=self.profile, + callback=self._plug_profile_autodisconnect, errback=self._getParamError) + + def _plug_profile_autodisconnect(self, autodisconnect): + if C.bool(autodisconnect): + self._autodisconnect = True self.bridge.asyncGetParamA("autoconnect", "Connection", profile_key=self.profile, callback=self._plug_profile_autoconnect, errback=self._getParamError) def _plug_profile_autoconnect(self, value_str): autoconnect = C.bool(value_str) - if autoconnect and not self.bridge.isConnected(self.profile): + if autoconnect and not self.connected: self.host.asyncConnect(self.profile, callback=lambda dummy: self._plug_profile_afterconnect()) else: self._plug_profile_afterconnect() @@ -78,6 +97,7 @@ def _plug_profile_afterconnect(self): # Profile can be connected or not # we get cached data + self.connected = True self.host.bridge.getFeatures(profile_key=self.profile, callback=self._plug_profile_getFeaturesCb, errback=self._plug_profile_getFeaturesEb) def _plug_profile_getFeaturesEb(self, failure): @@ -100,7 +120,7 @@ for key, value in data.iteritems(): self.host.entityDataUpdatedHandler(entity_s, key, value, self.profile) - if not self.bridge.isConnected(self.profile): + if not self.connected: self.host.setPresenceStatus(C.PRESENCE_UNAVAILABLE, '', profile=self.profile) else: @@ -142,8 +162,8 @@ # and we launch frontend specific method self.host.profilePlugged(self.profile) - def _getParamError(self, ignore): - log.error(_("Can't get profile parameter")) + def _getParamError(self, failure): + log.error(_("Can't get profile parameter: {msg}").format(msg=failure)) class ProfilesManager(object): @@ -164,6 +184,9 @@ def __len__(self): return len(self._profiles) + def iteritems(self): + return self._profiles.iteritems() + def plug(self, profile): if profile in self._profiles: raise exceptions.ConflictError('A profile of the name [{}] is already plugged'.format(profile)) @@ -189,10 +212,10 @@ MB_HANDLER = True # Set to False if the frontend doesn't manage microblog AVATARS_HANDLER = True # set to False if avatars are not used - def __init__(self, create_bridge, xmlui, check_options=None): + def __init__(self, bridge_factory, xmlui, check_options=None, connect_bridge=True): """Create a frontend application - @param create_bridge: method to use to create the Bridge + @param bridge_factory: method to use to create the Bridge @param xmlui: xmlui module @param check_options: method to call to check options (usually command line arguments) """ @@ -220,15 +243,19 @@ self.trigger = trigger.TriggerManager() # trigger are used to change the default behaviour ## bridge ## - try: - self.bridge = create_bridge() - except exceptions.BridgeExceptionNoService: - print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) - sys.exit(1) - except exceptions.BridgeInitError: - print(_(u"Can't init bridge")) - sys.exit(1) + self.bridge = bridge_factory() ProfileManager.bridge = self.bridge + if connect_bridge: + self.connectBridge() + + self._notif_id = 0 + self._notifications = OrderedDict() + self.features = None + + def connectBridge(self): + self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb) + + def _bridgeCb(self): self.registerSignal("connected") self.registerSignal("disconnected") self.registerSignal("actionNew") @@ -255,10 +282,15 @@ quick_games.Quiz.registerSignals(self) quick_games.Radiocol.registerSignals(self) - self._notif_id = 0 - self._notifications = OrderedDict() - self.media_dir = self.bridge.getConfig('', 'media_dir') - self.features = None + def _bridgeEb(self, failure): + if isinstance(failure, exceptions.BridgeExceptionNoService): + print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) + sys.exit(1) + elif isinstance(failure, exceptions.BridgeInitError): + print(_(u"Can't init bridge")) + sys.exit(1) + else: + print(_(u"Error while initialising bridge: {}".format(failure))) @property def current_profile(self): @@ -871,11 +903,10 @@ def onExit(self): """Must be called when the frontend is terminating""" to_unplug = [] - for profile in self.profiles: - if self.bridge.isConnected(profile): - if C.bool(self.bridge.getParamA("autodisconnect", "Connection", profile_key=profile)): - #The user wants autodisconnection - self.disconnect(profile) + for profile, profile_manager in self.profiles.iteritems(): + if profile_manager.connected(profile) and profile_manager.autodisconnect: + #The user wants autodisconnection + self.disconnect(profile) to_unplug.append(profile) for profile in to_unplug: self.unplug_profile(profile) diff -r 52bd463e6fe7 -r f413bfc24458 frontends/src/quick_frontend/quick_profile_manager.py --- a/frontends/src/quick_frontend/quick_profile_manager.py Sun Dec 04 21:35:23 2016 +0100 +++ b/frontends/src/quick_frontend/quick_profile_manager.py Tue Dec 13 22:27:48 2016 +0100 @@ -108,15 +108,22 @@ self._autoconnect=False self.host.actionManager(data, callback=authenticate_cb, profile=profile) - for profile_key in profile_keys: - profile = self.host.bridge.getProfileName(profile_key) + def getProfileNameCb(profile): if not profile: + # FIXME: this method is not handling manual mode correclty anymore + # must be thought to be handled asynchronously self._autoconnect = False # manual mode msg = _("Trying to plug an unknown profile key ({})".format(profile_key)) log.warning(msg) - self.showDialog(_("Profile plugging in error"), msg, 'error') - break - self.host.launchAction(C.AUTHENTICATE_PROFILE_ID, callback=authenticate_cb, profile=profile) + self.host.showDialog(_("Profile plugging in error"), msg, 'error') + else: + self.host.launchAction(C.AUTHENTICATE_PROFILE_ID, callback=authenticate_cb, profile=profile) + + def getProfileNameEb(failure): + log.error(u"Can't retrieve profile name: {}".format(failure)) + + for profile_key in profile_keys: + self.host.bridge.getProfileName(profile_key, callback=getProfileNameCb, errback=getProfileNameEb) def getParamError(self, dummy): diff -r 52bd463e6fe7 -r f413bfc24458 src/bridge/bridge_constructor/base_constructor.py --- a/src/bridge/bridge_constructor/base_constructor.py Sun Dec 04 21:35:23 2016 +0100 +++ b/src/bridge/bridge_constructor/base_constructor.py Tue Dec 13 22:27:48 2016 +0100 @@ -176,7 +176,7 @@ @param name: dictionary of arguments name like given by getArgumentsDoc @param default: dictionary of default values, like given by getDefault @param unicode_protect: activate unicode protection on strings (return strings as unicode(str)) - @return: list of arguments that correspond to a signature (e.g.: "sss" return "arg1, arg2, arg3") + @return (str): arguments that correspond to a signature (e.g.: "sss" return "arg1, arg2, arg3") """ idx = 0 attr_string = [] diff -r 52bd463e6fe7 -r f413bfc24458 src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py --- a/src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py Sun Dec 04 21:35:23 2016 +0100 +++ b/src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py Tue Dec 13 22:27:48 2016 +0100 @@ -60,7 +60,8 @@ class Bridge(BridgeFrontend): - def __init__(self): + + def bridgeConnect(self, callback, errback): try: self.sessions_bus = dbus.SessionBus() self.db_object = self.sessions_bus.get_object(const_INT_PREFIX, @@ -72,12 +73,13 @@ except dbus.exceptions.DBusException, e: if e._dbus_error_name in ('org.freedesktop.DBus.Error.ServiceUnknown', 'org.freedesktop.DBus.Error.Spawn.ExecFailed'): - raise BridgeExceptionNoService + errback(BridgeExceptionNoService()) elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) - raise BridgeInitError + errback(BridgeInitError) else: - raise e + errback(e) + callback() #props = self.db_core_iface.getProperties() def register_signal(self, functionName, handler, iface="core"): diff -r 52bd463e6fe7 -r f413bfc24458 src/bridge/bridge_constructor/constructors/embedded/embedded_template.py --- a/src/bridge/bridge_constructor/constructors/embedded/embedded_template.py Sun Dec 04 21:35:23 2016 +0100 +++ b/src/bridge/bridge_constructor/constructors/embedded/embedded_template.py Tue Dec 13 22:27:48 2016 +0100 @@ -31,6 +31,9 @@ "plugin": {} } + def bridgeConnect(self, callback, errback): + callback() + def register_method(self, name, callback): log.debug(u"registering embedded bridge method [{}]".format(name)) if name in self._methods_cbs: