summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Shyba <victor1984@riseup.net>2017-11-11 01:48:16 -0300
committerVictor Shyba <victor1984@riseup.net>2017-11-13 18:17:16 -0300
commit1d4f43570345fc644b42a96dfd70cd72435f55fd (patch)
tree9bea2f2e10b5562bff28fa30c6a5ba5387d2bd33
parent8f3fdc2f9c3d4360669c2c7fd89dbd95e0f8dd22 (diff)
[feature] support unsynced local_only blobs
Adds the ability to have document that wont be synced. This enables applications to use soledad to store temporary blobs that should be discarded later instead of unnecessarily keeping the sync loop busy. -- Resolves: #8819
-rw-r--r--src/leap/soledad/client/_db/blobs/__init__.py12
-rw-r--r--src/leap/soledad/client/_db/blobs/sql.py1
-rw-r--r--src/leap/soledad/client/_db/blobs/sync.py4
-rw-r--r--tests/blobs/test_blob_manager.py13
4 files changed, 27 insertions, 3 deletions
diff --git a/src/leap/soledad/client/_db/blobs/__init__.py b/src/leap/soledad/client/_db/blobs/__init__.py
index a5b7d6e3..3c7492c6 100644
--- a/src/leap/soledad/client/_db/blobs/__init__.py
+++ b/src/leap/soledad/client/_db/blobs/__init__.py
@@ -207,7 +207,7 @@ class BlobManager(BlobsSynchronizer):
def local_list_status(self, status, namespace=''):
return self.local.list_status(status, namespace)
- def put(self, doc, size, namespace=''):
+ def put(self, doc, size, namespace='', local_only=False):
"""
Put a blob in local storage and upload it to server.
@@ -215,14 +215,16 @@ class BlobManager(BlobsSynchronizer):
:type doc: leap.soledad.client._document.BlobDoc
:param size: The size of the blob.
:type size: int
+ :param local_only: Avoids sync (doesn't send to server).
+ :type local_only: bool
:param namespace:
Optional parameter to restrict operation to a given namespace.
:type namespace: str
"""
- return self.semaphore.run(self._put, doc, size, namespace)
+ return self.semaphore.run(self._put, doc, size, namespace, local_only)
@defer.inlineCallbacks
- def _put(self, doc, size, namespace):
+ def _put(self, doc, size, namespace, local_only=False):
if (yield self.local.exists(doc.blob_id, namespace=namespace)):
error_message = "Blob already exists: %s" % doc.blob_id
raise BlobAlreadyExistsError(error_message)
@@ -230,6 +232,10 @@ class BlobManager(BlobsSynchronizer):
# TODO this is a tee really, but ok... could do db and upload
# concurrently. not sure if we'd gain something.
yield self.local.put(doc.blob_id, fd, size=size, namespace=namespace)
+ if local_only:
+ yield self.local.update_sync_status(
+ doc.blob_id, SyncStatus.LOCAL_ONLY)
+ defer.returnValue(None)
yield self.local.update_sync_status(
doc.blob_id, SyncStatus.PENDING_UPLOAD)
# In fact, some kind of pipe is needed here, where each write on db
diff --git a/src/leap/soledad/client/_db/blobs/sql.py b/src/leap/soledad/client/_db/blobs/sql.py
index 5337ab87..ebd6c095 100644
--- a/src/leap/soledad/client/_db/blobs/sql.py
+++ b/src/leap/soledad/client/_db/blobs/sql.py
@@ -42,6 +42,7 @@ class SyncStatus:
FAILED_UPLOAD = 4
FAILED_DOWNLOAD = 5
PENDING_DELETE = 6
+ LOCAL_ONLY = 7
UNAVAILABLE_STATUSES = (3, 5)
diff --git a/src/leap/soledad/client/_db/blobs/sync.py b/src/leap/soledad/client/_db/blobs/sync.py
index bdfbb983..3ee60305 100644
--- a/src/leap/soledad/client/_db/blobs/sync.py
+++ b/src/leap/soledad/client/_db/blobs/sync.py
@@ -77,6 +77,10 @@ class BlobsSynchronizer(object):
remote_deletions = self.remote_list(namespace=namespace, deleted=True)
remote_deletions = yield remote_deletions
yield self.local.batch_delete(remote_deletions)
+ yield self.local.update_batch_sync_status(
+ remote_deletions,
+ SyncStatus.SYNCED,
+ namespace=namespace)
@defer.inlineCallbacks
def send_missing(self, namespace=''):
diff --git a/tests/blobs/test_blob_manager.py b/tests/blobs/test_blob_manager.py
index 58f99790..c7bbb0d3 100644
--- a/tests/blobs/test_blob_manager.py
+++ b/tests/blobs/test_blob_manager.py
@@ -83,6 +83,19 @@ class BlobManagerTestCase(unittest.TestCase):
@defer.inlineCallbacks
@pytest.mark.usefixtures("method_tmpdir")
+ def test_put_local_only_doesnt_send_to_server(self):
+ self.manager._encrypt_and_upload = Mock(return_value=None)
+ msg, blob_id = "Hey Joe", uuid4().hex
+ doc = BlobDoc(BytesIO(msg), blob_id=blob_id)
+ yield self.manager.put(doc, size=len(msg), local_only=True)
+ result = yield self.manager.local.get(blob_id)
+ status, _ = yield self.manager.local.get_sync_status(blob_id)
+ self.assertEquals(result.getvalue(), msg)
+ self.assertEquals(status, SyncStatus.LOCAL_ONLY)
+ self.assertFalse(self.manager._encrypt_and_upload.called)
+
+ @defer.inlineCallbacks
+ @pytest.mark.usefixtures("method_tmpdir")
def test_put_then_get_using_real_file_descriptor(self):
self.manager._encrypt_and_upload = Mock(return_value=None)
self.manager._download_and_decrypt = Mock(return_value=None)