5 # Copyright 2012 Intel Corporation.
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 # Luc Yriarte <luc.yriarte@intel.com>
20 # Christophe Guiraud <christophe.guiraud@intel.com>
24 import sys, dbus, json
26 from twisted.internet import glib2reactor
27 # Configure the twisted mainloop to be run inside the glib mainloop.
28 # This must be done before importing the other twisted modules
29 glib2reactor.install()
30 from twisted.internet import reactor, defer
32 from autobahn.websocket import listenWS
33 from autobahn.wamp import exportRpc, WampServerFactory, WampCraServerProtocol
35 from dbus.mainloop.glib import DBusGMainLoop
38 gobject.threads_init()
44 from twisted.python import log
45 log.startLogging(sys.stdout)
49 ###############################################################################
52 for item in list[1:len(list)]:
57 ###############################################################################
65 self.dbusConnexions = {}
67 self.signalHandlers = {}
70 def dbusConnexion(self, busName):
71 if not self.dbusConnexions.has_key(busName):
72 if busName == "session":
73 self.dbusConnexions[busName] = dbus.SessionBus()
74 elif busName == "system":
75 self.dbusConnexions[busName] = dbus.SystemBus()
77 raise Exception("Error: invalid bus: %s" % busName)
78 return self.dbusConnexions[busName]
82 ###############################################################################
83 class DbusSignalHandler:
84 def __init__(self, object, senderName, objectName, interfaceName, signalName):
86 self.id = hashId([senderName, objectName, interfaceName, signalName])
87 # connect dbus proxy object to signal
88 self.proxyObject = object
89 self.proxyObject.connect_to_signal(signalName, self.handleSignal, interfaceName)
92 def handleSignal(self, *args):
93 # publish dbus args under topic hash id
94 factory.dispatch(self.id, json.dumps(args))
98 ###############################################################################
99 class DbusCallHandler:
100 def __init__(self, method, args):
101 # deferred reply to return dbus results
103 self.request = defer.Deferred()
108 def callMethod(self):
109 # dbus method async call
111 self.method(*self.args, reply_handler=self.dbusSuccess, error_handler=self.dbusError)
115 def dbusSuccess(self, *result):
116 # return JSON string result array
117 self.request.callback(json.dumps(result))
121 def dbusError(self, error):
122 # return dbus error message
123 self.request.errback(error.get_dbus_message())
128 ###############################################################################
129 class CloudeebusService:
130 def __init__(self, permissions):
131 self.permissions = permissions;
133 self.proxyObjects = {}
135 self.proxyMethods = {}
137 self.pendingCalls = []
140 def proxyObject(self, busName, serviceName, objectName):
141 id = hashId([serviceName, objectName])
142 if not self.proxyObjects.has_key(id):
143 # check permissions, array.index throws exception
144 self.permissions.index(serviceName)
145 bus = cache.dbusConnexion(busName)
146 self.proxyObjects[id] = bus.get_object(serviceName, objectName)
147 return self.proxyObjects[id]
150 def proxyMethod(self, busName, serviceName, objectName, interfaceName, methodName):
151 id = hashId([serviceName, objectName, interfaceName, methodName])
152 if not self.proxyMethods.has_key(id):
153 obj = self.proxyObject(busName, serviceName, objectName)
154 self.proxyMethods[id] = obj.get_dbus_method(methodName, interfaceName)
155 return self.proxyMethods[id]
159 def dbusRegister(self, list):
160 # read arguments list by position
162 raise Exception("Error: expected arguments: bus, sender, object, interface, signal)")
164 # check if a handler exists
165 sigId = hashId(list[1:5])
166 if cache.signalHandlers.has_key(sigId):
169 # get dbus proxy object
170 object = self.proxyObject(list[0], list[1], list[2])
172 # create a handler that will publish the signal
173 dbusSignalHandler = DbusSignalHandler(object, *list[1:5])
174 cache.signalHandlers[sigId] = dbusSignalHandler
176 return dbusSignalHandler.id
180 def dbusSend(self, list):
181 # clear pending calls
182 for call in self.pendingCalls:
184 self.pendingCalls.remove(call)
186 # read arguments list by position
188 raise Exception("Error: expected arguments: bus, destination, object, interface, message, [args])")
190 # parse JSON arg list
193 args = json.loads(list[5])
195 # get dbus proxy method
196 method = self.proxyMethod(list[0], *list[1:5])
198 # use a deferred call handler to manage dbus results
199 dbusCallHandler = DbusCallHandler(method, args)
200 self.pendingCalls.append(dbusCallHandler)
201 return dbusCallHandler.callMethod()
205 ###############################################################################
206 class CloudeebusServerProtocol(WampCraServerProtocol):
209 "cloudeebus": "secret"
213 "com.intel.media-service-upnp",
214 "com.intel.renderer-service-upnp",
215 "org.freedesktop.DBus",
216 "org.freedesktop.DisplayManager",
217 "org.freedesktop.FileManager1",
218 "org.freedesktop.ModemManager",
219 "org.freedesktop.NetworkManager",
220 "org.freedesktop.Notifications",
221 "org.freedesktop.Tracker1",
222 "org.gnome.Nautilus",
224 "org.gnome.ScreenSaver",
230 def onSessionOpen(self):
231 # CRA authentication options
232 self.clientAuthTimeout = 0
233 self.clientAuthAllowAnonymous = True
234 # CRA authentication init
235 WampCraServerProtocol.onSessionOpen(self)
238 def getAuthPermissions(self, key, extra):
239 return json.loads(extra.get("permissions", "[]"))
242 def getAuthSecret(self, key):
243 return self.PASSWD.get(key, None)
246 def onAuthenticated(self, key, permissions):
247 # check authentication key
249 raise Exception("Authentication failed")
250 # check permissions, array.index throws exception
251 for req in permissions:
252 self.WHITELIST.index(req)
253 # create cloudeebus service instance
254 self.cloudeebusService = CloudeebusService(permissions)
255 # register it for RPC
256 self.registerForRpc(self.cloudeebusService)
257 # register for Publish / Subscribe
258 self.registerForPubSub("", True)
261 def connectionLost(self, reason):
262 WampCraServerProtocol.connectionLost(self, reason)
263 if factory.getConnectionCount() == 0:
268 ###############################################################################
269 if __name__ == '__main__':
273 if len(sys.argv) == 2:
276 uri = "ws://localhost:" + port
278 factory = WampServerFactory(uri, debugWamp = True)
279 factory.protocol = CloudeebusServerProtocol
280 factory.setProtocolOptions(allowHixie76 = True)
284 DBusGMainLoop(set_as_default=True)