faf520419b8a176bd571cce98402adf34c073846
[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
52 ###############################################################################
53
54 VERSION = "0.3.0"
55 OPENDOOR = False
56 CREDENTIALS = {}
57 WHITELIST = []
58
59 ###############################################################################
60 class DbusCache:
61     '''
62     Global cache of DBus connexions and signal handlers
63     '''
64     def __init__(self):
65         self.dbusConnexions = {}
66         self.signalHandlers = {}
67
68
69     def reset(self):
70         '''
71         Disconnect signal handlers before resetting cache.
72         '''
73         self.dbusConnexions = {}
74         # disconnect signal handlers
75         for key in self.signalHandlers:
76             self.signalHandlers[key].disconnect()
77         self.signalHandlers = {}
78
79
80     def dbusConnexion(self, busName):
81         if not self.dbusConnexions.has_key(busName):
82             if busName == "session":
83                 self.dbusConnexions[busName] = dbus.SessionBus()
84             elif busName == "system":
85                 self.dbusConnexions[busName] = dbus.SystemBus()
86             else:
87                 raise Exception("Error: invalid bus: %s" % busName)
88         return self.dbusConnexions[busName]
89
90
91
92 ###############################################################################
93 class DbusSignalHandler:
94     '''
95     signal hash id as busName#senderName#objectName#interfaceName#signalName
96     '''
97     def __init__(self, busName, senderName, objectName, interfaceName, signalName):
98         self.id = "#".join([busName, senderName, objectName, interfaceName, signalName])
99         # connect handler to signal
100         self.bus = cache.dbusConnexion(busName)
101         self.bus.add_signal_receiver(self.handleSignal, signalName, interfaceName, senderName, objectName)
102         
103     
104     def disconnect(self):
105         names = self.id.split("#")
106         self.bus.remove_signal_receiver(self.handleSignal, names[4], names[3], names[1], names[2])
107
108
109     def handleSignal(self, *args):
110         '''
111         publish dbus args under topic hash id
112         '''
113         factory.dispatch(self.id, json.dumps(args))
114
115
116
117 ###############################################################################
118 class DbusCallHandler:
119     '''
120     deferred reply to return dbus results
121     '''
122     def __init__(self, method, args):
123         self.pending = False
124         self.request = defer.Deferred()
125         self.method = method
126         self.args = args
127
128
129     def callMethod(self):
130         '''
131         dbus method async call
132         '''
133         self.pending = True
134         self.method(*self.args, reply_handler=self.dbusSuccess, error_handler=self.dbusError)
135         return self.request
136
137
138     def dbusSuccess(self, *result):
139         '''
140         return JSON string result array
141         '''
142         self.request.callback(json.dumps(result))
143         self.pending = False
144
145
146     def dbusError(self, error):
147         '''
148         return dbus error message
149         '''
150         self.request.errback(Exception(error.get_dbus_message()))
151         self.pending = False
152
153
154
155 ################################################################################       
156 class exec_code:
157     def __init__(self, globalCtx, localCtx) :
158         self.exec_string = ""
159         self.exec_code = None
160         self.exec_code_valid = 1
161         self.indent_level = 0
162         self.indent_increment = 1
163         self.line = 0
164         self.localCtx = localCtx
165         self.globalCtx = globalCtx
166         
167
168     # __str__ : Return a string representation of the object, for
169     # nice printing.
170     def __str__(self) :
171         return self.exec_string
172
173     def p(self) :
174         print str(self)
175
176     def append_stmt(self, stmt) :
177         self.exec_code_valid = 0
178         self.line += 1
179         if (stmt != "\n"):
180             for x in range(0,self.indent_level):
181                 self.exec_string = self.exec_string + ' '            
182             self.exec_string = self.exec_string + stmt + "\t\t# l:" + str(self.line) + '\n'
183         else:
184             if (stmt == "\n"):
185                 self.exec_string = self.exec_string + "# l:" + str(self.line) + '\n'
186             else:
187                 self.exec_string = self.exec_string + stmt + "\t\t# l:" + str(self.line) + '\n'
188
189     def indent(self) :
190         self.indent_level = self.indent_level + self.indent_increment
191
192     def dedent(self) :
193         self.indent_level = self.indent_level - self.indent_increment
194     
195     # compile : Compile exec_string into exec_code using the builtin
196     # compile function. Skip if already in sync.
197     def compile(self) :
198         if not self.exec_code_valid :
199             self.exec_code = compile(self.exec_string, "<string>", "exec")
200         self.exec_code_valid = True
201
202     def execute(self) :
203         if not self.exec_code_valid :
204             self.compile()
205         exec(self.exec_code, self.globalCtx, self.localCtx)
206
207
208
209 ################################################################################       
210 class XmlCb_Parser: # The target object of the parser
211     maxDepth = 0
212     depth = 0
213     def __init__(self, dynDBusClass):
214         self.dynDBusClass = dynDBusClass
215         
216     def start(self, tag, attrib):   # Called for each opening tag.
217         if (tag == 'node'):
218             return
219         # Set interface name
220         if (tag == 'interface'):
221             self.dynDBusClass.set_interface(attrib['name'])
222             return
223         # Set method name
224         if (tag == 'method'):
225             self.current = tag
226             self.dynDBusClass.def_method(attrib['name'])
227             return
228         if (tag == 'signal'):
229             self.current = tag
230             self.dynDBusClass.def_signal(attrib['name'])
231             return
232
233         # Set signature (in/out & name) for method
234         if (tag == 'arg'):
235             if (self.current == 'method'):
236                 if (attrib.has_key('direction') == False):
237                     attrib['direction'] = "in"
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" % (str(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         ## Class already exist, instanciate it if not already instanciated
645         if (self.serviceAgents.has_key(self.className) == False):
646             self.serviceAgents[self.className] = eval(self.className + "(self.bus, callback=self.srvCB, objName=self.agentObjectPath, busName=self.srvName)", self.globalCtx, self.localCtx)
647             
648         self.serviceAgents[self.className].add_to_connection()
649         return (self.agentObjectPath)
650                     
651     @exportRpc
652     def serviceDelAgent(self, list):
653         '''
654         arguments: objectPath, xmlTemplate
655         '''
656         agentObjectPath = list[0]
657         className = re.sub('/', '_', agentObjectPath[1:])
658
659         if (self.serviceAgents.has_key(className)):
660             self.serviceAgents[self.className].remove_from_connection()
661             self.serviceAgents.pop(self.className)
662         else:
663             raise Exception(agentObjectPath + " doesn't exist!")
664         
665         return (agentObjectPath)
666                     
667     @exportRpc
668     def getVersion(self):
669         '''
670         return current version string
671         '''
672         return VERSION
673
674
675
676 ###############################################################################
677 class CloudeebusServerProtocol(WampCraServerProtocol):
678     '''
679     connexion and session authentication management
680     '''
681     
682     def onSessionOpen(self):
683         # CRA authentication options
684         self.clientAuthTimeout = 0
685         self.clientAuthAllowAnonymous = OPENDOOR
686         # CRA authentication init
687         WampCraServerProtocol.onSessionOpen(self)
688     
689     
690     def getAuthPermissions(self, key, extra):
691         return json.loads(extra.get("permissions", "[]"))
692     
693     
694     def getAuthSecret(self, key):
695         secret = CREDENTIALS.get(key, None)
696         if secret is None:
697             return None
698         # secret must be of str type to be hashed
699         return secret.encode('utf-8')
700     
701
702     def onAuthenticated(self, key, permissions):
703         if not OPENDOOR:
704             # check authentication key
705             if key is None:
706                 raise Exception("Authentication failed")
707             # check permissions, array.index throws exception
708             for req in permissions:
709                 WHITELIST.index(req)
710         # create cloudeebus service instance
711         self.cloudeebusService = CloudeebusService(permissions)
712         # register it for RPC
713         self.registerForRpc(self.cloudeebusService)
714         # register for Publish / Subscribe
715         self.registerForPubSub("", True)
716     
717     
718     def connectionLost(self, reason):
719         WampCraServerProtocol.connectionLost(self, reason)
720         if factory.getConnectionCount() == 0:
721             cache.reset()
722
723
724
725 ###############################################################################
726
727 if __name__ == '__main__':
728     
729     cache = DbusCache()
730
731     parser = argparse.ArgumentParser(description='Javascript DBus bridge.')
732     parser.add_argument('-v', '--version', action='store_true', 
733         help='print version and exit')
734     parser.add_argument('-d', '--debug', action='store_true', 
735         help='log debug info on standard output')
736     parser.add_argument('-o', '--opendoor', action='store_true',
737         help='allow anonymous access to all services')
738     parser.add_argument('-p', '--port', default='9000',
739         help='port number')
740     parser.add_argument('-c', '--credentials',
741         help='path to credentials file')
742     parser.add_argument('-w', '--whitelist',
743         help='path to whitelist file')
744     
745     args = parser.parse_args(sys.argv[1:])
746
747     if args.version:
748         print("Cloudeebus version " + VERSION)
749         exit(0)
750     
751     if args.debug:
752         log.startLogging(sys.stdout)
753     
754     OPENDOOR = args.opendoor
755     
756     if args.credentials:
757         jfile = open(args.credentials)
758         CREDENTIALS = json.load(jfile)
759         jfile.close()
760     
761     if args.whitelist:
762         jfile = open(args.whitelist)
763         WHITELIST = json.load(jfile)
764         jfile.close()
765     
766     uri = "ws://localhost:" + args.port
767     
768     factory = WampServerFactory(uri, debugWamp = args.debug)
769     factory.protocol = CloudeebusServerProtocol
770     factory.setProtocolOptions(allowHixie76 = True)
771     
772     listenWS(factory)
773     
774     DBusGMainLoop(set_as_default=True)
775     
776     reactor.run()