# HG changeset patch # User Goffi # Date 1482074931 -3600 # Node ID e0066920a661c463fb8003265f02de712c0222a9 # Parent 4bc408b549cdb26ed765d71ddf6ad0ea04cb91ed primitivus, jp: dynamic bridge + fixed D-Bus bridge: Primitivus and jp can now load the bridge specified in sat.conf, but they are only working with D-Bus so far (need to change all sync calls to async). Exit code 3 is used for Bridge init error. diff -r 4bc408b549cd -r e0066920a661 frontends/src/bridge/bridge_frontend.py --- a/frontends/src/bridge/bridge_frontend.py Sun Dec 18 16:28:46 2016 +0100 +++ b/frontends/src/bridge/bridge_frontend.py Sun Dec 18 16:28:51 2016 +0100 @@ -19,8 +19,6 @@ class BridgeFrontend(object): - def __init__(self): - print "Bridge frontend initialization" def register(self, functionName, handler): raise NotImplementedError diff -r 4bc408b549cd -r e0066920a661 frontends/src/jp/base.py --- a/frontends/src/jp/base.py Sun Dec 18 16:28:46 2016 +0100 +++ b/frontends/src/jp/base.py Sun Dec 18 16:28:51 2016 +0100 @@ -29,11 +29,11 @@ import locale import os.path import argparse -from gi.repository import GLib from glob import iglob from importlib import import_module from sat_frontends.tools.jid import JID -from sat_frontends.bridge.dbus_bridge import Bridge +from sat.tools import config +from sat.tools.common import dynamic_import from sat.core import exceptions import sat_frontends.jp from sat_frontends.jp.constants import Const as C @@ -41,6 +41,66 @@ import shlex from collections import OrderedDict +## bridge handling +# we get bridge name from conf and initialise the right class accordingly +main_config = config.parseMainConf() +bridge_name = config.getConfig(main_config, '', 'bridge', 'dbus') + + +# TODO: move loops handling in a separated module +if 'dbus' in bridge_name: + from gi.repository import GLib + + + class JPLoop(object): + + def __init__(self): + self.loop = GLib.MainLoop() + + def run(self): + self.loop.run() + + def quit(self): + self.loop.quit() + + def call_later(self, delay, callback, *args): + """call a callback repeatedly + + @param delay(int): delay between calls in ms + @param callback(callable): method to call + if the callback return True, the call will continue + else the calls will stop + @param *args: args of the callbac + """ + GLib.timeout_add(delay, callback, *args) + +else: + print u"can't start jp: only D-Bus bridge is currently handled" + sys.exit(C.EXIT_ERROR) + # FIXME: twisted loop can be used when jp can handle fully async bridges + # from twisted.internet import reactor + + # class JPLoop(object): + + # def run(self): + # reactor.run() + + # def quit(self): + # reactor.stop() + + # def _timeout_cb(self, args, callback, delay): + # ret = callback(*args) + # if ret: + # reactor.callLater(delay, self._timeout_cb, args, callback, delay) + + # def call_later(self, delay, callback, *args): + # delay = float(delay) / 1000 + # reactor.callLater(delay, self._timeout_cb, args, callback, delay) + +if bridge_name == "embedded": + from sat.core import sat_main + sat = sat_main.SAT() + if sys.version_info < (2, 7, 3): # XXX: shlex.split only handle unicode since python 2.7.3 # this is a workaround for older versions @@ -52,8 +112,8 @@ try: import progressbar except ImportError: - log.info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar')) - log.info (_('Progress bar deactivated\n--\n')) + log.info (_(u'ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar')) + log.info (_(u'Progress bar deactivated\n--\n')) progressbar=None #consts @@ -95,18 +155,19 @@ @attribute progress_failure(callable): method to call when progress failed by default display a message """ - try: - self.bridge = 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")) + # FIXME: need_loop should be removed, everything must be async in bridge so + # loop will always be needed + bridge_module = dynamic_import.bridge(bridge_name, 'sat_frontends.bridge') + if bridge_module is None: + log.error(u"Can't import {} bridge".format(bridge_name)) sys.exit(1) + self.bridge = bridge_module.Bridge() + self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb) + + def _bridgeCb(self): self.parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=DESCRIPTION) - self._make_parents() self.add_parser_options() self.subparsers = self.parser.add_subparsers(title=_('Available commands'), dest='subparser_name') @@ -122,6 +183,15 @@ for type_ in C.OUTPUT_TYPES: self._outputs[type_] = OrderedDict() + def _bridgeEb(self, failure): + if isinstance(failure, exceptions.BridgeExceptionNoService): + print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) + elif isinstance(failure, exceptions.BridgeInitError): + print(_(u"Can't init bridge")) + else: + print(_(u"Error while initialising bridge: {}".format(failure))) + sys.exit(C.EXIT_BRIDGE_ERROR) + @property def version(self): return self.bridge.getVersion() @@ -287,7 +357,7 @@ log.info(_("User interruption: good bye")) def _start_loop(self): - self.loop = GLib.MainLoop() + self.loop = JPLoop() self.loop.run() def stop_loop(self): @@ -304,7 +374,7 @@ assert self._need_loop # XXX: python-dbus will show a traceback if we exit in a signal handler # so we use this little timeout trick to avoid it - GLib.timeout_add(0, self.quit, errcode) + self.loop.call_later(0, self.quit, errcode) def quit(self, errcode=0): # first the onQuitCallbacks @@ -437,7 +507,8 @@ def __init__(self, host, name, use_profile=True, use_output=False, need_connect=None, help=None, **kwargs): - """ Initialise CommandBase + """Initialise CommandBase + @param host: Jp instance @param name(unicode): name of the new command @param use_profile(bool): if True, add profile selection/connection commands @@ -453,7 +524,6 @@ progress* signals will be handled - use_verbose(bool): if True, add verbosity option @attribute need_loop(bool): to set by commands when loop is needed - """ self.need_loop = False # to be set by commands when loop is needed try: # If we have subcommands, host is a CommandBase and we need to use host.host @@ -536,7 +606,7 @@ else: if self.host.watch_progress and uid == self.progress_id: self.onProgressStarted(metadata) - GLib.timeout_add(PROGRESS_DELAY, self.progressUpdate) + self.loop.call_later(PROGRESS_DELAY, self.progressUpdate) def progressFinishedHandler(self, uid, metadata, profile): if profile != self.profile: diff -r 4bc408b549cd -r e0066920a661 frontends/src/jp/constants.py --- a/frontends/src/jp/constants.py Sun Dec 18 16:28:46 2016 +0100 +++ b/frontends/src/jp/constants.py Sun Dec 18 16:28:51 2016 +0100 @@ -34,6 +34,7 @@ EXIT_OK = 0 EXIT_ERROR = 1 # generic error, when nothing else match EXIT_BAD_ARG = 2 # arguments given by user are bad + EXIT_BRIDGE_ERROR = 3 # can't connect to bridge EXIT_NOT_FOUND = 16 # an item required by a command was not found EXIT_FILE_NOT_EXE = 126 # a file to be executed was found, but it was not an executable utility (cf. man 1 exit) EXIT_CMD_NOT_FOUND = 127 # a utility to be executed was not found (cf. man 1 exit) diff -r 4bc408b549cd -r e0066920a661 frontends/src/primitivus/primitivus --- a/frontends/src/primitivus/primitivus Sun Dec 18 16:28:46 2016 +0100 +++ b/frontends/src/primitivus/primitivus Sun Dec 18 16:28:51 2016 +0100 @@ -28,7 +28,6 @@ import urwid from urwid.util import is_wide_char from urwid_satext import sat_widgets -from sat_frontends.bridge.dbus_bridge import Bridge from sat_frontends.quick_frontend.quick_app import QuickApp from sat_frontends.quick_frontend import quick_utils from sat_frontends.quick_frontend import quick_chat @@ -41,9 +40,17 @@ from sat_frontends.primitivus.keys import action_key_map as a_key from sat_frontends.primitivus import config from sat_frontends.tools.misc import InputHistory +from sat.tools.common import dynamic_import from sat_frontends.tools import jid import signal import sys +## bridge handling +# we get bridge name from conf and initialise the right class accordingly +main_config = sat_config.parseMainConf() +bridge_name = sat_config.getConfig(main_config, '', 'bridge', 'dbus') +if 'dbus' not in bridge_name: + print(u"only D-Bus bridge is currently supported") + sys.exit(3) class EditBar(sat_widgets.ModalEdit): @@ -276,11 +283,18 @@ AVATAR_HANDLER = False def __init__(self): - QuickApp.__init__(self, create_bridge=Bridge, xmlui=xmlui, check_options=quick_utils.check_options) - + bridge_module = dynamic_import.bridge(bridge_name, 'sat_frontends.bridge') + if bridge_module is None: + log.error(u"Can't import {} bridge".format(bridge_name)) + sys.exit(3) + else: + log.debug(u"Loading {} bridge".format(bridge_name)) + QuickApp.__init__(self, bridge_factory=bridge_module.Bridge, xmlui=xmlui, check_options=quick_utils.check_options, connect_bridge=False) ## main loop setup ## - self.main_widget = ProfileManager(self) - self.loop = urwid.MainLoop(self.main_widget, C.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler) + event_loop = urwid.GLibEventLoop if 'dbus' in bridge_name else urwid.TwistedEventLoop + self.loop = urwid.MainLoop(urwid.SolidFill(), C.PALETTE, event_loop=event_loop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler) + + def onBridgeConnected(self): ##misc setup## self._visible_widgets = set() @@ -302,6 +316,9 @@ sys.stdout.write("\033[?2004h") self._bracketed_mode_set = True + self.loop.widget = self.main_widget = ProfileManager(self) + self.postInit() + @property def visible_widgets(self): return self._visible_widgets @@ -343,8 +360,7 @@ pass def start(self): - self.i = 0 - self.loop.set_alarm_in(0,lambda a,b: self.postInit()) + self.connectBridge() self.loop.run() def postInit(self): @@ -813,5 +829,5 @@ else: log.warning(u"No ContactList widget found for profile {}".format(profile)) -sat = PrimitivusApp() -sat.start() +primitivus = PrimitivusApp() +primitivus.start() diff -r 4bc408b549cd -r e0066920a661 src/bridge/bridge_constructor/constructors/embedded/embedded_template.py --- a/src/bridge/bridge_constructor/constructors/embedded/embedded_template.py Sun Dec 18 16:28:46 2016 +0100 +++ b/src/bridge/bridge_constructor/constructors/embedded/embedded_template.py Sun Dec 18 16:28:51 2016 +0100 @@ -24,7 +24,7 @@ class _Bridge(object): def __init__(self): - log.info(u"Init embedded bridge...") + log.debug(u"Init embedded bridge...") self._methods_cbs = {} self._signals_cbs = { "core": {},