class ShareAccept(): def __init__(self): print "init" self.sd = SyncDaemonTool() self.detect_shares() @defer.inlineCallbacks def detect_shares(self): print "Detecting shares..." self.sd.refresh_shares() l = yield self.sd.get_shares() for s in l: volume_id = str(s["volume_id"]) if s["accepted"] == "": print "...FOUND NEW SHARE: " + str(s["name"]) + " (" + str( s["volume_id"]) + ")" print "...accepting share: " + volume_id res = yield self.sd.accept_share(volume_id) if s["subscribed"] == "": print "...subscribing to share: " + volume_id sub = yield self.sd.subscribe_share(volume_id) print "...done!" print "Completed." reactor.stop()
class ShareAccept(): def __init__(self): print "init" self.sd = SyncDaemonTool() self.detect_shares() @defer.inlineCallbacks def detect_shares(self): print "Detecting shares..." self.sd.refresh_shares() l = yield self.sd.get_shares() for s in l: volume_id = str(s["volume_id"]) if s["accepted"] == "": print "...FOUND NEW SHARE: " + str(s["name"]) + " (" + str(s["volume_id"]) + ")" print "...accepting share: " + volume_id res = yield self.sd.accept_share(volume_id) if s["subscribed"] == "": print "...subscribing to share: " + volume_id sub = yield self.sd.subscribe_share(volume_id) print "...done!" print "Completed." reactor.stop()
def __init__(self, msd): # magicicada's syncdaemon self.msd = msd logger.info("DBus interface starting") self._public_files_deferred = None # set up dbus and related stuff loop = DBusGMainLoop(set_as_default=True) self._bus = bus = SessionBus(mainloop=loop) self.sync_daemon_tool = SyncDaemonTool(bus) # hook up for signals and store info for the shutdown _signals = [ (self._on_status_changed, 'Status', 'StatusChanged'), (self._on_queue_added, 'Status', 'RequestQueueAdded'), (self._on_queue_removed, 'Status', 'RequestQueueRemoved'), (self._on_upload_progress, 'Status', 'UploadFileProgress'), (self._on_download_progress, 'Status', 'DownloadFileProgress'), (self._on_folder_created, 'Folders', 'FolderCreated'), (self._on_folder_deleted, 'Folders', 'FolderDeleted'), (self._on_folder_subscribed, 'Folders', 'FolderSubscribed'), (self._on_folder_unsubscribed, 'Folders', 'FolderUnSubscribed'), (self._on_share_created, 'Shares', 'ShareCreated'), (self._on_share_deleted, 'Shares', 'ShareDeleted'), (self._on_share_changed, 'Shares', 'ShareChanged'), (self._on_public_files_changed, 'PublicFiles', 'PublicAccessChanged'), ] self._dbus_matches = [] for method, dbus_lastname, signal_name in _signals: if dbus_lastname is None: dbus_interface = None else: dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname match = bus.add_signal_receiver(method, dbus_interface=dbus_interface, signal_name=signal_name) self._dbus_matches.append((match, dbus_interface, signal_name))
def __init__(self, success_callback, failure_callback): self.success_callback = success_callback self.failure_callback = failure_callback self.path = None if SyncDaemonTool: self.sd = SyncDaemonTool(bus=dbus.SessionBus())
class Uploader(object): def __init__(self, success_callback, failure_callback): self.success_callback = success_callback self.failure_callback = failure_callback self.path = None if SyncDaemonTool: self.sd = SyncDaemonTool(bus=dbus.SessionBus()) def uploadFile(self, path): self.path = path if not SyncDaemonTool: failure_callback(path, "Could not find Ubuntu One library (python-ubuntuone-client)") return # First, confirm Ubuntu One is connected d = self.sd.get_status() d.addErrback(self.__failure) d.addCallback(self.__got_status) def __failure(self, *args): self.failure_callback(self.path, "Problem uploading to Ubuntu One: %s" % str(args)) def __got_status(self, state): if state["is_online"]: self.__copy_file() else: # not online, so try to connect self.sig_status_changed = self.sd.bus.add_signal_receiver( handler_function=self.__status_changed, signal_name="StatusChanged", dbus_interface=DBUS_IFACE_STATUS_NAME, path='/status') d = self.sd.connect() d.addErrback(self.__failure) def __status_changed(self, status): if status["is_online"]: # We are connected; continue self.sig_status_changed.remove() self.__copy_file() return if status["is_error"]: # We are not connected, and not going to be without user fixes self.sig_status_changed.remove() self.__failure("Could not connect to Ubuntu One") return def __copy_file(self): # First, create a folder to put the copy of the specified file in fol = os.path.expanduser("~/Ubuntu One/Gwibber Uploads") try: os.makedirs(fol) except OSError: if not os.path.isdir(fol): self.__failure("Could not create Gwibber Uploads folder in Ubuntu One") return # OSError is OK if the folder already existed fdir, ffullname = os.path.split(self.path) fname, fext = os.path.splitext(ffullname) src = gio.File(self.path) dest = gio.File(os.path.join(fol, ffullname)) # We connect to the UploadFinished signal from syncdaemon here, # before we even copy the file, so we know that it's right. self.sig_upload_finished = self.sd.bus.add_signal_receiver( handler_function=self.__file_uploaded, signal_name="UploadFinished", dbus_interface=DBUS_IFACE_STATUS_NAME, path='/status') try: src.copy(dest) except gio.Error: # file with this name exists. Try creating a file with a number in differentiator = 1 while 1: try: dest = gio.File(os.path.join(fol, "%s (%s)%s" % (fname, differentiator, fext))) src.copy(dest) except gio.Error: differentiator += 1 else: break self.u1path = dest.get_path() # the actual path in ~/Ubuntu One def __file_uploaded(self, path, info): if path == self.u1path: # stop listening to the signal self.sig_upload_finished.remove() # publish the file d = self.sd.change_public_access(path, True) d.addCallback(self.__published) d.addErrback(self.__failure) def __published(self, info): self.success_callback(self.path, info["public_url"])
def initWithDelegate_(self, delegate): self = super(U1FinderLib, self).init() self.sync_daemon_tool = SyncDaemonTool(None) self.delegate = delegate cfreactor.install() return self
class U1FinderLib(NSObject): ## # Default constructor. @objc.typedSelector('@@:@') def initWithDelegate_(self, delegate): self = super(U1FinderLib, self).init() self.sync_daemon_tool = SyncDaemonTool(None) self.delegate = delegate cfreactor.install() return self ## # Returns the list of the shared volumes in a NSArray<NSString>. Example: # # [ # @"/Users/jose/Ubuntu One", # @"/Users/jose/Pictures" # ] @objc.typedSelector('v@:') def volumeList(self): d = self.sync_daemon_tool.get_folders() d.addCallback(lambda r: volume_list(r, self.delegate)) return None ## # Returns a NSArray<NSString> whit all the files that are being uploaded. Example: # [ # @"/Users/jose/Ubuntu One/Document.pdf", # @"/Users/jose/Pictures/Image.png" # } @objc.typedSelector('v@:') def currentUploads(self): d = self.sync_daemon_tool.get_current_uploads() d.addCallback(lambda r: get_uploads(r, self.delegate)) return None ## # Like currentUploads() but with the downloads. @objc.typedSelector('v@:') def currentDownloads(self): d = self.sync_daemon_tool.get_current_downloads() d.addCallback(lambda r: get_downloads(r, self.delegate)) return None ## # Indicates if the specified file is public or not. @objc.typedSelector('@@:@') def isFilePublic_(self, filePath): d = self.sync_daemon_tool.get_public_files() d.addCallback(lambda r: file_is_public(r, filePath, self.delegate)) return None ## # Publish or unpublish the specified file. @objc.typedSelector('v@:@B') def changeFile_visibillity_(self, filePath, isPublic): self.sync_daemon_tool.change_public_access(os.path.abspath(filePath), isPublic) return None ## # Returns the link (NSString) of a public file or nil if the file is not public. @objc.typedSelector('@@:@') def getPublicLinkOfFile_(self, filePath): d = self.sync_daemon_tool.get_public_files() d.addCallback(lambda r: get_public_files(r, filePath, self.delegate)) return None ## # Synchronizes the specified folder @objc.typedSelector('@@:@') def synchronizeFolderAtPath_(self, folderPath): d = self.sync_daemon_tool.create_folder(os.path.abspath(folderPath)) d.addCallback(lambda r: folder_synchronized(r, self.delegate)) return None ## # Unsuscribes the specified folder. @objc.typedSelector('@@:@') def unsuscribeFolderAtPath_(self, folderPath): d = self.sync_daemon_tool.get_folders() d.addCallback(lambda r: unsuscribe_volume_list( r, folderPath, self.sync_daemon_tool, self.delegate)) return None
def __init__(self): print "init" self.sd = SyncDaemonTool() self.detect_shares()
class DBusInterface(object): """The DBus Interface to Ubuntu One's SyncDaemon.""" def __init__(self, msd): # magicicada's syncdaemon self.msd = msd logger.info("DBus interface starting") self._public_files_deferred = None # set up dbus and related stuff loop = DBusGMainLoop(set_as_default=True) self._bus = bus = SessionBus(mainloop=loop) self.sync_daemon_tool = SyncDaemonTool(bus) # hook up for signals and store info for the shutdown _signals = [ (self._on_status_changed, 'Status', 'StatusChanged'), (self._on_queue_added, 'Status', 'RequestQueueAdded'), (self._on_queue_removed, 'Status', 'RequestQueueRemoved'), (self._on_upload_progress, 'Status', 'UploadFileProgress'), (self._on_download_progress, 'Status', 'DownloadFileProgress'), (self._on_folder_created, 'Folders', 'FolderCreated'), (self._on_folder_deleted, 'Folders', 'FolderDeleted'), (self._on_folder_subscribed, 'Folders', 'FolderSubscribed'), (self._on_folder_unsubscribed, 'Folders', 'FolderUnSubscribed'), (self._on_share_created, 'Shares', 'ShareCreated'), (self._on_share_deleted, 'Shares', 'ShareDeleted'), (self._on_share_changed, 'Shares', 'ShareChanged'), (self._on_public_files_changed, 'PublicFiles', 'PublicAccessChanged'), ] self._dbus_matches = [] for method, dbus_lastname, signal_name in _signals: if dbus_lastname is None: dbus_interface = None else: dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname match = bus.add_signal_receiver(method, dbus_interface=dbus_interface, signal_name=signal_name) self._dbus_matches.append((match, dbus_interface, signal_name)) def shutdown(self): """Shut down the SyncDaemon.""" logger.info("DBus interface going down") # remove the signals from DBus remove = self._bus.remove_signal_receiver for match, dbus_interface, signal in self._dbus_matches: remove(match, dbus_interface=dbus_interface, signal_name=signal) def _process_status(self, state): """Transform status information.""" name = state['name'] description = state['description'] is_error = bool(state['is_error']) is_connected = bool(state['is_connected']) is_online = bool(state['is_online']) queues = state['queues'] connection = state['connection'] return (name, description, is_error, is_connected, is_online, queues, connection) @retryable def get_status(self): """Get SD status.""" logger.info("Getting status") d = self.sync_daemon_tool.get_status() d.addCallback(self._process_status) return d @retryable @defer.inlineCallbacks def get_free_space(self, volume_id): """Get the free space for a volume.""" result = yield self.sync_daemon_tool.free_space(volume_id) logger.info("Free space for volume %r is %r", volume_id, result) defer.returnValue(result) @retryable @defer.inlineCallbacks def get_real_shares_dir(self): """Get the real directory for the shares.""" result = yield self.sync_daemon_tool.get_shares_dir() logger.info("Real shares dir: %r", result) defer.returnValue(result) @retryable @defer.inlineCallbacks def get_link_shares_dir(self): """Get the link directory for the shares.""" result = yield self.sync_daemon_tool.get_shares_dir_link() logger.info("Link shares dir: %r", result) defer.returnValue(result) def _process_transfers(self, transfers, progress): """Process downloads or uploads to keep useful info only.""" r = [Transfer(t['path'], int(t[progress]), int(t['deflated_size'])) for t in transfers if 'deflated_size' in t] return r @retryable @defer.inlineCallbacks def get_current_downloads(self): """Get the current_downloads.""" result = yield self.sync_daemon_tool.get_current_downloads() processed = self._process_transfers(result, 'n_bytes_read') logger.info("Get current downloads: %d items", len(processed)) defer.returnValue(processed) @retryable @defer.inlineCallbacks def get_current_uploads(self): """Get the current_uploads.""" result = yield self.sync_daemon_tool.get_current_uploads() processed = self._process_transfers(result, 'n_bytes_written') logger.info("Get current uploads: %d items", len(processed)) defer.returnValue(processed) def _on_status_changed(self, state): """Call the SD callback.""" logger.info("Received Status changed") logger.debug("Status changed data: %r", state) data = self._process_status(state) self.msd.on_sd_status_changed(*data) def _on_queue_added(self, op_name, op_id, op_data): """Call the SD callback.""" logger.debug("Received Queue added: %r [%s] %s", op_name, op_id, op_data) self.msd.on_sd_queue_added(op_name, op_id, op_data) def _on_queue_removed(self, op_name, op_id, op_data): """Call the SD callback.""" logger.debug("Received Queue removed: %r [%s] %s", op_name, op_id, op_data) self.msd.on_sd_queue_removed(op_name, op_id, op_data) def _on_upload_progress(self, path, op_data): """Call the SD callback.""" logger.debug("Received Upload progress: %r %s", path, op_data) transf = Transfer(path, int(op_data['n_bytes_written']), int(op_data['deflated_size'])) self.msd.on_sd_upload_progress(transf) def _on_download_progress(self, path, op_data): """Call the SD callback.""" logger.debug("Received Download progress: %r %s", path, op_data) transf = Transfer(path, int(op_data['n_bytes_read']), int(op_data['deflated_size'])) self.msd.on_sd_download_progress(transf) def _on_folder_created(self, _): """Call the SD callback.""" logger.info("Received Folder created") self.msd.on_sd_folders_changed() def _on_folder_deleted(self, _): """Call the SD callback.""" logger.info("Received Folder deleted") self.msd.on_sd_folders_changed() def _on_folder_subscribed(self, _): """Call the SD callback.""" logger.info("Received Folder subscribed") self.msd.on_sd_folders_changed() def _on_folder_unsubscribed(self, _): """Call the SD callback.""" logger.info("Received Folder unsubscribed") self.msd.on_sd_folders_changed() def _on_share_created(self, _): """Call the SD callback.""" logger.info("Received Share created") self.msd.on_sd_shares_changed() def _on_share_deleted(self, _): """Call the SD callback.""" logger.info("Received Share deleted") self.msd.on_sd_shares_changed() def _on_share_changed(self, _): """Call the SD callback.""" logger.info("Received Share changed") self.msd.on_sd_shares_changed() def _on_public_files_changed(self, data): """Call the SD callback.""" logger.debug("Received Public Files changed: %s", data) pf = PublicFilesData(volume=data['share_id'], node=data['node_id'], path=data['path'], public_url=data['public_url']) is_public = bool(data['is_public']) self.msd.on_sd_public_files_changed(pf, is_public) def _on_public_files_list(self, data): """Call the SD callback.""" logger.info("Received Public Files list (%d)", len(data)) processed = [] for d in data: logger.debug(" Public Files data: %s", d) p = PublicFilesData(volume=d['volume_id'], node=d['node_id'], path=d['path'], public_url=d['public_url']) processed.append(p) return processed @defer.inlineCallbacks def get_public_files(self): """Ask the Public Files info to syncdaemon.""" try: result = yield self.sync_daemon_tool.get_public_files() logger.debug("Public files asked ok.") except AttributeError: logger.warning('Method sdtool.get_public_files is not available, ' 'trying old one directly from dbus.') result = yield self.get_public_files_old() except: logger.exception("Public files finished with error:") result = [] defer.returnValue(self._on_public_files_list(result)) def get_public_files_old(self): """Ask the Public Files info to syncdaemon (old approach).""" # yes, they can be imported! pylint: disable=F0401,E0611,W0404 from ubuntuone.platform.tools import DBusClient, ErrorSignal from ubuntuone.platform.dbus_interface import \ DBUS_IFACE_PUBLIC_FILES_NAME client = DBusClient(self._bus, '/publicfiles', DBUS_IFACE_PUBLIC_FILES_NAME) # note that these callbacks do not come with the requested info, the # method just will return None, and the real info will come later # in a signal def call_done(result): """Call was succesful.""" logger.debug("Public files asked ok.") def call_error(error): """Call was not succesful.""" logger.error("Public files asked with error: %s", error) d = self.sync_daemon_tool.wait_for_signal('PublicFilesList', filter=lambda _: True) client.call_method('get_public_files', reply_handler=call_done, error_handler=call_error) return d @retryable def get_queue_content(self): """Get the queue content from SDT.""" logger.info("Getting queue content") return self.sync_daemon_tool.waiting() @retryable def get_folders(self): """Get the folders info from SDT.""" def process(data): """Enhance data format.""" logger.info("Processing Folders items (%d)", len(data)) all_items = [] for d in data: logger.debug(" Folders data: %r", d) f = self._get_folder_data(d) all_items.append(f) return all_items logger.info("Getting folders") d = self.sync_daemon_tool.get_folders() d.addCallback(process) return d def start(self): """Start SDT.""" logger.info("Calling start") return self.sync_daemon_tool.start() def quit(self): """Stop SDT.""" logger.info("Calling quit") return self.sync_daemon_tool.quit() def connect(self): """Connect SDT.""" logger.info("Calling connect") return self.sync_daemon_tool.connect() def disconnect(self): """Disconnect SDT.""" logger.info("Calling disconnect") return self.sync_daemon_tool.disconnect() @defer.inlineCallbacks def is_sd_started(self): """Find out if SD is active in the system.""" started = yield is_already_running() logger.info("Checking if SD is started: %s", started) defer.returnValue(started) def _process_share_info(self, data): """Process share data.""" all_items = [] for d in data: logger.debug(" Share data: %r", d) # some processing dfb = d['free_bytes'] free_bytes = None if dfb == '' else int(dfb) s = ShareData( accepted=bool(d['accepted']), access_level=d['access_level'], free_bytes=free_bytes, name=d['name'], node_id=d['node_id'], other_username=d['other_username'], other_visible_name=d['other_visible_name'], path=d['path'], volume_id=d['volume_id'], subscribed=bool(d['subscribed']), ) all_items.append(s) return all_items @retryable def get_shares_to_me(self): """Get the shares to me ('shares') info from SDT.""" def process(data): """Enhance data format.""" logger.info("Processing Shares To Me items (%d)", len(data)) return self._process_share_info(data) logger.info("Getting shares to me") d = self.sync_daemon_tool.get_shares() d.addCallback(process) return d @retryable def get_shares_to_others(self): """Get the shares to others ('shared') info from SDT.""" def process(data): """Enhance data format.""" logger.info("Processing Shares To Others items (%d)", len(data)) return self._process_share_info(data) logger.info("Getting shares to others") d = self.sync_daemon_tool.list_shared() d.addCallback(process) return d @retryable def get_metadata(self, path): """Return the raw metadata.""" logger.info("Getting metadata for %r", path) def fix_failure(failure): """Get the failure and return a nice message.""" if failure.check(dbus.exceptions.DBusException): if failure.value.get_dbus_name() == DBUSERR_PYKEYERROR: return NOT_SYNCHED_PATH return failure def process(metadata): """Process the metadata.""" logger.debug("Got metadata for path %r: %r", path, metadata) return dict(metadata) d = self.sync_daemon_tool.get_metadata(path) d.addCallbacks(process, fix_failure) return d @retryable @defer.inlineCallbacks def _answer_share(self, share_id, method, action_name): """Effectively accept or reject a share.""" logger.debug("%s share %s started", action_name, share_id) try: result = yield method(share_id) except Exception, e: if len(e.args) == 2 and len(e.args[1]) > 1: error = "%s (%s)" % (e.args[0], e.args[1][1]) else: error = str(e.args[0]) logger.debug("%s share %s crashed: %s", action_name, share_id, error) raise ShareOperationError(share_id=share_id, error=error) logger.debug("%s share %s finished: %s", action_name, share_id, result) if 'error' in result: raise ShareOperationError(share_id=share_id, error=result['error'])
class U1FinderLib(NSObject): ## # Default constructor. @objc.typedSelector('@@:@') def initWithDelegate_(self, delegate): self = super(U1FinderLib, self).init() self.sync_daemon_tool = SyncDaemonTool(None) self.delegate = delegate cfreactor.install() return self ## # Returns the list of the shared volumes in a NSArray<NSString>. Example: # # [ # @"/Users/jose/Ubuntu One", # @"/Users/jose/Pictures" # ] @objc.typedSelector('v@:') def volumeList(self): d = self.sync_daemon_tool.get_folders() d.addCallback(lambda r: volume_list(r, self.delegate)) return None ## # Returns a NSArray<NSString> whit all the files that are being uploaded. Example: # [ # @"/Users/jose/Ubuntu One/Document.pdf", # @"/Users/jose/Pictures/Image.png" # } @objc.typedSelector('v@:') def currentUploads(self): d = self.sync_daemon_tool.get_current_uploads() d.addCallback(lambda r: get_uploads(r, self.delegate)) return None ## # Like currentUploads() but with the downloads. @objc.typedSelector('v@:') def currentDownloads(self): d = self.sync_daemon_tool.get_current_downloads() d.addCallback(lambda r: get_downloads(r, self.delegate)) return None ## # Indicates if the specified file is public or not. @objc.typedSelector('@@:@') def isFilePublic_(self, filePath): d = self.sync_daemon_tool.get_public_files() d.addCallback(lambda r: file_is_public(r, filePath, self.delegate)) return None ## # Publish or unpublish the specified file. @objc.typedSelector('v@:@B') def changeFile_visibillity_(self, filePath, isPublic): self.sync_daemon_tool.change_public_access(os.path.abspath(filePath), isPublic) return None ## # Returns the link (NSString) of a public file or nil if the file is not public. @objc.typedSelector('@@:@') def getPublicLinkOfFile_(self, filePath): d = self.sync_daemon_tool.get_public_files() d.addCallback(lambda r: get_public_files(r, filePath, self.delegate)) return None ## # Synchronizes the specified folder @objc.typedSelector('@@:@') def synchronizeFolderAtPath_(self, folderPath): d = self.sync_daemon_tool.create_folder(os.path.abspath(folderPath)) d.addCallback(lambda r: folder_synchronized(r, self.delegate)) return None ## # Unsuscribes the specified folder. @objc.typedSelector('@@:@') def unsuscribeFolderAtPath_(self, folderPath): d = self.sync_daemon_tool.get_folders() d.addCallback(lambda r: unsuscribe_volume_list(r, folderPath, self.sync_daemon_tool, self.delegate)) return None