diff src/plugins/plugin_misc_file.py @ 1626:63cef4dbf2a4

core, plugins file, XEP-0234, bridge: progression api enhancement: - progressStarted have a new metadata parameter, useful to know the kind of progression, direction, etc. Check bridge doc - progressGetAllMetadata can be used to retrieve this data and discover on currently running progressions - progressFinished also have a new metadata parameter, used to e.g. indicate that hash is checked - core: fixed progressGetAll - file, XEP-0234: implemented the API modifications, hash is returned on progressFinished - file: SatFile.checkSize allows to check size independently of close (be sure that all the data have been transfered though)
author Goffi <goffi@goffi.org>
date Thu, 19 Nov 2015 18:13:26 +0100
parents 3ec7511dbf28
children 591e04f0103c
line wrap: on
line diff
--- a/src/plugins/plugin_misc_file.py	Thu Nov 19 11:15:06 2015 +0100
+++ b/src/plugins/plugin_misc_file.py	Thu Nov 19 18:13:26 2015 +0100
@@ -71,16 +71,52 @@
         self.size = size
         self.data_cb = data_cb
         self.profile = profile
-        self.host.registerProgressCb(self.uid, self.getProgress, profile)
-        self.host.bridge.progressStarted(self.uid, self.profile)
+        metadata = self.getProgressMetadata()
+        self.host.registerProgressCb(self.uid, self.getProgress, metadata, profile=profile)
+        self.host.bridge.progressStarted(self.uid, metadata, self.profile)
 
-    def close(self):
+    def checkSize(self):
+        """Check that current size correspond to given size
+
+        must be used when the transfer is supposed to be finished
+        @return (bool): True if the position is the same as given size
+        @raise exceptions.NotFound: size has not be specified
+        """
         position = self._file.tell()
+        if self.size is None:
+            raise exceptions.NotFound
+        return position == self.size
+
+
+    def close(self, progress_metadata=None, error=None):
+        """Close the current file
+
+        @param progress_metadata(None, dict): metadata to send with _onProgressFinished message
+        @param error(None, unicode): set to an error message if progress was not successful
+            mutually exclusive with progress_metadata
+            error can happen even if error is None, if current size differ from given size
+        """
+        if error is None:
+            try:
+                size_ok = self.checkSize()
+            except exceptions.NotFound:
+                size_ok = True
+            finally:
+                if not size_ok:
+                    error = u'declared size and actual mismatch'
+                    log.warning(u"successful close was requested, but there is a size mismatch")
+                    progress_metadata = None
+
         self._file.close()
-        if not self.size or self.size == position:
-            self.host.bridge.progressFinished(self.uid, self.profile)
+
+        if error is None:
+            if progress_metadata is None:
+                progress_metadata = {}
+            self.host.bridge.progressFinished(self.uid, progress_metadata, self.profile)
         else:
-            self.host.bridge.progressError(self.uid, u"size doesn't match", self.profile)
+            assert progress_metadata is None
+            self.host.bridge.progressError(self.uid, error, self.profile)
+
         self.host.removeProgressCb(self.uid, self.profile)
 
     def flush(self):
@@ -103,6 +139,32 @@
     def tell(self):
         return self._file.tell()
 
+    def mode(self):
+        return self._file.mode()
+
+    def getProgressMetadata(self):
+        """Return progression metadata as given to progressStarted
+
+        @return (dict): metadata (check bridge for documentation)
+        """
+        metadata = {'type': C.META_TYPE_FILE}
+
+        mode = self._file.mode
+        if '+' in mode:
+            pass # we have no direction in read/write modes
+        elif mode in ('r', 'rb'):
+            metadata['direction'] = 'out'
+        elif mode in ('w', 'wb'):
+            metadata['direction'] = 'in'
+        elif 'U' in mode:
+            metadata['direction'] = 'out'
+        else:
+            raise exceptions.InternalError
+
+        metadata['name'] = self._file.name
+
+        return metadata
+
     def getProgress(self, progress_id, profile):
         ret = {'position': self._file.tell()}
         if self.size: