Package conduit :: Module DBus
[hide private]

Source Code for Module conduit.DBus

  1  """ 
  2  DBus related functionality including the DBus interface and utility  
  3  functions 
  4   
  5  Copyright: John Stowers, 2006 
  6  License: GPLv2 
  7  """ 
  8  import os.path 
  9  import dbus 
 10  import dbus.service 
 11  import logging 
 12  log = logging.getLogger("DBus") 
 13   
 14  import conduit 
 15  import conduit.utils as Utils 
 16  import conduit.Conduit as Conduit 
 17  import conduit.SyncSet as SyncSet 
 18   
 19  ERROR = -1 
 20  SUCCESS = 0 
 21   
 22  DEBUG_ALL_CALLS = True 
 23   
 24  APPLICATION_DBUS_IFACE="org.conduit.Application" 
 25  SYNCSET_DBUS_IFACE="org.conduit.SyncSet" 
 26  CONDUIT_DBUS_IFACE="org.conduit.Conduit" 
 27  EXPORTER_DBUS_IFACE="org.conduit.Exporter" 
 28  DATAPROVIDER_DBUS_IFACE="org.conduit.DataProvider" 
 29   
 30  ################################################################################ 
 31  # DBus API Docs 
 32  ################################################################################ 
 33  # 
 34  # ==== Main Application ==== 
 35  # Service               org.conduit.Application 
 36  # Interface             org.conduit.Application 
 37  # Object path           / 
 38  # 
 39  # Methods: 
 40  # BuildConduit(source, sink) 
 41  # BuildExporter(self, sinkKey) 
 42  # ListAllDataProviders 
 43  # GetDataProvider 
 44  # NewSyncSet 
 45  # Quit 
 46  #  
 47  # Signals: 
 48  # DataproviderAvailable(key) 
 49  # DataproviderUnavailable(key) 
 50  # 
 51  # ==== SyncSet ==== 
 52  # Service               org.conduit.SyncSet 
 53  # Interface             org.conduit.SyncSet 
 54  # Object path           /syncset/{dbus, gui, UUID} 
 55  # 
 56  # Methods: 
 57  # AddConduit 
 58  # DeleteConduit 
 59  # SaveToXml 
 60  # RestoreFromXml 
 61  #  
 62  # Signals: 
 63  # ConduitAdded(key) 
 64  # ConduitRemoved(key) 
 65  # 
 66  # ==== Conduit ==== 
 67  # Service               org.conduit.Conduit 
 68  # Interface             org.conduit.Conduit 
 69  # Object path           /conduit/{some UUID} 
 70  # 
 71  # Methods: 
 72  # EnableTwoWaySync 
 73  # DisableTwoWaySync 
 74  # IsTwoWay 
 75  # AddDataprovider 
 76  # DeleteDataprovider 
 77  # Sync 
 78  # Refresh 
 79  #  
 80  # Signals: 
 81  # SyncStarted 
 82  # SyncCompleted(aborted, error, conflict) 
 83  # SyncConflict 
 84  # SyncProgress(progress, completedUIDs) 
 85  # DataproviderAdded 
 86  # DataproviderRemoved 
 87  # 
 88  # ==== Exporter Conduit ==== 
 89  # Service               org.conduit.Conduit 
 90  # Interface             org.conduit.Exporter 
 91  # Object path           /conduit/{some UUID} 
 92  # 
 93  # Methods: 
 94  # AddData 
 95  # SinkConfigure 
 96  # SinkGetInformation 
 97  # SinkGetConfigurationXml 
 98  # SinkSetConfigurationXml 
 99  # 
100  # ==== DataProvider ==== 
101  # Service               org.conduit.DataProvider 
102  # Interface             org.conduit.DataProvider 
103  # Object path           /dataprovider/{some UUID} 
104  # 
105  # Methods: 
106  # IsPending 
107  # IsConfigured 
108  # SetConfigurationXML 
109  # GetConfigurationXML 
110  # Configure 
111  # GetInformation 
112  # AddData 
113  #  
114  # Signals: 
115   
116  #All objects currently exported over the bus 
117  EXPORTED_OBJECTS = {} 
118   
119 -class ConduitException(dbus.DBusException):
120 _dbus_error_name = 'org.conduit.ConduitException'
121
122 -class DBusItem(dbus.service.Object):
123 - def __init__(self, iface, path):
124 bus_name = dbus.service.BusName(iface, bus=dbus.SessionBus()) 125 dbus.service.Object.__init__(self, bus_name, path) 126 127 log.debug("DBus Exported: %s" % self.get_path())
128
129 - def get_path(self):
130 return self.__dbus_object_path__
131
132 - def _print(self, message):
133 if DEBUG_ALL_CALLS: 134 log.debug("DBus Message from %s: %s" % (self.get_path(), message))
135
136 -class ConduitDBusItem(DBusItem):
137 - def __init__(self, sync_manager, conduit, uuid):
138 DBusItem.__init__(self, iface=CONDUIT_DBUS_IFACE, path="/conduit/%s" % uuid) 139 140 self.sync_manager = sync_manager 141 self.conduit = conduit 142 143 self.conduit.connect("sync-started", self._on_sync_started) 144 self.conduit.connect("sync-completed", self._on_sync_completed) 145 self.conduit.connect("sync-conflict", self._on_sync_conflict) 146 self.conduit.connect("sync-progress", self._on_sync_progress)
147
148 - def _on_sync_started(self, cond):
149 if cond == self.conduit: 150 self.SyncStarted()
151
152 - def _on_sync_completed(self, cond, aborted, error, conflict):
153 if cond == self.conduit: 154 self.SyncCompleted(bool(aborted), bool(error), bool(conflict))
155
156 - def _on_sync_progress(self, cond, progress, UIDs):
157 if cond == self.conduit: 158 self.SyncProgress(float(progress), UIDs)
159
160 - def _on_sync_conflict(self, cond, conflict):
161 if cond == self.conduit: 162 self.SyncConflict()
163 164 # 165 # org.conduit.Conduit 166 # 167 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='', out_signature='')
168 - def EnableTwoWaySync(self):
169 self._print("EnableTwoWaySync") 170 self.conduit.enable_two_way_sync()
171 172 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='', out_signature='')
173 - def DisableTwoWaySync(self):
174 self._print("DisableTwoWaySync") 175 self.conduit.disable_two_way_sync()
176 177 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='', out_signature='b')
178 - def IsTwoWay(self):
179 self._print("IsTwoWay") 180 return self.conduit.is_two_way()
181 182 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='ob', out_signature='')
183 - def AddDataprovider(self, dp, trySource):
184 self._print("AddDataprovider: %s" % dp) 185 186 #get the actual dps from their object paths 187 try: 188 dpw = EXPORTED_OBJECTS[str(dp)].dataprovider 189 except KeyError, e: 190 raise ConduitException("Could not locate dataprovider: %s" % e) 191 192 if not self.conduit.add_dataprovider(dpw): 193 raise ConduitException("Could not add dataprovider: %s" % e)
194 195 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='o', out_signature='')
196 - def DeleteDataprovider(self, dp):
197 self._print("DeleteDataprovider: %s" % dp) 198 199 #get the actual dps from their object paths 200 try: 201 dpw = EXPORTED_OBJECTS[str(dp)].dataprovider 202 except KeyError, e: 203 raise ConduitException("Could not locate dataprovider: %s" % e) 204 205 if not self.conduit.delete_dataprovider(dpw): 206 raise ConduitException("Could not delete dataprovider: %s" % e)
207 208 209 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='', out_signature='')
210 - def Sync(self):
211 self._print("Sync") 212 self.conduit.sync()
213 214 @dbus.service.method(CONDUIT_DBUS_IFACE, in_signature='', out_signature='')
215 - def Refresh(self):
216 self._print("Refresh") 217 self.conduit.refresh()
218 219 @dbus.service.signal(CONDUIT_DBUS_IFACE, signature='')
220 - def SyncStarted(self):
221 self._print("SyncStarted")
222 223 @dbus.service.signal(CONDUIT_DBUS_IFACE, signature='bbb')
224 - def SyncCompleted(self, aborted, error, conflict):
225 self._print("SyncCompleted (abort:%s error:%s conflict:%s)" % (aborted,error,conflict))
226 227 @dbus.service.signal(CONDUIT_DBUS_IFACE, signature='')
228 - def SyncConflict(self):
229 self._print("SyncConflict")
230 231 @dbus.service.signal(CONDUIT_DBUS_IFACE, signature='das')
232 - def SyncProgress(self, progress, UIDs):
233 self._print("SyncProgress %s%%\n\t%s" % ((progress*100.0), UIDs))
234 235 # 236 # org.conduit.Exporter 237 # 238 @dbus.service.method(EXPORTER_DBUS_IFACE, in_signature='s', out_signature='')
239 - def SinkSetConfigurationXml(self, xml):
240 self._print("SinkSetConfigurationXml: %s" % xml) 241 if len(self.conduit.datasinks) != 1: 242 raise ConduitException("Simple exporter must only have one sink") 243 self.conduit.datasinks[0].set_configuration_xml(xml)
244 245 @dbus.service.method(EXPORTER_DBUS_IFACE, in_signature='', out_signature='')
246 - def SinkConfigure(self):
247 self._print("SinkConfigure") 248 if len(self.conduit.datasinks) != 1: 249 raise ConduitException("Simple exporter must only have one sink") 250 self.conduit.datasinks[0].configure(None)
251 252 @dbus.service.method(EXPORTER_DBUS_IFACE, in_signature='s', out_signature='b')
253 - def AddData(self, uri):
254 self._print("AddData: %s" % uri) 255 if self.conduit.datasource == None: 256 raise ConduitException("Simple exporter must have a source") 257 258 return self.conduit.datasource.module.add(uri)
259 260 @dbus.service.method(EXPORTER_DBUS_IFACE, in_signature='', out_signature='a{ss}')
261 - def SinkGetInformation(self):
262 self._print("SinkGetInformation") 263 if len(self.conduit.datasinks) != 1: 264 raise ConduitException("Simple exporter must only have one sink") 265 266 #Need to call get_icon so that the icon_name/path is loaded 267 try: 268 self.conduit.datasinks[0].get_icon() 269 except: 270 log.warn("DBus could not lookup dp icon") 271 272 info = {} 273 info["name"] = self.conduit.datasinks[0].name 274 info["description"] = self.conduit.datasinks[0].description 275 info["module_type"] = self.conduit.datasinks[0].module_type 276 info["category"] = self.conduit.datasinks[0].category.name 277 info["in_type"] = self.conduit.datasinks[0].get_input_type() 278 info["out_type"] = self.conduit.datasinks[0].get_output_type() 279 info["classname"] = self.conduit.datasinks[0].classname 280 info["key"] = self.conduit.datasinks[0].get_key() 281 info["enabled"] = str( self.conduit.datasinks[0].enabled) 282 info["UID"] = self.conduit.datasinks[0].get_UID() 283 info["icon_name"] = self.conduit.datasinks[0].icon_name 284 info["icon_path"] = self.conduit.datasinks[0].icon_path 285 return info
286 287 @dbus.service.method(EXPORTER_DBUS_IFACE, in_signature='', out_signature='s')
288 - def SinkGetConfigurationXml(self):
289 self._print("SinkGetConfigurationXml") 290 if len(self.conduit.datasinks) != 1: 291 raise ConduitException("Simple exporter must only have one sink") 292 return self.conduit.datasinks[0].get_configuration_xml()
293
294 -class DataProviderDBusItem(DBusItem):
295 - def __init__(self, dataprovider, uuid):
296 DBusItem.__init__(self, iface=DATAPROVIDER_DBUS_IFACE, path="/dataprovider/%s" % uuid) 297 298 self.dataprovider = dataprovider
299 300 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='', out_signature='b')
301 - def IsPending(self):
302 self._print("IsPending") 303 return self.dataprovider.module == None
304 305 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='bb', out_signature='b')
306 - def IsConfigured(self, isSource, isTwoWay):
307 self._print("IsConfigured") 308 if self.dataprovider.module != None: 309 return self.dataprovider.module.is_configured(isSource, isTwoWay) 310 return False
311 312 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='', out_signature='a{ss}')
313 - def GetInformation(self):
314 self._print("GetInformation") 315 #Need to call get_icon so that the icon_name/path is loaded 316 try: 317 self.dataprovider.get_icon() 318 except: 319 log.warn("DBus could not lookup dp icon") 320 321 info = {} 322 info["name"] = self.dataprovider.name 323 info["description"] = self.dataprovider.description 324 info["module_type"] = self.dataprovider.module_type 325 info["category"] = self.dataprovider.category.name 326 info["in_type"] = self.dataprovider.get_input_type() 327 info["out_type"] = self.dataprovider.get_output_type() 328 info["classname"] = self.dataprovider.classname 329 info["key"] = self.dataprovider.get_key() 330 info["enabled"] = str(self.dataprovider.enabled) 331 info["UID"] = self.dataprovider.get_UID() 332 info["icon_name"] = self.dataprovider.icon_name 333 info["icon_path"] = self.dataprovider.icon_path 334 335 return info
336 337 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='', out_signature='s')
338 - def GetConfigurationXml(self):
339 self._print("GetConfigurationXml") 340 return self.dataprovider.get_configuration_xml()
341 342 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='s', out_signature='')
343 - def SetConfigurationXml(self, xml):
344 self._print("SetConfigurationXml: %s" % xml) 345 self.dataprovider.set_configuration_xml(xml)
346 347 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='', out_signature='')
348 - def Configure(self):
349 self._print("Configure") 350 self.dataprovider.configure(None)
351 352 @dbus.service.method(DATAPROVIDER_DBUS_IFACE, in_signature='s', out_signature='b')
353 - def AddData(self, uri):
354 self._print("AddData: %s" % uri) 355 return self.dataprovider.module.add(uri)
356
357 -class SyncSetDBusItem(DBusItem):
358 - def __init__(self, syncSet, name):
359 DBusItem.__init__(self, iface=SYNCSET_DBUS_IFACE, path="/syncset/%s" % name) 360 361 self.syncSet = syncSet 362 self.syncSet.connect("conduit-added", self._on_conduit_added) 363 self.syncSet.connect("conduit-removed", self._on_conduit_removed)
364
365 - def _on_conduit_added(self, syncset, cond):
366 self.ConduitAdded()
367
368 - def _on_conduit_removed(self, syncset, cond):
369 self.ConduitRemoved()
370 371 @dbus.service.signal(SYNCSET_DBUS_IFACE, signature='')
372 - def ConduitAdded(self):
373 self._print("Emmiting DBus signal ConduitAdded")
374 375 @dbus.service.signal(SYNCSET_DBUS_IFACE, signature='')
376 - def ConduitRemoved(self):
377 self._print("Emmiting DBus signal ConduitRemoved")
378 379 @dbus.service.method(SYNCSET_DBUS_IFACE, in_signature='o', out_signature='')
380 - def AddConduit(self, cond):
381 self._print("AddConduit: %s" % cond) 382 383 try: 384 c = EXPORTED_OBJECTS[str(cond)].conduit 385 except KeyError, e: 386 raise ConduitException("Could not locate Conduit: %s" % e) 387 388 self.syncSet.add_conduit(c)
389 390 @dbus.service.method(SYNCSET_DBUS_IFACE, in_signature='o', out_signature='')
391 - def DeleteConduit(self, cond):
392 self._print("DeleteConduit: %s" % cond) 393 394 try: 395 c = EXPORTED_OBJECTS[str(cond)].conduit 396 except KeyError, e: 397 raise ConduitException("Could not locate Conduit: %s" % e) 398 399 self.syncSet.remove_conduit(c)
400 401 @dbus.service.method(SYNCSET_DBUS_IFACE, in_signature='s', out_signature='')
402 - def SaveToXml(self, path):
403 self._print("SaveToXml: %s" % path) 404 self.syncSet.save_to_xml(os.path.abspath(path))
405 406 @dbus.service.method(SYNCSET_DBUS_IFACE, in_signature='s', out_signature='')
407 - def RestoreFromXml(self, path):
408 self._print("RestoreFromXml: %s" % path) 409 self.syncSet.restore_from_xml(os.path.abspath(path))
410
411 -class DBusInterface(DBusItem):
412 - def __init__(self, conduitApplication, moduleManager, typeConverter, syncManager, guiSyncSet, dbusSyncSet):
413 DBusItem.__init__(self, iface=APPLICATION_DBUS_IFACE, path="/") 414 415 self.conduitApplication = conduitApplication 416 417 #setup the module manager 418 self.moduleManager = moduleManager 419 self.moduleManager.connect("dataprovider-available", self._on_dataprovider_available) 420 self.moduleManager.connect("dataprovider-unavailable", self._on_dataprovider_unavailable) 421 422 #type converter and sync manager 423 self.type_converter = typeConverter 424 self.sync_manager = syncManager 425 426 427 #export the syncsets 428 if guiSyncSet != None: 429 new = SyncSetDBusItem(guiSyncSet, "gui") 430 EXPORTED_OBJECTS[new.get_path()] = new 431 432 if dbusSyncSet != None: 433 new = SyncSetDBusItem(dbusSyncSet, "dbus") 434 EXPORTED_OBJECTS[new.get_path()] = new 435 436 #export myself 437 EXPORTED_OBJECTS[self.get_path()] = self
438
439 - def _get_all_dps(self):
440 datasources = self.moduleManager.get_modules_by_type("source") 441 datasinks = self.moduleManager.get_modules_by_type("sink") 442 twoways = self.moduleManager.get_modules_by_type("twoway") 443 return datasources + datasinks + twoways
444
445 - def _new_syncset(self):
446 ss = SyncSet.SyncSet( 447 moduleManager=self.moduleManager, 448 syncManager=self.sync_manager 449 ) 450 i = Utils.uuid_string() 451 new = SyncSetDBusItem(ss, i) 452 EXPORTED_OBJECTS[new.get_path()] = new 453 return new
454
455 - def _get_dataprovider(self, key):
456 """ 457 Instantiates a new dataprovider (source or sink), storing it 458 appropriately. 459 @param key: Key of the DP to create 460 @returns: The new DP 461 """ 462 dpw = self.moduleManager.get_module_wrapper_with_instance(key) 463 if dpw == None: 464 raise ConduitException("Could not find dataprovider with key: %s" % key) 465 466 i = Utils.uuid_string() 467 new = DataProviderDBusItem(dpw, i) 468 EXPORTED_OBJECTS[new.get_path()] = new 469 return new
470
471 - def _get_conduit(self, source=None, sink=None, sender=None):
472 """ 473 Instantiates a new dataprovider (source or sink), storing it 474 appropriately. 475 @param key: Key of the DP to create 476 @returns: The new DP 477 """ 478 if sender == None: 479 raise ConduitException("Invalid DBus Caller") 480 481 cond = Conduit.Conduit(self.sync_manager) 482 if source != None: 483 if not cond.add_dataprovider(dataprovider_wrapper=source, trySourceFirst=True): 484 raise ConduitException("Error adding source to conduit") 485 if sink != None: 486 if not cond.add_dataprovider(dataprovider_wrapper=sink, trySourceFirst=False): 487 raise ConduitException("Error adding source to conduit") 488 489 i = Utils.uuid_string() 490 new = ConduitDBusItem(self.sync_manager, cond, i) 491 EXPORTED_OBJECTS[new.get_path()] = new 492 return new
493
494 - def _on_dataprovider_available(self, loader, dataprovider):
495 self.DataproviderAvailable(dataprovider.get_key())
496
497 - def _on_dataprovider_unavailable(self, loader, dataprovider):
498 self.DataproviderUnavailable(dataprovider.get_key())
499 500 @dbus.service.signal(APPLICATION_DBUS_IFACE, signature='s')
501 - def DataproviderAvailable(self, key):
502 self._print("Emmiting DBus signal DataproviderAvailable %s" % key)
503 504 @dbus.service.signal(APPLICATION_DBUS_IFACE, signature='s')
505 - def DataproviderUnavailable(self, key):
506 self._print("Emiting DBus signal DataproviderUnavailable %s" % key)
507 508 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='', out_signature='o')
509 - def NewSyncSet(self):
510 self._print("NewSyncSet") 511 return self._new_syncset()
512 513 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='', out_signature='as')
514 - def GetAllDataProviders(self):
515 self._print("GetAllDataProviders") 516 return [i.get_key() for i in self._get_all_dps()]
517 518 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='s', out_signature='o')
519 - def GetDataProvider(self, key):
520 self._print("GetDataProvider: %s" % key) 521 return self._get_dataprovider(key)
522 523 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='oo', out_signature='o', sender_keyword='sender')
524 - def BuildConduit(self, source, sink, sender=None):
525 self._print("BuildConduit (sender: %s:) %s --> %s" % (sender, source, sink)) 526 527 #get the actual dps from their object paths 528 try: 529 source = EXPORTED_OBJECTS[str(source)].dataprovider 530 sink = EXPORTED_OBJECTS[str(sink)].dataprovider 531 except KeyError, e: 532 raise ConduitException("Could not find dataprovider with key: %s" % e) 533 534 return self._get_conduit(source, sink, sender)
535 536 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='s', out_signature='o', sender_keyword='sender')
537 - def BuildExporter(self, key, sender=None):
538 self._print("BuildExporter (sender: %s:) --> %s" % (sender,key)) 539 540 source = self._get_dataprovider("FileSource") 541 sink = self._get_dataprovider(key) 542 543 return self._get_conduit(source.dataprovider, sink.dataprovider, sender)
544 545 @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='', out_signature='')
546 - def Quit(self):
547 if self.conduitApplication != None: 548 self.conduitApplication.Quit()
549