ReactNativeClient/lib/file-api.js
async function basicDelta(path, getDirStatFn, options) {
	const outputLimit = 50;
	const itemIds = await options.allItemIdsHandler();
	if (!Array.isArray(itemIds)) throw new Error('Delta API not supported - local IDs must be provided');

	const context = basicDeltaContextFromOptions_(options);

	let newContext = {
		timestamp: context.timestamp,
		filesAtTimestamp: context.filesAtTimestamp.slice(),
		statsCache: context.statsCache,
		statIdsCache: context.statIdsCache,
		deletedItemsProcessed: context.deletedItemsProcessed,
	};

	// Stats are cached until all items have been processed (until hasMore is false)
	if (newContext.statsCache === null) {
		newContext.statsCache = await getDirStatFn(path);
		newContext.statsCache.sort(function(a, b) {
			return a.updated_time - b.updated_time;
		});
		newContext.statIdsCache = newContext.statsCache
			.filter(item => BaseItem.isSystemPath(item.path))
			.map(item => BaseItem.pathToId(item.path));
		newContext.statIdsCache.sort(); // Items must be sorted to use binary search below
	}

	let output = [];

	// Find out which files have been changed since the last time. Note that we keep
	// both the timestamp of the most recent change, *and* the items that exactly match
	// this timestamp. This to handle cases where an item is modified while this delta
	// function is running. For example:
	// t0: Item 1 is changed
	// t0: Sync items - run delta function
	// t0: While delta() is running, modify Item 2
	// Since item 2 was modified within the same millisecond, it would be skipped in the
	// next sync if we relied exclusively on a timestamp.
	for (let i = 0; i < newContext.statsCache.length; i++) {
		const stat = newContext.statsCache[i];

		if (stat.isDir) continue;

		if (stat.updated_time < context.timestamp) continue;

		// Special case for items that exactly match the timestamp
		if (stat.updated_time === context.timestamp) {
			if (context.filesAtTimestamp.indexOf(stat.path) >= 0) continue;
		}

		if (stat.updated_time > newContext.timestamp) {
			newContext.timestamp = stat.updated_time;
			newContext.filesAtTimestamp = [];
		}

		newContext.filesAtTimestamp.push(stat.path);
		output.push(stat);

		if (output.length >= outputLimit) break;
	}

	if (!newContext.deletedItemsProcessed) {
		// Find out which items have been deleted on the sync target by comparing the items
		// we have to the items on the target.
		// Note that when deleted items are processed it might result in the output having
		// more items than outputLimit. This is acceptable since delete operations are cheap.
		let deletedItems = [];
		for (let i = 0; i < itemIds.length; i++) {
			const itemId = itemIds[i];

			if (ArrayUtils.binarySearch(newContext.statIdsCache, itemId) < 0) {
				deletedItems.push({
					path: BaseItem.systemPath(itemId),
					isDeleted: true,
				});
			}
		}

		output = output.concat(deletedItems);
	}

	newContext.deletedItemsProcessed = true;

	const hasMore = output.length >= outputLimit;

	if (!hasMore) {
		// Clear temporary info from context. It's especially important to remove deletedItemsProcessed
		// so that they are processed again on the next sync.
		newContext.statsCache = null;
		newContext.statIdsCache = null;
		delete newContext.deletedItemsProcessed;
	}

	return {
		hasMore: hasMore,
		context: newContext,
		items: output,
	};
}
async function basicDelta(path, getDirStatFn, options) {
	const outputLimit = 50;
	const itemIds = await options.allItemIdsHandler();
	if (!Array.isArray(itemIds)) throw new Error('Delta API not supported - local IDs must be provided');

	const context = basicDeltaContextFromOptions_(options);

	let newContext = {
		timestamp: context.timestamp,
		filesAtTimestamp: context.filesAtTimestamp.slice(),
		statsCache: context.statsCache,
		statIdsCache: context.statIdsCache,
		deletedItemsProcessed: context.deletedItemsProcessed,
	};

	// Stats are cached until all items have been processed (until hasMore is false)
	if (newContext.statsCache === null) {
		newContext.statsCache = await getDirStatFn(path);
		newContext.statsCache.sort(function(a, b) {
			return a.updated_time - b.updated_time;
		});
		newContext.statIdsCache = newContext.statsCache
			.filter(item => BaseItem.isSystemPath(item.path))
			.map(item => BaseItem.pathToId(item.path));
		newContext.statIdsCache.sort(); // Items must be sorted to use binary search below
	}

	let output = [];

	// Find out which files have been changed since the last time. Note that we keep
	// both the timestamp of the most recent change, *and* the items that exactly match
	// this timestamp. This to handle cases where an item is modified while this delta
	// function is running. For example:
	// t0: Item 1 is changed
	// t0: Sync items - run delta function
	// t0: While delta() is running, modify Item 2
	// Since item 2 was modified within the same millisecond, it would be skipped in the
	// next sync if we relied exclusively on a timestamp.
	for (let i = 0; i < newContext.statsCache.length; i++) {
		const stat = newContext.statsCache[i];

		if (stat.isDir) continue;

		if (stat.updated_time < context.timestamp) continue;

		// Special case for items that exactly match the timestamp
		if (stat.updated_time === context.timestamp) {
			if (context.filesAtTimestamp.indexOf(stat.path) >= 0) continue;
		}

		if (stat.updated_time > newContext.timestamp) {
			newContext.timestamp = stat.updated_time;
			newContext.filesAtTimestamp = [];
		}

		newContext.filesAtTimestamp.push(stat.path);
		output.push(stat);

		if (output.length >= outputLimit) break;
	}

	if (!newContext.deletedItemsProcessed) {
		// Find out which items have been deleted on the sync target by comparing the items
		// we have to the items on the target.
		// Note that when deleted items are processed it might result in the output having
		// more items than outputLimit. This is acceptable since delete operations are cheap.
		let deletedItems = [];
		for (let i = 0; i < itemIds.length; i++) {
			const itemId = itemIds[i];

			if (ArrayUtils.binarySearch(newContext.statIdsCache, itemId) < 0) {
				deletedItems.push({
					path: BaseItem.systemPath(itemId),
					isDeleted: true,
				});
			}
		}

		output = output.concat(deletedItems);
	}

	newContext.deletedItemsProcessed = true;

	const hasMore = output.length >= outputLimit;

	if (!hasMore) {
		// Clear temporary info from context. It's especially important to remove deletedItemsProcessed
		// so that they are processed again on the next sync.
		newContext.statsCache = null;
		newContext.statIdsCache = null;
		delete newContext.deletedItemsProcessed;
	}

	return {
		hasMore: hasMore,
		context: newContext,
		items: output,
	};
}
async function basicDelta ( path , getDirStatFn , options ) { const outputLimit = 50 ; const itemIds = await options . allItemIdsHandler ( ) ; if ( ! Array . isArray ( itemIds ) ) throw new Error ( 'Delta API not supported - local IDs must be provided' ) ; const context = basicDeltaContextFromOptions_ ( options ) ; let newContext = { timestamp : context . timestamp , filesAtTimestamp : context . filesAtTimestamp . slice ( ) , statsCache : context . statsCache , statIdsCache : context . statIdsCache , deletedItemsProcessed : context . deletedItemsProcessed , } ; // Stats are cached until all items have been processed (until hasMore is false) if ( newContext . statsCache === null ) { newContext . statsCache = await getDirStatFn ( path ) ; newContext . statsCache . sort ( function ( a , b ) { return a . updated_time - b . updated_time ; } ) ; newContext . statIdsCache = newContext . statsCache . filter ( item => BaseItem . isSystemPath ( item . path ) ) . map ( item => BaseItem . pathToId ( item . path ) ) ; newContext . statIdsCache . sort ( ) ; // Items must be sorted to use binary search below } let output = [ ] ; // Find out which files have been changed since the last time. Note that we keep // both the timestamp of the most recent change, *and* the items that exactly match // this timestamp. This to handle cases where an item is modified while this delta // function is running. For example: // t0: Item 1 is changed // t0: Sync items - run delta function // t0: While delta() is running, modify Item 2 // Since item 2 was modified within the same millisecond, it would be skipped in the // next sync if we relied exclusively on a timestamp. for ( let i = 0 ; i < newContext . statsCache . length ; i ++ ) { const stat = newContext . statsCache [ i ] ; if ( stat . isDir ) continue ; if ( stat . updated_time < context . timestamp ) continue ; // Special case for items that exactly match the timestamp if ( stat . updated_time === context . timestamp ) { if ( context . filesAtTimestamp . indexOf ( stat . path ) >= 0 ) continue ; } if ( stat . updated_time > newContext . timestamp ) { newContext . timestamp = stat . updated_time ; newContext . filesAtTimestamp = [ ] ; } newContext . filesAtTimestamp . push ( stat . path ) ; output . push ( stat ) ; if ( output . length >= outputLimit ) break ; } if ( ! newContext . deletedItemsProcessed ) { // Find out which items have been deleted on the sync target by comparing the items // we have to the items on the target. // Note that when deleted items are processed it might result in the output having // more items than outputLimit. This is acceptable since delete operations are cheap. let deletedItems = [ ] ; for ( let i = 0 ; i < itemIds . length ; i ++ ) { const itemId = itemIds [ i ] ; if ( ArrayUtils . binarySearch ( newContext . statIdsCache , itemId ) < 0 ) { deletedItems . push ( { path : BaseItem . systemPath ( itemId ) , isDeleted : true , } ) ; } } output = output . concat ( deletedItems ) ; } newContext . deletedItemsProcessed = true ; const hasMore = output . length >= outputLimit ; if ( ! hasMore ) { // Clear temporary info from context. It's especially important to remove deletedItemsProcessed // so that they are processed again on the next sync. newContext . statsCache = null ; newContext . statIdsCache = null ; delete newContext . deletedItemsProcessed ; } return { hasMore : hasMore , context : newContext , items : output , } ; }
This is the basic delta algorithm, which can be used in case the cloud service does not have a built-in delta API. OneDrive and Dropbox have one for example, but Nextcloud and obviously the file system do not.
This is the basic delta algorithm which can be used in case the cloud service does not have a built - in delta API . OneDrive and Dropbox have one for example but Nextcloud and obviously the file system do not .