1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-06-15 23:00:36 +02:00

All: Resolves #1481: New: Allow downloading attachments on demand or automatically (#1527)

* Allow downloading resources automatically, on demand, or when loading note

* Make needToBeFetched calls to return the right number of resources

* All: Improved handling of resource downloading and decryption

* Desktop: Click on resource to download it (and, optionally, to decrypt it)

* Desktop: Better handling of resource state (not downloaded, downloading, encrypted) in front end

* Renamed setting to sync.resourceDownloadMode

* Download resources when changing setting

* tweaks

* removed duplicate cs

* Better report resource download progress

* Make sure resource cache is properly cleared when needed

* Also handle manual download for non-image resources

* More improvements to logic when downloading and decrypting resources
This commit is contained in:
Laurent Cozic
2019-05-22 15:56:07 +01:00
committed by GitHub
parent 6bcbedd6a4
commit 8a6fe20a69
23 changed files with 470 additions and 108 deletions

View File

@ -2,6 +2,7 @@ const BaseItem = require('lib/models/BaseItem');
const Resource = require('lib/models/Resource');
const ResourceService = require('lib/services/ResourceService');
const { Logger } = require('lib/logger.js');
const EventEmitter = require('events');
class DecryptionWorker {
@ -14,6 +15,7 @@ class DecryptionWorker {
};
this.scheduleId_ = null;
this.eventEmitter_ = new EventEmitter();
}
setLogger(l) {
@ -24,6 +26,14 @@ class DecryptionWorker {
return this.logger_;
}
on(eventName, callback) {
return this.eventEmitter_.on(eventName, callback);
}
off(eventName, callback) {
return this.eventEmitter_.removeListener(eventName, callback);
}
static instance() {
if (this.instance_) return this.instance_;
this.instance_ = new DecryptionWorker();
@ -85,14 +95,6 @@ class DecryptionWorker {
const ItemClass = BaseItem.itemClass(item);
if (item.type_ === Resource.modelType()) {
const ls = await Resource.localState(item);
if (ls.fetch_status !== Resource.FETCH_STATUS_DONE) {
excludedIds.push(item.id);
continue;
}
}
this.dispatchReport({
itemIndex: i,
itemCount: items.length,
@ -101,10 +103,21 @@ class DecryptionWorker {
// Don't log in production as it results in many messages when importing many items
// this.logger().info('DecryptionWorker: decrypting: ' + item.id + ' (' + ItemClass.tableName() + ')');
try {
await ItemClass.decrypt(item);
const decryptedItem = await ItemClass.decrypt(item);
if (decryptedItem.type_ === Resource.modelType() && !!decryptedItem.encryption_blob_encrypted) {
// itemsThatNeedDecryption() will return the resource again if the blob has not been decrypted,
// but that will result in an infinite loop if the blob simply has not been downloaded yet.
// So skip the ID for now, and the service will try to decrypt the blob again the next time.
excludedIds.push(decryptedItem.id);
}
if (decryptedItem.type_ === Resource.modelType() && !decryptedItem.encryption_blob_encrypted) {
this.eventEmitter_.emit('resourceDecrypted', { id: decryptedItem.id });
}
} catch (error) {
excludedIds.push(item.id);
if (error.code === 'masterKeyNotLoaded' && options.masterKeyNotLoadedHandler === 'dispatch') {
if (notLoadedMasterKeyDisptaches.indexOf(error.masterKeyId) < 0) {
this.dispatch({
@ -139,9 +152,16 @@ class DecryptionWorker {
this.logger().info('DecryptionWorker: completed decryption.');
const downloadedButEncryptedBlobCount = await Resource.downloadedButEncryptedBlobCount();
this.dispatchReport({ state: 'idle' });
this.state_ = 'idle';
if (downloadedButEncryptedBlobCount) {
this.logger().info('DecryptionWorker: Some resources have been downloaded but are not decrypted yet. Scheduling another decryption. Resource count: ' + downloadedButEncryptedBlobCount);
this.scheduleStart();
}
}
}