diff --git a/docs/algorithm.md b/docs/algorithm.md index efd6dc4..315a8d7 100644 --- a/docs/algorithm.md +++ b/docs/algorithm.md @@ -14,14 +14,16 @@ Assuming all sources are reliable. We list all combinations mutually exclusive and collectively exhaustive. -| ID | Remote Files | Local files | Local delete rename history | Extra | Decision | -| --- | ------------ | ----------- | --------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| 1 | exist | exist | ignore | mtime_remote > mtime_local | download remote file, create local folder if not exists, clear local history if exists | -| 2 | exist | exist | ignore | mtime_remote <= mtime_local | upload local file, create remote folder if not exists, clear local history if exists | -| 3 | exist | exist | ignore | If local is a folder. mtime_local === undefined | clear local history if exists. TODO: what if a folder and a previous file share the same name? | -| 4 | exist | not exist | exist | mtime_remote >= delete_time_local | download remote file, create folder if not exists | -| 5 | exist | not exist | exist | mtime_remote < delete_time_local | delete remote file, clear local history | -| 6 | exist | not exist | not exist | | download remote file, create folder if not exists | -| 7 | not exist | exist | ignore | If local is a single file. | upload local file, create remote folder if not exists, clear local history if exists | -| 8 | not exist | exist | ignore | If local is a folder. | upload local files recursively, create remote folder if not exists, clear local history if exists | -| 9 | not exist | not exist | ignore | | clear local history if exists | +| ID | Remote Files | Local files | Local delete rename history | Extra | Decision | +| --- | ------------ | ----------- | --------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| 1 | exist | exist | ignore | mtime_remote > mtime_local | download remote file, create local folder if not exists, clear local history if exists | +| 2 | exist | exist | ignore | mtime_remote < mtime_local | upload local file, create remote folder if not exists, clear local history if exists | +| 3 | exist | exist | ignore | mtime_remote === mtime_local && size_remote === size_local | clear local history if exists (the file was synced and no changes after last sync) | +| 4 | exist | exist | ignore | mtime_remote === mtime_local && size_remote !== size_local | upload local file, clear local history if exists (we always prefer local to remote) | +| 5 | exist | exist | ignore | If local is a folder. mtime_local === undefined | clear local history if exists. TODO: what if a folder and a previous file share the same name? | +| 6 | exist | not exist | exist | mtime_remote >= delete_time_local | download remote file, create folder if not exists | +| 7 | exist | not exist | exist | mtime_remote < delete_time_local | delete remote file, clear local history | +| 8 | exist | not exist | not exist | | download remote file, create folder if not exists | +| 9 | not exist | exist | ignore | If local is a single file. | upload local file, create remote folder if not exists, clear local history if exists | +| 10 | not exist | exist | ignore | If local is a folder. | upload local files recursively, create remote folder if not exists, clear local history if exists | +| 11 | not exist | not exist | ignore | | clear local history if exists | diff --git a/src/sync.ts b/src/sync.ts index 0eaed27..4d168ba 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -28,6 +28,8 @@ interface FileOrFolderMixedState { mtime_local?: number; mtime_remote?: number; delete_time_local?: number; + size_local?: number; + size_remote?: number; decision?: DecisionType; syncDone?: "done"; } @@ -46,11 +48,13 @@ export const ensembleMixedStates = ( key: key, exist_remote: true, mtime_remote: entry.LastModified.valueOf(), + size_remote: entry.Size, }; if (results.hasOwnProperty(key)) { results[key].key = r.key; results[key].exist_remote = r.exist_remote; results[key].mtime_remote = r.mtime_remote; + results[key].size_remote = r.size_remote; } else { results[key] = r; } @@ -68,6 +72,7 @@ export const ensembleMixedStates = ( key: entry.path, exist_local: true, mtime_local: entry.stat.mtime, + size_local: entry.stat.size, }; } else if (entry instanceof TFolder) { key = `${entry.path}/`; @@ -75,6 +80,7 @@ export const ensembleMixedStates = ( key: key, exist_local: true, mtime_local: undefined, + size_local: 0, }; } else { throw Error(`unexpected ${entry}`); @@ -84,6 +90,7 @@ export const ensembleMixedStates = ( results[key].key = r.key; results[key].exist_local = r.exist_local; results[key].mtime_local = r.mtime_local; + results[key].size_local = r.size_local; } else { results[key] = r; } @@ -156,7 +163,25 @@ export const getOperation = ( r.exist_local && r.mtime_remote !== undefined && r.mtime_local !== undefined && - r.mtime_remote <= r.mtime_local + r.mtime_remote < r.mtime_local + ) { + r.decision = "upload_clearhist"; + } else if ( + r.exist_remote && + r.exist_local && + r.mtime_remote !== undefined && + r.mtime_local !== undefined && + r.mtime_remote === r.mtime_local && + r.size_local === r.size_remote + ) { + r.decision = "skip"; + } else if ( + r.exist_remote && + r.exist_local && + r.mtime_remote !== undefined && + r.mtime_local !== undefined && + r.mtime_remote === r.mtime_local && + r.size_local === r.size_remote ) { r.decision = "upload_clearhist"; } else if (