Package conduit :: Package dataproviders :: Module Opensync
[hide private]

Source Code for Module conduit.dataproviders.Opensync

  1  """ 
  2  Interfaces for inter-operation with opensync 
  3   
  4  Copyright: John Stowers, 2006 
  5  License: GPLv2 
  6  """ 
  7  import md5 
  8  import logging 
  9  log = logging.getLogger("dataproviders.Opensync") 
 10   
 11  import conduit 
 12  import conduit.dataproviders.DataProvider as DataProvider 
 13  import conduit.dataproviders.DataProviderCategory as DataProviderCategory 
 14  from conduit.datatypes import Rid 
 15  import conduit.datatypes.Contact as Contact 
 16  import conduit.datatypes.Event as Event 
 17   
 18  try: 
 19      import opensync 
 20  except ImportError: 
 21      raise conduit.Exceptions.NotSupportedError 
 22   
 23  # Create a Format Environment and load plugins in to it 
 24  formats = opensync.FormatEnv() 
 25  formats.load_plugins() 
 26   
 27  # Create a Plugins Environment and load plugins in to it 
 28  plugins = opensync.PluginEnv() 
 29  plugins.load() 
 30   
31 -class BaseDataprovider(DataProvider.TwoWay):
32 """ 33 Generic dataprovider for interfacing with OpenSync plugins 34 35 Maps all Conduit sync calls onto the OpenSync code. HAL and other 36 integration work is left to the DPs that extend this base class. 37 """ 38 39 _module_type_ = "twoway" 40
41 - def __init__(self, *args):
42 DataProvider.TwoWay.__init__(self) 43 44 self.info = None 45 self.data = None 46 self.sink = None 47 self.ctx = None 48 49 for plugin in plugins.plugins: 50 print plugin.name 51 if plugin.name == self._os_name_: 52 self.info = opensync.PluginInfo() 53 self.info.set_config(self._get_config()) 54 self.info.set_format_env(formats) 55 56 self.data = plugin.initialize(self.info) 57 plugin.discover(self.data, self.info) 58 59 for sink in self.info.objtypes: 60 print sink.name 61 if sink.name == self._os_sink_: 62 self.sink = sink 63 self.info.sink = sink 64 65 assert self.info and self.sink 66 67 self.ctx = opensync.Context() 68 self.ctx.set_callback_object(Callbacks(self)) 69 self.uids = None
70
71 - def refresh(self):
72 DataProvider.TwoWay.refresh(self) 73 self.uids = {} 74 self.sink.connect(self.data, self.info, self.ctx)
75
76 - def get_all(self):
77 self.uids = {} 78 self.sink.get_changes(self.data, self.info, self.ctx) 79 return list(self.uids.keys())
80
81 - def get(self, LUID):
82 DataProvider.TwoWay.get(self, LUID) 83 return self.uids[LUID]
84
85 - def put(self, obj, overwrite, LUID=None):
86 DataProvider.TwoWay.put(self, obj, overwrite, LUID) 87 chg = self._object_to_change(obj) 88 89 if overwrite == True and LUID != None: 90 chg.uid = LUID 91 chg.changetype = opensync.CHANGE_TYPE_MODIFIED 92 else: 93 chg.changetype = opensync.CHANGE_TYPE_ADDED 94 95 self.sink.commit_change(self.data, self.info, chg, self.ctx) 96 return Rid(uid=chg.uid, hash=self._get_hash(chg))
97
98 - def delete(self, LUID):
99 print type(LUID) 100 DataProvider.TwoWay.delete(self, LUID) 101 chg = opensync.Change() 102 chg.uid = LUID 103 chg.changetype = opensync.CHANGE_TYPE_DELETED 104 self.sink.commit_change(self.data, self.info, chg, self.ctx)
105
106 - def finish(self, aborted, error, conflict):
107 DataProvider.TwoWay.finish(self) 108 self.uids = None 109 self.sink.disconnect(self.data, self.info, self.ctx)
110
111 - def get_UID(self):
112 return "foobar"
113
114 - def _convert(self, data, chgfrom, chgto):
115 """ 116 Invoke an opensync conversion plugin 117 """ 118 if chgfrom == chgto: 119 return data 120 121 formatfrom = formats.find_objformat(chgfrom) 122 formatto = formats.find_objformat(chgto) 123 converter = formats.find_converter(formatfrom, formatto) 124 return converter.invoke(data, "")
125
126 - def _get_hash(self, change):
127 """ 128 If it's valid, return an osync change hash. 129 Otherwise, generate a new one. 130 """ 131 myhash = change.hash 132 if myhash == None or len(myhash) == 0: 133 return md5.md5(change.data.data).hexdigest()
134
135 - def _change_to_object(self, change):
136 """ 137 Map from an opensync data object to a Conduit data object 138 """ 139 raise NotImplementedError
140
141 - def _object_to_change(self, obj):
142 """ 143 Map from a Conduit data object to an opensync data object 144 """ 145 raise NotImplementedError
146
147 - def _get_config(self):
148 """ 149 Generate the config that opensync needs to use this endpoint 150 """ 151 raise NotImplementedError
152 153
154 -class Callbacks(opensync.ContextCallbacks):
155 """ 156 The OpenSync bindings call back into this function as changes are received 157 from the other dataprovider. As they are received, we updated the uids dict. 158 159 Would it be dirty to merge this with the dataprovider base? I think so. 160 """ 161
162 - def __init__(self, dp):
163 self.dp = dp
164
165 - def callback(self, err):
166 log.warn(err)
167
168 - def changes(self, change):
169 self.dp.uids[change.uid] = self.dp._change_to_object(change)
170
171 - def warning(self, warning):
172 log.warn(warning)
173 174
175 -class ContactDataprovider(BaseDataprovider):
176 """ 177 Implement mappings between Conduit vcard and OS vcard 178 """ 179 180 _in_type_ = "contact" 181 _out_type_ = "contact" 182 _icon_ = "contact-new" 183 _osync_type_ = "vcard30" 184
185 - def _change_to_object(self, change):
186 uid = change.uid 187 # FIXME: Shouldn't need to trim the data! 188 data = str(change.data.data)[:-1] 189 contact = Contact.Contact() 190 contact.set_UID(change.uid) 191 contact.set_from_vcard_string(data) 192 # contact.set_hash(self._get_hash(change)) 193 # contact.set_mtime(...) 194 return contact
195
196 - def _object_to_change(self, obj):
197 chg = opensync.Change() 198 chg.format = "vcard30" 199 chg.objtype = "data" 200 format = formats.find_objformat("vcard30") 201 vcard = str(obj.get_vcard_string()) 202 chg.data = opensync.Data(vcard, format) 203 return chg
204
205 -class EventDataprovider(BaseDataprovider):
206 """ 207 Implement mappings between Conduit vevent and OS vevent 208 """ 209 210 _in_type_ = "event" 211 _out_type_ = "event" 212 _icon_ = "contact-new" 213 _osync_type_ = "vevent20" 214
215 - def _change_to_object(self, change):
216 uid = change.uid 217 # FIXME: Shouldn't need to trim the data! 218 data = str(change.data.data)[:-1] 219 event = Event.Event() 220 event.set_UID(uid) 221 event.set_from_ical_string(data) 222 # event.set_hash(self._get_hash(change)) 223 # event.set_mtime(...) 224 return event
225
226 - def _object_to_change(self, obj):
227 chg = opensync.Change() 228 chg.format = "vevent20" 229 chg.objtype = "data" 230 format = formats.find_objformat("vevent20") 231 vcard = str(obj.get_ical_string()) 232 chg.data = opensync.Data(vcard, format) 233 return chg
234