1 ###############################################################################
2 # Copyright 2012 Intel Corporation.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 ###############################################################################
18 import sys, dbus, json
20 from twisted.internet import glib2reactor
21 # Configure the twisted mainloop to be run inside the glib mainloop.
22 # This must be done before importing the other twisted modules
23 glib2reactor.install()
24 from twisted.internet import reactor, defer
26 from autobahn.websocket import listenWS
27 from autobahn.wamp import exportRpc, WampServerFactory, WampServerProtocol
29 from dbus.mainloop.glib import DBusGMainLoop
32 gobject.threads_init()
38 from twisted.python import log
39 log.startLogging(sys.stdout)
43 ###############################################################################
46 for item in list[1:len(list)]:
52 ###############################################################################
53 class DbusSignalHandler:
54 def __init__(self, bus, object, senderName, objectName, interfaceName, signalName):
56 self.id = hashId([senderName, objectName, interfaceName, signalName])
57 # connect dbus proxy object to signal
58 object.connect_to_signal(signalName, self.handleSignal, interfaceName)
61 def handleSignal(self, *args):
62 # publish dbus args under topic hash id
63 factory.dispatch(self.id, json.dumps(args))
66 ###############################################################################
67 class DbusCallHandler:
68 def __init__(self, method, args):
69 # deferred reply to return dbus results
71 self.request = defer.Deferred()
77 # dbus method async call
79 self.method(*self.args, reply_handler=self.dbusSuccess, error_handler=self.dbusError)
83 def dbusSuccess(self, *result):
84 # return JSON string result array
85 self.request.callback(json.dumps(result))
89 def dbusError(self, error):
90 # return dbus error message
91 self.request.errback(error.get_dbus_message())
96 ###############################################################################
97 class CloudeebusService:
100 self.dbusConnexions = {}
102 self.proxyObjects = {}
104 self.proxyMethods = {}
106 self.signalHandlers = {}
108 self.pendingCalls = []
111 def dbusConnexion(self, busName):
112 if not self.dbusConnexions.has_key(busName):
113 if busName == "session":
114 self.dbusConnexions[busName] = dbus.SessionBus()
115 elif busName == "system":
116 self.dbusConnexions[busName] = dbus.SystemBus()
118 raise Exception("Error: invalid bus: %s" % busName)
119 return self.dbusConnexions[busName]
122 def proxyObject(self, bus, serviceName, objectName):
123 id = hashId([serviceName, objectName])
124 if not self.proxyObjects.has_key(id):
125 self.proxyObjects[id] = bus.get_object(serviceName, objectName)
126 return self.proxyObjects[id]
129 def proxyMethod(self, bus, serviceName, objectName, interfaceName, methodName):
130 id = hashId([serviceName, objectName, interfaceName, methodName])
131 if not self.proxyMethods.has_key(id):
132 obj = self.proxyObject(bus, serviceName, objectName)
133 self.proxyMethods[id] = obj.get_dbus_method(methodName, interfaceName)
134 return self.proxyMethods[id]
138 def dbusRegister(self, list):
139 # read arguments list by position
141 raise Exception("Error: expected arguments: bus, sender, object, interface, signal)")
143 # check if a handler exists
144 sigId = hashId(list[1:5])
145 if self.signalHandlers.has_key(sigId):
149 bus = self.dbusConnexion(list[0])
152 object = self.proxyObject(bus, list[1], list[2])
154 # create a handler that will publish the signal
155 dbusSignalHandler = DbusSignalHandler(bus, object, *list[1:5])
156 self.signalHandlers[sigId] = dbusSignalHandler
158 return dbusSignalHandler.id
162 def dbusSend(self, list):
163 # clear pending calls
164 for call in self.pendingCalls:
166 self.pendingCalls.remove(call)
168 # read arguments list by position
170 raise Exception("Error: expected arguments: bus, destination, object, interface, message, [args])")
173 bus = self.dbusConnexion(list[0])
175 # parse JSON arg list
178 args = json.loads(list[5])
181 method = self.proxyMethod(bus, *list[1:5])
183 # use a deferred call handler to manage dbus results
184 dbusCallHandler = DbusCallHandler(method, args)
185 self.pendingCalls.append(dbusCallHandler)
186 return dbusCallHandler.callMethod()
190 def listNames(self, list):
191 # read arguments list by position
193 raise Exception("Error: expected arguments: bus)")
196 bus = self.dbusConnexion(list[0])
198 # return bus names as json array
199 return json.dumps(bus.list_names())
203 ###############################################################################
204 class CloudeebusServerProtocol(WampServerProtocol):
205 def onSessionOpen(self):
206 # create cloudeebus service instance
207 self.cloudeebusService = CloudeebusService()
208 # register it for RPC
209 self.registerForRpc(self.cloudeebusService)
210 # register for Publish / Subscribe
211 self.registerForPubSub("", True)
215 ###############################################################################
216 if __name__ == '__main__':
218 if len(sys.argv) == 2:
221 uri = "ws://localhost:" + port
223 factory = WampServerFactory(uri, debugWamp = True)
224 factory.protocol = CloudeebusServerProtocol
225 factory.setProtocolOptions(allowHixie76 = True)
229 DBusGMainLoop(set_as_default=True)