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 ###############################################################################
191 class CloudeebusServerProtocol(WampServerProtocol):
192 def onSessionOpen(self):
193 # create cloudeebus service instance
194 self.cloudeebusService = CloudeebusService()
195 # register it for RPC
196 self.registerForRpc(self.cloudeebusService)
197 # register for Publish / Subscribe
198 self.registerForPubSub("", True)
202 ###############################################################################
203 if __name__ == '__main__':
205 if len(sys.argv) == 2:
208 uri = "ws://localhost:" + port
210 factory = WampServerFactory(uri, debugWamp = True)
211 factory.protocol = CloudeebusServerProtocol
212 factory.setProtocolOptions(allowHixie76 = True)
216 DBusGMainLoop(set_as_default=True)