Merge branch 'agent' of https://github.com/01org/cloudeebus into agent
[contrib/cloudeebus.git] / cloudeebus / cloudeebus.py
1 #!/usr/bin/env python
2
3 # Cloudeebus
4 #
5 # Copyright 2012 Intel Corporation.
6 #
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
10 #
11 # http://www.apache.org/licenses/LICENSE-2.0
12 #
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.
18 #
19 # Luc Yriarte <luc.yriarte@intel.com>
20 # Christophe Guiraud <christophe.guiraud@intel.com>
21 #
22
23
24 import argparse, dbus, json, sys
25
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
31
32 from autobahn.websocket import listenWS
33 from autobahn.wamp import exportRpc, WampServerFactory, WampCraServerProtocol
34
35 from dbus.mainloop.glib import DBusGMainLoop
36
37 import gobject
38 import re
39 import dbus.service
40 gobject.threads_init()
41
42 from dbus import glib
43 glib.init_threads()
44
45 # enable debug log
46 from twisted.python import log
47
48 # XML parser module
49 from xml.etree.ElementTree import XMLParser
50
51 # For debug only
52 import os
53
54 ###############################################################################
55
56 VERSION = "0.3.0"
57 OPENDOOR = False
58 CREDENTIALS = {}
59 WHITELIST = []
60
61 ###############################################################################
62 class DbusCache:
63     '''
64     Global cache of DBus connexions and signal handlers
65     '''
66     def __init__(self):
67         self.dbusConnexions = {}
68         self.signalHandlers = {}
69
70
71     def reset(self):
72         '''
73         Disconnect signal handlers before resetting cache.
74         '''
75         self.dbusConnexions = {}
76         # disconnect signal handlers
77         for key in self.signalHandlers:
78             self.signalHandlers[key].disconnect()
79         self.signalHandlers = {}
80
81
82     def dbusConnexion(self, busName):
83         if not self.dbusConnexions.has_key(busName):
84             if busName == "session":
85                 self.dbusConnexions[busName] = dbus.SessionBus()
86             elif busName == "system":
87                 self.dbusConnexions[busName] = dbus.SystemBus()
88             else:
89                 raise Exception("Error: invalid bus: %s" % busName)
90         return self.dbusConnexions[busName]
91
92
93
94 ###############################################################################
95 class DbusSignalHandler:
96     '''
97     signal hash id as busName#senderName#objectName#interfaceName#signalName
98     '''
99     def __init__(self, busName, senderName, objectName, interfaceName, signalName):
100         self.id = "#".join([busName, senderName, objectName, interfaceName, signalName])
101         # connect handler to signal
102         self.bus = cache.dbusConnexion(busName)
103         self.bus.add_signal_receiver(self.handleSignal, signalName, interfaceName, senderName, objectName)
104         
105     
106     def disconnect(self):
107         names = self.id.split("#")
108         self.bus.remove_signal_receiver(self.handleSignal, names[4], names[3], names[1], names[2])
109
110
111     def handleSignal(self, *args):
112         '''
113         publish dbus args under topic hash id
114         '''
115         factory.dispatch(self.id, json.dumps(args))
116
117
118
119 ###############################################################################
120 class DbusCallHandler:
121     '''
122     deferred reply to return dbus results
123     '''
124     def __init__(self, method, args):
125         self.pending = False
126         self.request = defer.Deferred()
127         self.method = method
128         self.args = args
129
130
131     def callMethod(self):
132         '''
133         dbus method async call
134         '''
135         self.pending = True
136         self.method(*self.args, reply_handler=self.dbusSuccess, error_handler=self.dbusError)
137         return self.request
138
139
140     def dbusSuccess(self, *result):
141         '''
142         return JSON string result array
143         '''
144         self.request.callback(json.dumps(result))
145         self.pending = False
146
147
148     def dbusError(self, error):
149         '''
150         return dbus error message
151         '''
152         self.request.errback(Exception(error.get_dbus_message()))
153         self.pending = False
154
155
156
157 ################################################################################       
158 class exec_code:
159     def __init__(self, globalCtx, localCtx) :
160         self.exec_string = ""
161         self.exec_code = None
162         self.exec_code_valid = 1
163         self.indent_level = 0
164         self.indent_increment = 1
165         self.line = 0
166         self.localCtx = localCtx
167         self.globalCtx = globalCtx
168         
169
170     # __str__ : Return a string representation of the object, for
171     # nice printing.
172     def __str__(self) :
173         return self.exec_string
174
175     def p(self) :
176         print str(self)
177
178     def append_stmt(self, stmt) :
179         self.exec_code_valid = 0
180         self.line += 1
181         if (stmt != "\n"):
182             for x in range(0,self.indent_level):
183                 self.exec_string = self.exec_string + ' '            
184             self.exec_string = self.exec_string + stmt + "\t\t# l:" + str(self.line) + '\n'
185         else:
186             if (stmt == "\n"):
187                 self.exec_string = self.exec_string + "# l:" + str(self.line) + '\n'
188             else:
189                 self.exec_string = self.exec_string + stmt + "\t\t# l:" + str(self.line) + '\n'
190
191     def indent(self) :
192         self.indent_level = self.indent_level + self.indent_increment
193
194     def dedent(self) :
195         self.indent_level = self.indent_level - self.indent_increment
196     
197     # compile : Compile exec_string into exec_code using the builtin
198     # compile function. Skip if already in sync.
199     def compile(self) :
200         if not self.exec_code_valid :
201             self.exec_code = compile(self.exec_string, "<string>", "exec")
202         self.exec_code_valid = True
203
204     def execute(self) :
205         if not self.exec_code_valid :
206             self.compile()
207         exec(self.exec_code, self.globalCtx, self.localCtx)
208
209
210
211 ################################################################################       
212 class XmlCb_Parser: # The target object of the parser
213     maxDepth = 0
214     depth = 0
215     def __init__(self, dynDBusClass):
216         self.dynDBusClass = dynDBusClass
217         
218     def start(self, tag, attrib):   # Called for each opening tag.
219         if (tag == 'node'):
220             return
221         # Set interface name
222         if (tag == 'interface'):
223             self.dynDBusClass.set_interface(attrib['name'])
224             return
225         # Set method name
226         if (tag == 'method'):
227             self.current = tag
228             self.dynDBusClass.def_method(attrib['name'])
229             return
230         if (tag == 'signal'):
231             self.current = tag
232             self.dynDBusClass.def_signal(attrib['name'])
233             return
234
235         # Set signature (in/out & name) for method
236         if (tag == 'arg'):
237             if (self.current == 'method'):
238                 self.dynDBusClass.add_signature(attrib['name'],
239                                                 attrib['direction'],
240                                                 attrib['type'])
241                 return
242             if (self.current == 'signal'):
243                 self.dynDBusClass.add_signature(attrib['name'], 'in',
244                                                 attrib['type'])
245                 return
246     def end(self, tag):             # Called for each closing tag.
247         if (tag == 'method'):
248             self.dynDBusClass.add_dbus_method()
249             self.dynDBusClass.add_body_method()
250             self.dynDBusClass.end_method()
251         if (tag == 'signal'):
252             self.dynDBusClass.add_dbus_signal()
253             self.dynDBusClass.add_body_signal()
254             self.dynDBusClass.end_method()
255            
256     def data(self, data):
257         pass            # We do not need to do anything with data.
258     def close(self):    # Called when all data has been parsed.
259         return self.maxDepth
260
261
262        
263 ################################################################################       
264 class dynDBusClass():
265     def __init__(self, className, globalCtx, localCtx):
266         self.className = className
267         self.xmlCB = XmlCb_Parser(self)
268         self.signature = {}
269         self.class_code = exec_code(globalCtx, localCtx)  
270         self.class_code.indent_increment = 4
271         self.class_code.append_stmt("import dbus")
272         self.class_code.append_stmt("\n")
273         self.class_code.append_stmt("\n")
274         self.class_code.append_stmt("class " + self.className + "(dbus.service.Object):")
275         self.class_code.indent()
276         
277         ## Overload of __init__ method 
278         self.def_method("__init__")
279         self.add_method("bus, callback=None, objName='/sample', busName='org.cloudeebus'")
280         self.add_stmt("self.bus = bus")
281         self.add_stmt("self.objName = objName")
282         self.add_stmt("self.callback = callback")        
283 #        self.add_stmt("dbus.service.Object.__init__(self, conn=bus, object_path=objName, bus_name=busName)")
284         self.add_stmt("dbus.service.Object.__init__(self, conn=bus, bus_name=busName)")
285         self.end_method()
286                
287         ## Create 'add_to_connection' method 
288         self.def_method("add_to_connection")
289         self.add_method("connection=None, path=None")
290         self.add_stmt("dbus.service.Object.add_to_connection(self, connection=self.bus, path=self.objName)")
291         self.end_method()
292                
293         ## Create 'remove_from_connection' method 
294         self.def_method("remove_from_connection")
295         self.add_method("connection=None, path=None")
296         self.add_stmt("dbus.service.Object.remove_from_connection(self, connection=None, path=self.objName)")
297         self.end_method()
298                
299     def createDBusServiceFromXML(self, xml):
300         self.parser = XMLParser(target=self.xmlCB)
301         self.parser.feed(xml)
302         self.parser.close()
303     
304     def set_interface(self, ifName):
305         self.ifName = ifName
306         
307     def def_method(self, methodName):
308         self.methodToAdd = methodName
309         self.signalToAdd = None
310         self.args_str = str()
311         self.signature = {}
312         self.signature['name'] = str()
313         self.signature['in'] = str()                
314         self.signature['out'] = str()                        
315
316     def def_signal(self, signalName):
317         self.methodToAdd = None
318         self.signalToAdd = signalName
319         self.args_str = str()
320         self.signature = {}
321         self.signature['name'] = str()
322         self.signature['in'] = str()                
323         self.signature['out'] = str()                        
324
325     def add_signature(self, name, direction, signature):
326         if (direction == 'in'):
327             self.signature['in'] += signature
328             if (self.signature['name'] != str()):
329                 self.signature['name'] += ", "
330             self.signature['name'] += name
331         if (direction == 'out'):
332             self.signature['out'] = signature                        
333         
334     def add_method(self, args = None, async_success_cb = None, async_err_cb = None):
335         async_cb_str = str()
336         if (self.methodToAdd != None):
337             name = self.methodToAdd
338         else:
339             name = self.signalToAdd
340         if (args != None):
341             self.args_str = args
342         if (async_success_cb != None):
343             async_cb_str = async_success_cb
344         if (async_err_cb != None):
345             if (async_cb_str != str()):
346                 async_cb_str += ", "
347             async_cb_str += async_err_cb
348                         
349         parameters = self.args_str
350         if (async_cb_str != str()):
351             if (parameters != str()):
352                 parameters += ", "
353             parameters +=async_cb_str       
354         
355         if (parameters != str()):
356             self.class_code.append_stmt("def " + name + "(self, %s):" % parameters)               
357         else:
358             self.class_code.append_stmt("def " + name + "(self):")
359         self.class_code.indent()
360         
361     def end_method(self):
362         self.class_code.append_stmt("\n")
363         self.class_code.append_stmt("\n")        
364         self.class_code.dedent()
365         
366     def add_dbus_method(self):
367         decorator = '@dbus.service.method("' + self.ifName + '"'
368         if (self.signature.has_key('in') and self.signature['in'] != str()):
369                 decorator += ", in_signature='" + self.signature['in'] + "'"
370         if (self.signature.has_key('out') and self.signature['out'] != str()):
371                 decorator += ", out_signature='" + self.signature['out'] + "'"
372         decorator += ", async_callbacks=('dbus_async_cb', 'dbus_async_err_cb')"            
373         decorator += ")"
374         self.class_code.append_stmt(decorator)
375         if (self.signature.has_key('name') and self.signature['name'] != str()):
376             self.add_method(self.signature['name'], async_success_cb='dbus_async_cb', async_err_cb='dbus_async_err_cb')
377         else:
378             self.add_method(async_success_cb='dbus_async_cb', async_err_cb='dbus_async_err_cb')
379
380     def add_dbus_signal(self):
381         decorator = '@dbus.service.signal("' + self.ifName + '"'
382         if (self.signature.has_key('in') and self.signature['in'] != str()):
383                 decorator += ", signature='" + self.signature['in'] + "'"
384         decorator += ")"            
385         self.class_code.append_stmt(decorator)
386         if (self.signature.has_key('name') and self.signature['name'] != str()):
387             self.add_method(self.signature['name'])
388         else:
389             self.add_method()
390
391     def add_body_method(self):
392         if (self.methodToAdd != None):
393             self.class_code.append_stmt("print 'In " + self.methodToAdd + "()'")
394             if (self.args_str != str()):
395                 self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', dbus_async_cb, dbus_async_err_cb, %s)" % self.args_str)
396             else:        
397                 self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', dbus_async_cb, dbus_async_err_cb)")
398
399     def add_body_signal(self):
400         self.class_code.append_stmt("return") ## TODO: Remove and fix with code ad hoc
401         self.class_code.append_stmt("\n")
402
403     def add_stmt(self, stmt) :
404         self.class_code.append_stmt(stmt)
405         
406     def declare(self) :
407         self.class_code.execute()
408      
409     def __str__(self) :
410         return self.class_code.exec_string
411
412     # p : Since it is often useful to be able to look at the code
413     # that is generated interactively, this function provides
414     # a shorthand for "print str(some_exec_code_instance)", which
415     # gives a reasonable nice look at the contents of the
416     # exec_code object.
417     def p(self) :
418         print str(self)
419
420
421
422 ###############################################################################
423 class CloudeebusService:
424     '''
425     support for sending DBus messages and registering for DBus signals
426     '''
427     def __init__(self, permissions):
428         self.permissions = permissions;
429         self.proxyObjects = {}
430         self.proxyMethods = {}
431         self.pendingCalls = []
432         self.dynDBusClasses = {} # DBus class source code generated dynamically (a list because one by classname)
433         self.services = {}  # DBus service created
434         self.serviceAgents = {} # Instantiated DBus class previously generated dynamically, for now, one by classname
435         self.servicePendingCalls = {} # JS methods called (and waiting for a Success/error response), containing 'methodId', (successCB, errorCB)
436         self.localCtx = locals()
437         self.globalCtx = globals()
438
439
440     def proxyObject(self, busName, serviceName, objectName):
441         '''
442         object hash id as busName#serviceName#objectName
443         '''
444         id = "#".join([busName, serviceName, objectName])
445         if not self.proxyObjects.has_key(id):
446             if not OPENDOOR:
447                 # check permissions, array.index throws exception
448                 self.permissions.index(serviceName)
449             bus = cache.dbusConnexion(busName)
450             self.proxyObjects[id] = bus.get_object(serviceName, objectName)
451         return self.proxyObjects[id]
452
453
454     def proxyMethod(self, busName, serviceName, objectName, interfaceName, methodName):
455         '''
456         method hash id as busName#serviceName#objectName#interfaceName#methodName
457         '''
458         id = "#".join([busName, serviceName, objectName, interfaceName, methodName])
459         if not self.proxyMethods.has_key(id):
460             obj = self.proxyObject(busName, serviceName, objectName)
461             self.proxyMethods[id] = obj.get_dbus_method(methodName, interfaceName)
462         return self.proxyMethods[id]
463
464
465     @exportRpc
466     def dbusRegister(self, list):
467         '''
468         arguments: bus, sender, object, interface, signal
469         '''
470         if len(list) < 5:
471             raise Exception("Error: expected arguments: bus, sender, object, interface, signal)")
472         
473         if not OPENDOOR:
474             # check permissions, array.index throws exception
475             self.permissions.index(list[1])
476         
477         # check if a handler exists
478         sigId = "#".join(list)
479         if cache.signalHandlers.has_key(sigId):
480             return sigId
481         
482         # create a handler that will publish the signal
483         dbusSignalHandler = DbusSignalHandler(*list)
484         cache.signalHandlers[sigId] = dbusSignalHandler
485         
486         return dbusSignalHandler.id
487
488
489     @exportRpc
490     def dbusSend(self, list):
491         '''
492         arguments: bus, destination, object, interface, message, [args]
493         '''
494         # clear pending calls
495         for call in self.pendingCalls:
496             if not call.pending:
497                 self.pendingCalls.remove(call)
498         
499         if len(list) < 5:
500             raise Exception("Error: expected arguments: bus, destination, object, interface, message, [args])")
501         
502         # parse JSON arg list
503         args = []
504         if len(list) == 6:
505             args = json.loads(list[5])
506         
507         # get dbus proxy method
508         method = self.proxyMethod(*list[0:5])
509         
510         # use a deferred call handler to manage dbus results
511         dbusCallHandler = DbusCallHandler(method, args)
512         self.pendingCalls.append(dbusCallHandler)
513         return dbusCallHandler.callMethod()
514
515
516     @exportRpc
517     def returnMethod(self, list):
518         '''
519         arguments: methodId, success (=true, error otherwise), result (to return)
520         '''
521         methodId = list[0]
522         success = list[1]
523         result = list[2]
524         if (self.servicePendingCalls.has_key(methodId)):
525             cb = self.servicePendingCalls[methodId]
526             if (success):                
527                 successCB = cb["successCB"]
528                 if (result != None):
529                     successCB(result)
530                 else:
531                     successCB()                    
532             else:     
533                 errorCB = cb["errorCB"]        
534                 if (result != None):
535                     errorCB(result)
536                 else:
537                     errorCB()
538             self.servicePendingCalls[methodId] = None
539         else:
540             print "No methodID %s  !!" % (methodId)  
541
542     def jsonEncodeTupleKeyDict(self, data):
543         ndict = dict()
544         # creates new dictionary with the original tuple converted to json string
545         dataLen = len(data)
546         string = ""
547         for index in range(dataLen):
548             for key in data[index]:
549                 value = data[index][key]
550                 print "key=" + key
551                 print "value=" + str(value)
552                 nkey = str(key)
553                 nvalue = ""
554                 print "JSON key=" + nkey
555                 if (isinstance(value, dbus.Array)):
556                     # Searching dbus byte in array...
557                     ValueLen = len(value)
558                     nvalue = []
559                     for indexValue in range(ValueLen):
560                         a = value[indexValue]
561                         if (isinstance(a, dbus.Byte)):
562                             a = int(value[indexValue])
563                             nvalue.append(a)
564                         else:
565                             nvalue = str(value[indexValue])
566                             
567                 print "JSON value=" + str(nvalue)                
568                 ndict[nkey] =  nvalue
569
570         return ndict
571
572     def srvCB(self, name, async_succes_cb, async_error_cb, *args):
573         methodId = self.srvName + "#" + self.agentObjectPath + "#" + name
574         cb = { 'successCB': async_succes_cb, 
575                'errorCB': async_error_cb}
576         self.servicePendingCalls[methodId] = cb
577
578         if (len(args) > 0):
579             print "Received args=%s" % (args)
580         else:                     
581             print "No args received"
582             
583         try:               
584             print "factory.dispatch(methodId=%s, args=%s)" % (methodId, json.dumps(args))                     
585             factory.dispatch(methodId, json.dumps(args))
586             return
587         except Exception, e :
588             print "Error=%s" % (str(e))
589             
590         print "Trying to decode dbus.Dictionnary..."
591         try:
592             params = self.jsonEncodeTupleKeyDict(args)                
593             print "factory.dispatch(methodId=%s, args=%s)" % (methodId, params)                     
594             factory.dispatch(methodId, params)
595             return
596         except Exception, e :
597             print "Error=%s" % (str(e))
598                     
599         print "Trying to pass args as string..."
600         try:               
601             print "factory.dispatch(methodId=%s, args=%s)" % (methodId, str(args))                     
602             factory.dispatch(methodId, str(args))
603             return
604         except Exception, e :
605             print "Error=%s" % (str(e))
606                     
607     @exportRpc
608     def serviceAdd(self, list):
609         '''
610         arguments: busName, srvName
611         '''
612         busName = list[0]
613         self.bus =  cache.dbusConnexion( busName['name'] )
614         self.srvName = list[1]
615         if (self.services.has_key(self.srvName) == False):            
616             self.services[self.srvName] = dbus.service.BusName(name = self.srvName, bus = self.bus)
617         return self.srvName
618
619     @exportRpc
620     def serviceRelease(self, list):
621         '''
622         arguments: busName, srvName
623         '''
624         self.srvName = list[0]
625         if (self.services.has_key(self.srvName) == True):
626             self.services.pop(self.srvName)
627             return self.srvName
628         else:
629             raise Exception(self.srvName + " do not exist")
630                    
631     @exportRpc
632     def serviceAddAgent(self, list):
633         '''
634         arguments: objectPath, xmlTemplate
635         '''
636         self.agentObjectPath = list[0]
637         xmlTemplate = list[1]
638         self.className = re.sub('/', '_', self.agentObjectPath[1:])
639         if (self.dynDBusClasses.has_key(self.className) == False):
640             self.dynDBusClasses[self.className] = dynDBusClass(self.className, self.globalCtx, self.localCtx)
641             self.dynDBusClasses[self.className].createDBusServiceFromXML(xmlTemplate)
642             self.dynDBusClasses[self.className].declare()
643             
644             # For Debug only
645             if (1):
646                 if (1): ## Force deletion
647                     if os.access('./MyDbusClass.py', os.R_OK) == True:
648                         os.remove('./MyDbusClass.py')
649                     
650                     if os.access('./MyDbusClass.py', os.R_OK) == False:
651                         f = open('./MyDbusClass.py', 'w')
652                         f.write(self.dynDBusClasses[self.className].class_code.exec_string)
653                         f.close()
654
655         ## Class already exist, instanciate it if not already instanciated
656         if (self.serviceAgents.has_key(self.className) == False):
657 #            self.dynDBusClasses[self.className].p()
658 #            self.dynDBusClasses[self.className].declare()
659             self.serviceAgents[self.className] = eval(self.className + "(self.bus, callback=self.srvCB, objName=self.agentObjectPath, busName=self.srvName)", self.globalCtx, self.localCtx)
660             
661         self.serviceAgents[self.className].add_to_connection()
662 #        exe_str = "self.serviceAgents['" + self.className +"'].add_to_connection()"
663 #        exec (exe_str, self.globalCtx, self.localCtx)
664         return (self.agentObjectPath)
665                     
666     @exportRpc
667     def serviceDelAgent(self, list):
668         '''
669         arguments: objectPath, xmlTemplate
670         '''
671         agentObjectPath = list[0]
672         className = re.sub('/', '_', agentObjectPath[1:])
673
674         if (self.serviceAgents.has_key(className)):
675             self.serviceAgents[self.className].remove_from_connection()
676             self.serviceAgents.pop(self.className)
677         else:
678             raise Exception(agentObjectPath + " doesn't exist!")
679         
680         return (agentObjectPath)
681                     
682     @exportRpc
683     def getVersion(self):
684         '''
685         return current version string
686         '''
687         return VERSION
688
689
690
691 ###############################################################################
692 class CloudeebusServerProtocol(WampCraServerProtocol):
693     '''
694     connexion and session authentication management
695     '''
696     
697     def onSessionOpen(self):
698         # CRA authentication options
699         self.clientAuthTimeout = 0
700         self.clientAuthAllowAnonymous = OPENDOOR
701         # CRA authentication init
702         WampCraServerProtocol.onSessionOpen(self)
703     
704     
705     def getAuthPermissions(self, key, extra):
706         return json.loads(extra.get("permissions", "[]"))
707     
708     
709     def getAuthSecret(self, key):
710         secret = CREDENTIALS.get(key, None)
711         if secret is None:
712             return None
713         # secret must be of str type to be hashed
714         return secret.encode('utf-8')
715     
716
717     def onAuthenticated(self, key, permissions):
718         if not OPENDOOR:
719             # check authentication key
720             if key is None:
721                 raise Exception("Authentication failed")
722             # check permissions, array.index throws exception
723             for req in permissions:
724                 WHITELIST.index(req)
725         # create cloudeebus service instance
726         self.cloudeebusService = CloudeebusService(permissions)
727         # register it for RPC
728         self.registerForRpc(self.cloudeebusService)
729         # register for Publish / Subscribe
730         self.registerForPubSub("", True)
731     
732     
733     def connectionLost(self, reason):
734         WampCraServerProtocol.connectionLost(self, reason)
735         if factory.getConnectionCount() == 0:
736             cache.reset()
737
738
739
740 ###############################################################################
741
742 if __name__ == '__main__':
743     
744     cache = DbusCache()
745
746     parser = argparse.ArgumentParser(description='Javascript DBus bridge.')
747     parser.add_argument('-v', '--version', action='store_true', 
748         help='print version and exit')
749     parser.add_argument('-d', '--debug', action='store_true', 
750         help='log debug info on standard output')
751     parser.add_argument('-o', '--opendoor', action='store_true',
752         help='allow anonymous access to all services')
753     parser.add_argument('-p', '--port', default='9000',
754         help='port number')
755     parser.add_argument('-c', '--credentials',
756         help='path to credentials file')
757     parser.add_argument('-w', '--whitelist',
758         help='path to whitelist file')
759     
760     args = parser.parse_args(sys.argv[1:])
761
762     if args.version:
763         print("Cloudeebus version " + VERSION)
764         exit(0)
765     
766     if args.debug:
767         log.startLogging(sys.stdout)
768     
769     OPENDOOR = args.opendoor
770     
771     if args.credentials:
772         jfile = open(args.credentials)
773         CREDENTIALS = json.load(jfile)
774         jfile.close()
775     
776     if args.whitelist:
777         jfile = open(args.whitelist)
778         WHITELIST = json.load(jfile)
779         jfile.close()
780     
781     uri = "ws://localhost:" + args.port
782     
783     factory = WampServerFactory(uri, debugWamp = args.debug)
784     factory.protocol = CloudeebusServerProtocol
785     factory.setProtocolOptions(allowHixie76 = True)
786     
787     listenWS(factory)
788     
789     DBusGMainLoop(set_as_default=True)
790     
791     reactor.run()