comparison sat/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py @ 2562:26edcf3a30eb

core, setup: huge cleaning: - moved directories from src and frontends/src to sat and sat_frontends, which is the recommanded naming convention - move twisted directory to root - removed all hacks from setup.py, and added missing dependencies, it is now clean - use https URL for website in setup.py - removed "Environment :: X11 Applications :: GTK", as wix is deprecated and removed - renamed sat.sh to sat and fixed its installation - added python_requires to specify Python version needed - replaced glib2reactor which use deprecated code by gtk3reactor sat can now be installed directly from virtualenv without using --system-site-packages anymore \o/
author Goffi <goffi@goffi.org>
date Mon, 02 Apr 2018 19:44:50 +0200
parents src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py@0046283a285d
children 779351da2c13
comparison
equal deleted inserted replaced
2561:bd30dc3ffe5a 2562:26edcf3a30eb
1 #!/usr/bin/env python2
2 #-*- coding: utf-8 -*-
3
4 # SAT communication bridge
5 # Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 from sat.core.i18n import _
21 from bridge_frontend import BridgeException
22 import dbus
23 from sat.core.log import getLogger
24 log = getLogger(__name__)
25 from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
26
27 from dbus.mainloop.glib import DBusGMainLoop
28 DBusGMainLoop(set_as_default=True)
29
30 import ast
31
32 const_INT_PREFIX = "org.goffi.SAT" # Interface prefix
33 const_ERROR_PREFIX = const_INT_PREFIX + ".error"
34 const_OBJ_PATH = '/org/goffi/SAT/bridge'
35 const_CORE_SUFFIX = ".core"
36 const_PLUGIN_SUFFIX = ".plugin"
37 const_TIMEOUT = 120
38
39
40 def dbus_to_bridge_exception(dbus_e):
41 """Convert a DBusException to a BridgeException.
42
43 @param dbus_e (DBusException)
44 @return: BridgeException
45 """
46 full_name = dbus_e.get_dbus_name()
47 if full_name.startswith(const_ERROR_PREFIX):
48 name = dbus_e.get_dbus_name()[len(const_ERROR_PREFIX) + 1:]
49 else:
50 name = full_name
51 # XXX: dbus_e.args doesn't contain the original DBusException args, but we
52 # receive its serialized form in dbus_e.args[0]. From that we can rebuild
53 # the original arguments list thanks to ast.literal_eval (secure eval).
54 message = dbus_e.get_dbus_message() # similar to dbus_e.args[0]
55 try:
56 message, condition = ast.literal_eval(message)
57 except (SyntaxError, ValueError, TypeError):
58 condition = ''
59 return BridgeException(name, message, condition)
60
61
62 class Bridge(object):
63
64 def bridgeConnect(self, callback, errback):
65 try:
66 self.sessions_bus = dbus.SessionBus()
67 self.db_object = self.sessions_bus.get_object(const_INT_PREFIX,
68 const_OBJ_PATH)
69 self.db_core_iface = dbus.Interface(self.db_object,
70 dbus_interface=const_INT_PREFIX + const_CORE_SUFFIX)
71 self.db_plugin_iface = dbus.Interface(self.db_object,
72 dbus_interface=const_INT_PREFIX + const_PLUGIN_SUFFIX)
73 except dbus.exceptions.DBusException, e:
74 if e._dbus_error_name in ('org.freedesktop.DBus.Error.ServiceUnknown',
75 'org.freedesktop.DBus.Error.Spawn.ExecFailed'):
76 errback(BridgeExceptionNoService())
77 elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
78 log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
79 errback(BridgeInitError)
80 else:
81 errback(e)
82 callback()
83 #props = self.db_core_iface.getProperties()
84
85 def register_signal(self, functionName, handler, iface="core"):
86 if iface == "core":
87 self.db_core_iface.connect_to_signal(functionName, handler)
88 elif iface == "plugin":
89 self.db_plugin_iface.connect_to_signal(functionName, handler)
90 else:
91 log.error(_('Unknown interface'))
92
93 def __getattribute__(self, name):
94 """ usual __getattribute__ if the method exists, else try to find a plugin method """
95 try:
96 return object.__getattribute__(self, name)
97 except AttributeError:
98 # The attribute is not found, we try the plugin proxy to find the requested method
99
100 def getPluginMethod(*args, **kwargs):
101 # We first check if we have an async call. We detect this in two ways:
102 # - if we have the 'callback' and 'errback' keyword arguments
103 # - or if the last two arguments are callable
104
105 async = False
106 args = list(args)
107
108 if kwargs:
109 if 'callback' in kwargs:
110 async = True
111 _callback = kwargs.pop('callback')
112 _errback = kwargs.pop('errback', lambda failure: log.error(unicode(failure)))
113 try:
114 args.append(kwargs.pop('profile'))
115 except KeyError:
116 try:
117 args.append(kwargs.pop('profile_key'))
118 except KeyError:
119 pass
120 # at this point, kwargs should be empty
121 if kwargs:
122 log.warnings(u"unexpected keyword arguments, they will be ignored: {}".format(kwargs))
123 elif len(args) >= 2 and callable(args[-1]) and callable(args[-2]):
124 async = True
125 _errback = args.pop()
126 _callback = args.pop()
127
128 method = getattr(self.db_plugin_iface, name)
129
130 if async:
131 kwargs['timeout'] = const_TIMEOUT
132 kwargs['reply_handler'] = _callback
133 kwargs['error_handler'] = lambda err: _errback(dbus_to_bridge_exception(err))
134
135 return method(*args, **kwargs)
136
137 return getPluginMethod
138
139 ##METHODS_PART##