add mapping of local and remote

This commit is contained in:
fyears
2021-10-25 00:41:13 +08:00
parent 5ef032523a
commit 69bc1f0e03
5 changed files with 234 additions and 51 deletions
+99 -32
View File
@@ -1,10 +1,21 @@
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
import { S3Client } from "@aws-sdk/client-s3";
import * as lf from "lovefield-ts/dist/es6/lf.js";
import { clearHistoryOfKey, FileFolderHistoryRecord } from "./localdb";
import { S3Config, S3ObjectType, uploadToRemote, deleteFromRemote } from "./s3";
import { downloadFromRemote } from "./s3";
import {
clearDeleteRenameHistoryOfKey,
FileFolderHistoryRecord,
upsertSyncMetaMappingDataS3,
getSyncMetaMappingByRemoteKeyS3,
} from "./localdb";
import {
S3Config,
S3ObjectType,
uploadToRemote,
deleteFromRemote,
downloadFromRemote,
} from "./s3";
import { mkdirpInVault } from "./misc";
type DecisionType =
@@ -32,24 +43,43 @@ interface FileOrFolderMixedState {
size_remote?: number;
decision?: DecisionType;
syncDone?: "done";
decision_branch?: number;
}
export const ensembleMixedStates = (
export const ensembleMixedStates = async (
remote: S3ObjectType[],
local: TAbstractFile[],
deleteHistory: FileFolderHistoryRecord[]
deleteHistory: FileFolderHistoryRecord[],
db: lf.DatabaseConnection
) => {
const results = {} as Record<string, FileOrFolderMixedState>;
remote.forEach((entry) => {
for (const entry of remote) {
const backwardMapping = await getSyncMetaMappingByRemoteKeyS3(
db,
entry.Key,
entry.LastModified.valueOf(),
entry.ETag
);
let key = entry.Key;
let r = {} as FileOrFolderMixedState;
const key = entry.Key;
r = {
key: key,
exist_remote: true,
mtime_remote: entry.LastModified.valueOf(),
size_remote: entry.Size,
};
if (backwardMapping !== undefined) {
key = backwardMapping.local_key;
r = {
key: key,
exist_remote: true,
mtime_remote: backwardMapping.local_mtime,
size_remote: backwardMapping.local_size,
};
} else {
r = {
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;
@@ -58,15 +88,15 @@ export const ensembleMixedStates = (
} else {
results[key] = r;
}
});
}
local.forEach((entry) => {
for (const entry of local) {
let r = {} as FileOrFolderMixedState;
let key = entry.path;
if (entry.path === "/") {
// ignore
return;
continue;
} else if (entry instanceof TFile) {
r = {
key: entry.path,
@@ -94,9 +124,9 @@ export const ensembleMixedStates = (
} else {
results[key] = r;
}
});
}
deleteHistory.forEach((entry) => {
for (const entry of deleteHistory) {
let key = entry.key;
if (entry.key_type === "folder") {
if (!entry.key.endsWith("/")) {
@@ -119,7 +149,7 @@ export const ensembleMixedStates = (
} else {
results[key] = r;
}
});
}
return results;
};
@@ -158,6 +188,7 @@ export const getOperation = (
r.mtime_remote > r.mtime_local
) {
r.decision = "download_clearhist";
r.decision_branch = 1;
} else if (
r.exist_remote &&
r.exist_local &&
@@ -166,6 +197,7 @@ export const getOperation = (
r.mtime_remote < r.mtime_local
) {
r.decision = "upload_clearhist";
r.decision_branch = 2;
} else if (
r.exist_remote &&
r.exist_local &&
@@ -175,26 +207,24 @@ export const getOperation = (
r.size_local === r.size_remote
) {
r.decision = "skip";
r.decision_branch = 3;
} 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.size_local !== r.size_remote
) {
r.decision = "upload_clearhist";
} else if (
r.exist_remote &&
r.exist_local &&
r.mtime_remote !== undefined &&
r.mtime_local === undefined
) {
r.decision_branch = 4;
} else if (r.exist_remote && r.exist_local && r.mtime_local === undefined) {
// this must be a folder!
if (!r.key.endsWith("/")) {
throw Error(`${r.key} is not a folder but lacks local mtime`);
}
r.decision = "skip";
r.decision_branch = 5;
} else if (
r.exist_remote &&
!r.exist_local &&
@@ -204,6 +234,7 @@ export const getOperation = (
r.mtime_remote >= r.delete_time_local
) {
r.decision = "download_clearhist";
r.decision_branch = 6;
} else if (
r.exist_remote &&
!r.exist_local &&
@@ -213,6 +244,7 @@ export const getOperation = (
r.mtime_remote < r.delete_time_local
) {
r.decision = "delremote_clearhist";
r.decision_branch = 7;
} else if (
r.exist_remote &&
!r.exist_local &&
@@ -221,8 +253,10 @@ export const getOperation = (
r.delete_time_local == undefined
) {
r.decision = "download";
r.decision_branch = 8;
} else if (!r.exist_remote && r.exist_local && r.mtime_remote === undefined) {
r.decision = "upload_clearhist";
r.decision_branch = 9;
} else if (
!r.exist_remote &&
!r.exist_local &&
@@ -230,6 +264,7 @@ export const getOperation = (
r.mtime_local === undefined
) {
r.decision = "clearhist";
r.decision_branch = 10;
}
return r;
@@ -264,10 +299,26 @@ export const doActualSync = async (
vault,
state.mtime_remote
);
await clearHistoryOfKey(db, state.key);
await clearDeleteRenameHistoryOfKey(db, state.key);
} else if (state.decision === "upload_clearhist") {
await uploadToRemote(s3Client, s3Config, state.key, vault, false);
await clearHistoryOfKey(db, state.key);
const remoteObjMeta = await uploadToRemote(
s3Client,
s3Config,
state.key,
vault,
false
);
await upsertSyncMetaMappingDataS3(
db,
state.key,
state.mtime_local,
state.size_local,
state.key,
remoteObjMeta.LastModified.valueOf(),
remoteObjMeta.ContentLength,
remoteObjMeta.ETag
);
await clearDeleteRenameHistoryOfKey(db, state.key);
} else if (state.decision === "download") {
await mkdirpInVault(state.key, vault);
await downloadFromRemote(
@@ -279,11 +330,27 @@ export const doActualSync = async (
);
} else if (state.decision === "delremote_clearhist") {
await deleteFromRemote(s3Client, s3Config, state.key);
await clearHistoryOfKey(db, state.key);
await clearDeleteRenameHistoryOfKey(db, state.key);
} else if (state.decision === "upload") {
await uploadToRemote(s3Client, s3Config, state.key, vault, false);
const remoteObjMeta = await uploadToRemote(
s3Client,
s3Config,
state.key,
vault,
false
);
await upsertSyncMetaMappingDataS3(
db,
state.key,
state.mtime_local,
state.size_local,
state.key,
remoteObjMeta.LastModified.valueOf(),
remoteObjMeta.ContentLength,
remoteObjMeta.ETag
);
} else if (state.decision === "clearhist") {
await clearHistoryOfKey(db, state.key);
await clearDeleteRenameHistoryOfKey(db, state.key);
} else {
throw Error("this should never happen!");
}