add mapping of local and remote
This commit is contained in:
+99
-32
@@ -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!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user