You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Core: Fixed potential out-of-sync issue if user cancels while in the middle of delta step
This commit is contained in:
		| @@ -606,5 +606,25 @@ describe('Synchronizer', function() { | |||||||
|  |  | ||||||
| 		done(); | 		done(); | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
|  | 	it('items should be downloaded again when user cancels in the middle of delta operation', async (done) => { | ||||||
|  | 		let folder1 = await Folder.save({ title: "folder1" }); | ||||||
|  | 		let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id }); | ||||||
|  | 		await synchronizer().start(); | ||||||
|  |  | ||||||
|  | 		await switchClient(2); | ||||||
|  |  | ||||||
|  | 		synchronizer().debugFlags_ = ['cancelDeltaLoop2'];		 | ||||||
|  | 		let context = await synchronizer().start(); | ||||||
|  | 		let notes = await Note.all(); | ||||||
|  | 		expect(notes.length).toBe(0); | ||||||
|  |  | ||||||
|  | 		synchronizer().debugFlags_ = []; | ||||||
|  | 		await synchronizer().start({ context: context }); | ||||||
|  | 		notes = await Note.all(); | ||||||
|  | 		expect(notes.length).toBe(1); | ||||||
|  |  | ||||||
|  | 		done(); | ||||||
|  | 	}); | ||||||
| 	 | 	 | ||||||
| }); | }); | ||||||
| @@ -22,6 +22,10 @@ class Synchronizer { | |||||||
| 		this.appType_ = appType; | 		this.appType_ = appType; | ||||||
| 		this.cancelling_ = false; | 		this.cancelling_ = false; | ||||||
|  |  | ||||||
|  | 		// Debug flags are used to test certain hard-to-test conditions | ||||||
|  | 		// such as cancelling in the middle of a loop. | ||||||
|  | 		this.debugFlags_ = []; | ||||||
|  |  | ||||||
| 		this.onProgress_ = function(s) {}; | 		this.onProgress_ = function(s) {}; | ||||||
| 		this.progressReport_ = {}; | 		this.progressReport_ = {}; | ||||||
|  |  | ||||||
| @@ -354,10 +358,11 @@ class Synchronizer { | |||||||
| 			let context = null; | 			let context = null; | ||||||
| 			let newDeltaContext = null; | 			let newDeltaContext = null; | ||||||
| 			let localFoldersToDelete = []; | 			let localFoldersToDelete = []; | ||||||
|  | 			let hasCancelled = false; | ||||||
| 			if (lastContext.delta) context = lastContext.delta; | 			if (lastContext.delta) context = lastContext.delta; | ||||||
|  |  | ||||||
| 			while (true) { | 			while (true) { | ||||||
| 				if (this.cancelling()) break; | 				if (this.cancelling() || hasCancelled) break; | ||||||
|  |  | ||||||
| 				let listResult = await this.api().delta('', { | 				let listResult = await this.api().delta('', { | ||||||
| 					context: context, | 					context: context, | ||||||
| @@ -372,7 +377,10 @@ class Synchronizer { | |||||||
|  |  | ||||||
| 				let remotes = listResult.items; | 				let remotes = listResult.items; | ||||||
| 				for (let i = 0; i < remotes.length; i++) { | 				for (let i = 0; i < remotes.length; i++) { | ||||||
| 					if (this.cancelling()) break; | 					if (this.cancelling() || this.debugFlags_.indexOf('cancelDeltaLoop2') >= 0) { | ||||||
|  | 						hasCancelled = true; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  |  | ||||||
| 					let remote = remotes[i]; | 					let remote = remotes[i]; | ||||||
| 					if (!BaseItem.isSystemPath(remote.path)) continue; // The delta API might return things like the .sync, .resource or the root folder | 					if (!BaseItem.isSystemPath(remote.path)) continue; // The delta API might return things like the .sync, .resource or the root folder | ||||||
| @@ -443,11 +451,18 @@ class Synchronizer { | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (!listResult.hasMore) { | 				// If user has cancelled, don't record the new context (2) so that synchronisation | ||||||
| 					newDeltaContext = listResult.context; | 				// can start again from the previous context (1) next time. It is ok if some items | ||||||
| 					break; | 				// have been synced between (1) and (2) because the loop above will handle the same | ||||||
|  | 				// items being synced twice as an update. If the local and remote items are indentical | ||||||
|  | 				// the update will simply be skipped. | ||||||
|  | 				if (!hasCancelled) { | ||||||
|  | 					if (!listResult.hasMore) { | ||||||
|  | 						newDeltaContext = listResult.context; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					context = listResult.context; | ||||||
| 				} | 				} | ||||||
| 				context = listResult.context; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			outputContext.delta = newDeltaContext ? newDeltaContext : lastContext.delta; | 			outputContext.delta = newDeltaContext ? newDeltaContext : lastContext.delta; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user