add vault name into dbs

This commit is contained in:
fyears 2022-01-08 18:41:11 +08:00
parent c637038d95
commit 04f3a0c97c
7 changed files with 258 additions and 61 deletions

View File

@ -65,6 +65,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"loglevel": "^1.8.0", "loglevel": "^1.8.0",
"mime-types": "^2.1.33", "mime-types": "^2.1.33",
"nanoid": "^3.1.30",
"obsidian": "^0.12.0", "obsidian": "^0.12.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"process": "^0.11.10", "process": "^0.11.10",

View File

@ -53,6 +53,7 @@ export interface RemotelySavePluginSettings {
password: string; password: string;
serviceType: SUPPORTED_SERVICES_TYPE; serviceType: SUPPORTED_SERVICES_TYPE;
currLogLevel?: string; currLogLevel?: string;
vaultRandomID?: string;
} }
export interface RemoteItem { export interface RemoteItem {

View File

@ -1,7 +1,7 @@
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian"; import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
import type { SyncPlanType } from "./sync"; import type { SyncPlanType } from "./sync";
import { readAllSyncPlanRecordTexts } from "./localdb"; import { readAllSyncPlanRecordTextsByVault } from "./localdb";
import type { InternalDBs } from "./localdb"; import type { InternalDBs } from "./localdb";
import { mkdirpInVault } from "./misc"; import { mkdirpInVault } from "./misc";
@ -11,10 +11,14 @@ const log = origLog.getLogger("rs-default");
const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/"; const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX = "sync_plans_hist_exported_on_"; const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX = "sync_plans_hist_exported_on_";
export const exportSyncPlansToFiles = async (db: InternalDBs, vault: Vault) => { export const exportVaultSyncPlansToFiles = async (
db: InternalDBs,
vault: Vault,
vaultRandomID: string
) => {
log.info("exporting"); log.info("exporting");
await mkdirpInVault(DEFAULT_DEBUG_FOLDER, vault); await mkdirpInVault(DEFAULT_DEBUG_FOLDER, vault);
const records = await readAllSyncPlanRecordTexts(db); const records = await readAllSyncPlanRecordTextsByVault(db, vaultRandomID);
let md = ""; let md = "";
if (records.length === 0) { if (records.length === 0) {
md = "No sync plans history found"; md = "No sync plans history found";

View File

@ -9,7 +9,8 @@ export type LocalForage = typeof localforage;
import * as origLog from "loglevel"; import * as origLog from "loglevel";
const log = origLog.getLogger("rs-default"); const log = origLog.getLogger("rs-default");
export const DEFAULT_DB_VERSION_NUMBER: number = 20211114; const DB_VERSION_NUMBER_IN_HISTORY = [20211114, 20220108];
export const DEFAULT_DB_VERSION_NUMBER: number = 20220108;
export const DEFAULT_DB_NAME = "remotelysavedb"; export const DEFAULT_DB_NAME = "remotelysavedb";
export const DEFAULT_TBL_VERSION = "schemaversion"; export const DEFAULT_TBL_VERSION = "schemaversion";
export const DEFAULT_TBL_DELETE_HISTORY = "filefolderoperationhistory"; export const DEFAULT_TBL_DELETE_HISTORY = "filefolderoperationhistory";
@ -25,6 +26,7 @@ export interface FileFolderHistoryRecord {
actionType: "delete" | "rename"; actionType: "delete" | "rename";
keyType: "folder" | "file"; keyType: "folder" | "file";
renameTo: string; renameTo: string;
vaultRandomID: string;
} }
interface SyncMetaMappingRecord { interface SyncMetaMappingRecord {
@ -37,12 +39,14 @@ interface SyncMetaMappingRecord {
remoteExtraKey: string; remoteExtraKey: string;
remoteType: SUPPORTED_SERVICES_TYPE; remoteType: SUPPORTED_SERVICES_TYPE;
keyType: "folder" | "file"; keyType: "folder" | "file";
vaultRandomID: string;
} }
interface SyncPlanRecord { interface SyncPlanRecord {
ts: number; ts: number;
remoteType: string; remoteType: string;
syncPlan: string; syncPlan: string;
vaultRandomID: string;
} }
export interface InternalDBs { export interface InternalDBs {
@ -52,7 +56,103 @@ export interface InternalDBs {
syncPlansTbl: LocalForage; syncPlansTbl: LocalForage;
} }
export const prepareDBs = async () => { /**
* This migration mainly aims to assign vault name or vault id into all tables.
* @param db
* @param vaultRandomID
*/
const migrateDBsFrom20211114To20220108 = async (
db: InternalDBs,
vaultRandomID: string
) => {
const oldVer = 20211114;
const newVer = 20220108;
log.debug(`start upgrading internal db from ${oldVer} to ${newVer}`);
const allPromisesToWait: Promise<any>[] = [];
log.debug("assign vault id to any delete history");
const keysInDeleteHistoryTbl = await db.deleteHistoryTbl.keys();
for (const key of keysInDeleteHistoryTbl) {
if (key.startsWith(vaultRandomID)) {
continue;
}
const value = (await db.deleteHistoryTbl.getItem(
key
)) as FileFolderHistoryRecord;
if (value === null || value === undefined) {
continue;
}
if (value.vaultRandomID === undefined || value.vaultRandomID === "") {
value.vaultRandomID = vaultRandomID;
}
const newKey = `${vaultRandomID}\t${key}`;
allPromisesToWait.push(db.deleteHistoryTbl.setItem(newKey, value));
allPromisesToWait.push(db.deleteHistoryTbl.removeItem(key));
}
log.debug("assign vault id to any sync mapping");
const keysInSyncMappingTbl = await db.syncMappingTbl.keys();
for (const key of keysInSyncMappingTbl) {
if (key.startsWith(vaultRandomID)) {
continue;
}
const value = (await db.syncMappingTbl.getItem(
key
)) as SyncMetaMappingRecord;
if (value === null || value === undefined) {
continue;
}
if (value.vaultRandomID === undefined || value.vaultRandomID === "") {
value.vaultRandomID = vaultRandomID;
}
const newKey = `${vaultRandomID}\t${key}`;
allPromisesToWait.push(db.syncMappingTbl.setItem(newKey, value));
allPromisesToWait.push(db.syncMappingTbl.removeItem(key));
}
log.debug("assign vault id to any sync plan records");
const keysInSyncPlansTbl = await db.syncPlansTbl.keys();
for (const key of keysInSyncPlansTbl) {
if (key.startsWith(vaultRandomID)) {
continue;
}
const value = (await db.syncPlansTbl.getItem(key)) as SyncPlanRecord;
if (value === null || value === undefined) {
continue;
}
if (value.vaultRandomID === undefined || value.vaultRandomID === "") {
value.vaultRandomID = vaultRandomID;
}
const newKey = `${vaultRandomID}\t${key}`;
allPromisesToWait.push(db.syncPlansTbl.setItem(newKey, value));
allPromisesToWait.push(db.syncPlansTbl.removeItem(key));
}
log.debug("finally update version if everything is ok");
await Promise.all(allPromisesToWait);
await db.versionTbl.setItem("version", newVer);
log.debug(`finish upgrading internal db from ${oldVer} to ${newVer}`);
};
const migrateDBs = async (
db: InternalDBs,
oldVer: number,
newVer: number,
vaultRandomID: string
) => {
if (oldVer === newVer) {
return;
}
if (oldVer === 20211114 && newVer === 20220108) {
return await migrateDBsFrom20211114To20220108(db, vaultRandomID);
}
// not implemented
throw Error(`not supported internal db changes from ${oldVer} to ${newVer}`);
};
export const prepareDBs = async (vaultRandomID: string) => {
const db = { const db = {
versionTbl: localforage.createInstance({ versionTbl: localforage.createInstance({
name: DEFAULT_DB_NAME, name: DEFAULT_DB_NAME,
@ -74,11 +174,22 @@ export const prepareDBs = async () => {
const originalVersion = (await db.versionTbl.getItem("version")) as number; const originalVersion = (await db.versionTbl.getItem("version")) as number;
if (originalVersion === null) { if (originalVersion === null) {
log.debug(
`no internal db version, setting it to ${DEFAULT_DB_VERSION_NUMBER}`
);
await db.versionTbl.setItem("version", DEFAULT_DB_VERSION_NUMBER); await db.versionTbl.setItem("version", DEFAULT_DB_VERSION_NUMBER);
} else if (originalVersion === DEFAULT_DB_VERSION_NUMBER) { } else if (originalVersion === DEFAULT_DB_VERSION_NUMBER) {
// do nothing // do nothing
} else { } else {
await migrateDBs(db, originalVersion, DEFAULT_DB_VERSION_NUMBER); log.debug(
`trying to upgrade db version from ${originalVersion} to ${DEFAULT_DB_VERSION_NUMBER}`
);
await migrateDBs(
db,
originalVersion,
DEFAULT_DB_VERSION_NUMBER,
vaultRandomID
);
} }
log.info("db connected"); log.info("db connected");
@ -103,33 +214,32 @@ export const destroyDBs = async () => {
}; };
}; };
const migrateDBs = async (db: InternalDBs, oldVer: number, newVer: number) => { export const loadDeleteRenameHistoryTableByVault = async (
if (oldVer === newVer) { db: InternalDBs,
return; vaultRandomID: string
} ) => {
// not implemented
throw Error(`not supported internal db changes from ${oldVer} to ${newVer}`);
};
export const loadDeleteRenameHistoryTable = async (db: InternalDBs) => {
const records = [] as FileFolderHistoryRecord[]; const records = [] as FileFolderHistoryRecord[];
await db.deleteHistoryTbl.iterate((value, key, iterationNumber) => { await db.deleteHistoryTbl.iterate((value, key, iterationNumber) => {
if (key.startsWith(`${vaultRandomID}\t`)) {
records.push(value as FileFolderHistoryRecord); records.push(value as FileFolderHistoryRecord);
}
}); });
records.sort((a, b) => a.actionWhen - b.actionWhen); // ascending records.sort((a, b) => a.actionWhen - b.actionWhen); // ascending
return records; return records;
}; };
export const clearDeleteRenameHistoryOfKey = async ( export const clearDeleteRenameHistoryOfKeyAndVault = async (
db: InternalDBs, db: InternalDBs,
key: string key: string,
vaultRandomID: string
) => { ) => {
await db.deleteHistoryTbl.removeItem(key); await db.deleteHistoryTbl.removeItem(`${vaultRandomID}\t${key}`);
}; };
export const insertDeleteRecord = async ( export const insertDeleteRecordByVault = async (
db: InternalDBs, db: InternalDBs,
fileOrFolder: TAbstractFile fileOrFolder: TAbstractFile,
vaultRandomID: string
) => { ) => {
// log.info(fileOrFolder); // log.info(fileOrFolder);
let k: FileFolderHistoryRecord; let k: FileFolderHistoryRecord;
@ -143,6 +253,7 @@ export const insertDeleteRecord = async (
actionType: "delete", actionType: "delete",
keyType: "file", keyType: "file",
renameTo: "", renameTo: "",
vaultRandomID: vaultRandomID,
}; };
} else if (fileOrFolder instanceof TFolder) { } else if (fileOrFolder instanceof TFolder) {
// key should endswith "/" // key should endswith "/"
@ -158,15 +269,17 @@ export const insertDeleteRecord = async (
actionType: "delete", actionType: "delete",
keyType: "folder", keyType: "folder",
renameTo: "", renameTo: "",
vaultRandomID: vaultRandomID,
}; };
} }
await db.deleteHistoryTbl.setItem(k.key, k); await db.deleteHistoryTbl.setItem(`${vaultRandomID}\t${k.key}`, k);
}; };
export const insertRenameRecord = async ( export const insertRenameRecordByVault = async (
db: InternalDBs, db: InternalDBs,
fileOrFolder: TAbstractFile, fileOrFolder: TAbstractFile,
oldPath: string oldPath: string,
vaultRandomID: string
) => { ) => {
// log.info(fileOrFolder); // log.info(fileOrFolder);
let k: FileFolderHistoryRecord; let k: FileFolderHistoryRecord;
@ -180,6 +293,7 @@ export const insertRenameRecord = async (
actionType: "rename", actionType: "rename",
keyType: "file", keyType: "file",
renameTo: fileOrFolder.path, renameTo: fileOrFolder.path,
vaultRandomID: vaultRandomID,
}; };
} else if (fileOrFolder instanceof TFolder) { } else if (fileOrFolder instanceof TFolder) {
const key = oldPath.endsWith("/") ? oldPath : `${oldPath}/`; const key = oldPath.endsWith("/") ? oldPath : `${oldPath}/`;
@ -195,12 +309,13 @@ export const insertRenameRecord = async (
actionType: "rename", actionType: "rename",
keyType: "folder", keyType: "folder",
renameTo: renameTo, renameTo: renameTo,
vaultRandomID: vaultRandomID,
}; };
} }
await db.deleteHistoryTbl.setItem(k.key, k); await db.deleteHistoryTbl.setItem(`${vaultRandomID}\t${k.key}`, k);
}; };
export const upsertSyncMetaMappingData = async ( export const upsertSyncMetaMappingDataByVault = async (
serviceType: SUPPORTED_SERVICES_TYPE, serviceType: SUPPORTED_SERVICES_TYPE,
db: InternalDBs, db: InternalDBs,
localKey: string, localKey: string,
@ -209,7 +324,8 @@ export const upsertSyncMetaMappingData = async (
remoteKey: string, remoteKey: string,
remoteMTime: number, remoteMTime: number,
remoteSize: number, remoteSize: number,
remoteExtraKey: string /* ETag from s3 */ remoteExtraKey: string,
vaultRandomID: string
) => { ) => {
const aggregratedInfo: SyncMetaMappingRecord = { const aggregratedInfo: SyncMetaMappingRecord = {
localKey: localKey, localKey: localKey,
@ -221,19 +337,24 @@ export const upsertSyncMetaMappingData = async (
remoteExtraKey: remoteExtraKey, remoteExtraKey: remoteExtraKey,
remoteType: serviceType, remoteType: serviceType,
keyType: localKey.endsWith("/") ? "folder" : "file", keyType: localKey.endsWith("/") ? "folder" : "file",
vaultRandomID: vaultRandomID,
}; };
await db.syncMappingTbl.setItem(remoteKey, aggregratedInfo); await db.syncMappingTbl.setItem(
`${vaultRandomID}\t${remoteKey}`,
aggregratedInfo
);
}; };
export const getSyncMetaMappingByRemoteKey = async ( export const getSyncMetaMappingByRemoteKeyAndVault = async (
serviceType: SUPPORTED_SERVICES_TYPE, serviceType: SUPPORTED_SERVICES_TYPE,
db: InternalDBs, db: InternalDBs,
remoteKey: string, remoteKey: string,
remoteMTime: number, remoteMTime: number,
remoteExtraKey: string remoteExtraKey: string,
vaultRandomID: string
) => { ) => {
const potentialItem = (await db.syncMappingTbl.getItem( const potentialItem = (await db.syncMappingTbl.getItem(
remoteKey `${vaultRandomID}\t${remoteKey}`
)) as SyncMetaMappingRecord; )) as SyncMetaMappingRecord;
if (potentialItem === null) { if (potentialItem === null) {
@ -258,26 +379,33 @@ export const clearAllSyncMetaMapping = async (db: InternalDBs) => {
await db.syncMappingTbl.clear(); await db.syncMappingTbl.clear();
}; };
export const insertSyncPlanRecord = async ( export const insertSyncPlanRecordByVault = async (
db: InternalDBs, db: InternalDBs,
syncPlan: SyncPlanType syncPlan: SyncPlanType,
vaultRandomID: string
) => { ) => {
const record = { const record = {
ts: syncPlan.ts, ts: syncPlan.ts,
vaultRandomID: vaultRandomID,
remoteType: syncPlan.remoteType, remoteType: syncPlan.remoteType,
syncPlan: JSON.stringify(syncPlan /* directly stringify */, null, 2), syncPlan: JSON.stringify(syncPlan /* directly stringify */, null, 2),
} as SyncPlanRecord; } as SyncPlanRecord;
await db.syncPlansTbl.setItem(`${syncPlan.ts}`, record); await db.syncPlansTbl.setItem(`${vaultRandomID}\t${syncPlan.ts}`, record);
}; };
export const clearAllSyncPlanRecords = async (db: InternalDBs) => { export const clearAllSyncPlanRecords = async (db: InternalDBs) => {
await db.syncPlansTbl.clear(); await db.syncPlansTbl.clear();
}; };
export const readAllSyncPlanRecordTexts = async (db: InternalDBs) => { export const readAllSyncPlanRecordTextsByVault = async (
db: InternalDBs,
vaultRandomID: string
) => {
const records = [] as SyncPlanRecord[]; const records = [] as SyncPlanRecord[];
await db.syncPlansTbl.iterate((value, key, iterationNumber) => { await db.syncPlansTbl.iterate((value, key, iterationNumber) => {
if (key.startsWith(`${vaultRandomID}\t`)) {
records.push(value as SyncPlanRecord); records.push(value as SyncPlanRecord);
}
}); });
records.sort((a, b) => -(a.ts - b.ts)); // descending records.sort((a, b) => -(a.ts - b.ts)); // descending

View File

@ -1,5 +1,6 @@
import { Modal, Notice, Plugin, Setting } from "obsidian"; import { Modal, Notice, Plugin, Setting } from "obsidian";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
import { nanoid } from "nanoid";
import type { RemotelySavePluginSettings } from "./baseTypes"; import type { RemotelySavePluginSettings } from "./baseTypes";
import { import {
COMMAND_CALLBACK, COMMAND_CALLBACK,
@ -10,10 +11,10 @@ import {
import { importQrCodeUri } from "./importExport"; import { importQrCodeUri } from "./importExport";
import type { InternalDBs } from "./localdb"; import type { InternalDBs } from "./localdb";
import { import {
insertDeleteRecord, insertDeleteRecordByVault,
insertRenameRecord, insertRenameRecordByVault,
insertSyncPlanRecord, insertSyncPlanRecordByVault,
loadDeleteRenameHistoryTable, loadDeleteRenameHistoryTableByVault,
prepareDBs, prepareDBs,
} from "./localdb"; } from "./localdb";
import { RemoteClient } from "./remote"; import { RemoteClient } from "./remote";
@ -47,6 +48,7 @@ const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
password: "", password: "",
serviceType: "s3", serviceType: "s3",
currLogLevel: "info", currLogLevel: "info",
vaultRandomID: "",
}; };
interface OAuth2Info { interface OAuth2Info {
@ -86,6 +88,7 @@ export default class RemotelySavePlugin extends Plugin {
} }
await this.checkIfOauthExpires(); await this.checkIfOauthExpires();
await this.checkIfVaultIDAssigned(); // MUST before prepareDB()
await this.prepareDB(); await this.prepareDB();
@ -93,13 +96,22 @@ export default class RemotelySavePlugin extends Plugin {
this.registerEvent( this.registerEvent(
this.app.vault.on("delete", async (fileOrFolder) => { this.app.vault.on("delete", async (fileOrFolder) => {
await insertDeleteRecord(this.db, fileOrFolder); await insertDeleteRecordByVault(
this.db,
fileOrFolder,
this.settings.vaultRandomID
);
}) })
); );
this.registerEvent( this.registerEvent(
this.app.vault.on("rename", async (fileOrFolder, oldPath) => { this.app.vault.on("rename", async (fileOrFolder, oldPath) => {
await insertRenameRecord(this.db, fileOrFolder, oldPath); await insertRenameRecordByVault(
this.db,
fileOrFolder,
oldPath,
this.settings.vaultRandomID
);
}) })
); );
@ -316,7 +328,10 @@ export default class RemotelySavePlugin extends Plugin {
new Notice("3/7 Starting to fetch local meta data."); new Notice("3/7 Starting to fetch local meta data.");
this.syncStatus = "getting_local_meta"; this.syncStatus = "getting_local_meta";
const local = this.app.vault.getAllLoadedFiles(); const local = this.app.vault.getAllLoadedFiles();
const localHistory = await loadDeleteRenameHistoryTable(this.db); const localHistory = await loadDeleteRenameHistoryTableByVault(
this.db,
this.settings.vaultRandomID
);
// log.info(local); // log.info(local);
// log.info(localHistory); // log.info(localHistory);
@ -338,11 +353,16 @@ export default class RemotelySavePlugin extends Plugin {
local, local,
localHistory, localHistory,
this.db, this.db,
this.settings.vaultRandomID,
client.serviceType, client.serviceType,
this.settings.password this.settings.password
); );
log.info(syncPlan.mixedStates); // for debugging log.info(syncPlan.mixedStates); // for debugging
await insertSyncPlanRecord(this.db, syncPlan); await insertSyncPlanRecordByVault(
this.db,
syncPlan,
this.settings.vaultRandomID
);
// The operations above are read only and kind of safe. // The operations above are read only and kind of safe.
// The operations below begins to write or delete (!!!) something. // The operations below begins to write or delete (!!!) something.
@ -353,6 +373,7 @@ export default class RemotelySavePlugin extends Plugin {
await doActualSync( await doActualSync(
client, client,
this.db, this.db,
this.settings.vaultRandomID,
this.app.vault, this.app.vault,
syncPlan, syncPlan,
this.settings.password, this.settings.password,
@ -481,8 +502,18 @@ export default class RemotelySavePlugin extends Plugin {
} }
} }
async checkIfVaultIDAssigned() {
if (
this.settings.vaultRandomID === undefined ||
this.settings.vaultRandomID === ""
) {
this.settings.vaultRandomID = nanoid();
await this.saveSettings();
}
}
async prepareDB() { async prepareDB() {
this.db = await prepareDBs(); this.db = await prepareDBs(this.settings.vaultRandomID);
} }
destroyDBs() { destroyDBs() {
@ -495,7 +526,7 @@ export default class RemotelySavePlugin extends Plugin {
pathName: string, pathName: string,
decision: string decision: string
) { ) {
const msg = `${i}/${totalCount}, ${decision}, ${pathName}`; const msg = `syncing progress=${i}/${totalCount},decision=${decision},path=${pathName}`;
this.currSyncMsg = msg; this.currSyncMsg = msg;
} }
} }

View File

@ -1,6 +1,6 @@
import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian"; import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian";
import type { SUPPORTED_SERVICES_TYPE, WebdavAuthType } from "./baseTypes"; import type { SUPPORTED_SERVICES_TYPE, WebdavAuthType } from "./baseTypes";
import { exportSyncPlansToFiles } from "./debugMode"; import { exportVaultSyncPlansToFiles } from "./debugMode";
import { exportQrCodeUri } from "./importExport"; import { exportQrCodeUri } from "./importExport";
import { import {
clearAllSyncMetaMapping, clearAllSyncMetaMapping,
@ -19,6 +19,7 @@ import {
DEFAULT_ONEDRIVE_CONFIG, DEFAULT_ONEDRIVE_CONFIG,
getAuthUrlAndVerifier as getAuthUrlAndVerifierOnedrive, getAuthUrlAndVerifier as getAuthUrlAndVerifierOnedrive,
} from "./remoteForOnedrive"; } from "./remoteForOnedrive";
import { messyConfigToNormal } from "./configPersist";
import * as origLog from "loglevel"; import * as origLog from "loglevel";
const log = origLog.getLogger("rs-default"); const log = origLog.getLogger("rs-default");
@ -946,6 +947,24 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
log.info(`the log level is changed to ${val}`); log.info(`the log level is changed to ${val}`);
}); });
}); });
const outputCurrSettingsDiv = debugDiv.createDiv("div");
new Setting(outputCurrSettingsDiv)
.setName("output current settings from disk to console")
.setDesc(
"The settings save on disk in encoded. Click this to see the decoded settings in console."
)
.addButton(async (button) => {
button.setButtonText("Output");
button.onClick(async () => {
const c = messyConfigToNormal(await this.plugin.loadData());
if (c.currLogLevel === "debug") {
// no need to ouput it again because debug mode already output it
} else {
log.info(c);
}
new Notice("Finished outputing in console.");
});
});
const syncPlanDiv = debugDiv.createEl("div"); const syncPlanDiv = debugDiv.createEl("div");
new Setting(syncPlanDiv) new Setting(syncPlanDiv)
.setName("export sync plans") .setName("export sync plans")
@ -955,7 +974,11 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
.addButton(async (button) => { .addButton(async (button) => {
button.setButtonText("Export"); button.setButtonText("Export");
button.onClick(async () => { button.onClick(async () => {
await exportSyncPlansToFiles(this.plugin.db, this.app.vault); await exportVaultSyncPlansToFiles(
this.plugin.db,
this.app.vault,
this.plugin.settings.vaultRandomID
);
new Notice("sync plans history exported"); new Notice("sync plans history exported");
}); });
}); });

View File

@ -9,9 +9,9 @@ import {
} from "./encrypt"; } from "./encrypt";
import type { FileFolderHistoryRecord, InternalDBs } from "./localdb"; import type { FileFolderHistoryRecord, InternalDBs } from "./localdb";
import { import {
clearDeleteRenameHistoryOfKey, clearDeleteRenameHistoryOfKeyAndVault,
getSyncMetaMappingByRemoteKey, getSyncMetaMappingByRemoteKeyAndVault,
upsertSyncMetaMappingData, upsertSyncMetaMappingDataByVault,
} from "./localdb"; } from "./localdb";
import { isHiddenPath, isVaildText, mkdirpInVault } from "./misc"; import { isHiddenPath, isVaildText, mkdirpInVault } from "./misc";
import { RemoteClient } from "./remote"; import { RemoteClient } from "./remote";
@ -170,6 +170,7 @@ const ensembleMixedStates = async (
local: TAbstractFile[], local: TAbstractFile[],
deleteHistory: FileFolderHistoryRecord[], deleteHistory: FileFolderHistoryRecord[],
db: InternalDBs, db: InternalDBs,
vaultRandomID: string,
remoteType: SUPPORTED_SERVICES_TYPE, remoteType: SUPPORTED_SERVICES_TYPE,
password: string = "" password: string = ""
) => { ) => {
@ -190,12 +191,13 @@ const ensembleMixedStates = async (
throw Error(`unexpected key=${remoteEncryptedKey}`); throw Error(`unexpected key=${remoteEncryptedKey}`);
} }
} }
const backwardMapping = await getSyncMetaMappingByRemoteKey( const backwardMapping = await getSyncMetaMappingByRemoteKeyAndVault(
remoteType, remoteType,
db, db,
key, key,
entry.lastModified, entry.lastModified,
entry.etag entry.etag,
vaultRandomID
); );
let r = {} as FileOrFolderMixedState; let r = {} as FileOrFolderMixedState;
@ -443,6 +445,7 @@ export const getSyncPlan = async (
local: TAbstractFile[], local: TAbstractFile[],
deleteHistory: FileFolderHistoryRecord[], deleteHistory: FileFolderHistoryRecord[],
db: InternalDBs, db: InternalDBs,
vaultRandomID: string,
remoteType: SUPPORTED_SERVICES_TYPE, remoteType: SUPPORTED_SERVICES_TYPE,
password: string = "" password: string = ""
) => { ) => {
@ -451,6 +454,7 @@ export const getSyncPlan = async (
local, local,
deleteHistory, deleteHistory,
db, db,
vaultRandomID,
remoteType, remoteType,
password password
); );
@ -467,6 +471,7 @@ export const getSyncPlan = async (
const dispatchOperationToActual = async ( const dispatchOperationToActual = async (
key: string, key: string,
vaultRandomID: string,
state: FileOrFolderMixedState, state: FileOrFolderMixedState,
client: RemoteClient, client: RemoteClient,
db: InternalDBs, db: InternalDBs,
@ -501,7 +506,7 @@ const dispatchOperationToActual = async (
password, password,
remoteEncryptedKey remoteEncryptedKey
); );
await clearDeleteRenameHistoryOfKey(db, state.key); await clearDeleteRenameHistoryOfKeyAndVault(db, state.key, vaultRandomID);
} else if (state.decision === "upload_clearhist") { } else if (state.decision === "upload_clearhist") {
const remoteObjMeta = await client.uploadToRemote( const remoteObjMeta = await client.uploadToRemote(
state.key, state.key,
@ -511,7 +516,7 @@ const dispatchOperationToActual = async (
remoteEncryptedKey, remoteEncryptedKey,
foldersCreatedBefore foldersCreatedBefore
); );
await upsertSyncMetaMappingData( await upsertSyncMetaMappingDataByVault(
client.serviceType, client.serviceType,
db, db,
state.key, state.key,
@ -520,9 +525,10 @@ const dispatchOperationToActual = async (
state.key, state.key,
remoteObjMeta.lastModified, remoteObjMeta.lastModified,
remoteObjMeta.size, remoteObjMeta.size,
remoteObjMeta.etag remoteObjMeta.etag,
vaultRandomID
); );
await clearDeleteRenameHistoryOfKey(db, state.key); await clearDeleteRenameHistoryOfKeyAndVault(db, state.key, vaultRandomID);
} else if (state.decision === "download") { } else if (state.decision === "download") {
await mkdirpInVault(state.key, vault); await mkdirpInVault(state.key, vault);
await client.downloadFromRemote( await client.downloadFromRemote(
@ -534,7 +540,7 @@ const dispatchOperationToActual = async (
); );
} else if (state.decision === "delremote_clearhist") { } else if (state.decision === "delremote_clearhist") {
await client.deleteFromRemote(state.key, password, remoteEncryptedKey); await client.deleteFromRemote(state.key, password, remoteEncryptedKey);
await clearDeleteRenameHistoryOfKey(db, state.key); await clearDeleteRenameHistoryOfKeyAndVault(db, state.key, vaultRandomID);
} else if (state.decision === "upload") { } else if (state.decision === "upload") {
const remoteObjMeta = await client.uploadToRemote( const remoteObjMeta = await client.uploadToRemote(
state.key, state.key,
@ -544,7 +550,7 @@ const dispatchOperationToActual = async (
remoteEncryptedKey, remoteEncryptedKey,
foldersCreatedBefore foldersCreatedBefore
); );
await upsertSyncMetaMappingData( await upsertSyncMetaMappingDataByVault(
client.serviceType, client.serviceType,
db, db,
state.key, state.key,
@ -553,10 +559,11 @@ const dispatchOperationToActual = async (
state.key, state.key,
remoteObjMeta.lastModified, remoteObjMeta.lastModified,
remoteObjMeta.size, remoteObjMeta.size,
remoteObjMeta.etag remoteObjMeta.etag,
vaultRandomID
); );
} else if (state.decision === "clearhist") { } else if (state.decision === "clearhist") {
await clearDeleteRenameHistoryOfKey(db, state.key); await clearDeleteRenameHistoryOfKeyAndVault(db, state.key, vaultRandomID);
} else { } else {
throw Error("this should never happen!"); throw Error("this should never happen!");
} }
@ -565,6 +572,7 @@ const dispatchOperationToActual = async (
export const doActualSync = async ( export const doActualSync = async (
client: RemoteClient, client: RemoteClient,
db: InternalDBs, db: InternalDBs,
vaultRandomID: string,
vault: Vault, vault: Vault,
syncPlan: SyncPlanType, syncPlan: SyncPlanType,
password: string = "", password: string = "",
@ -586,6 +594,7 @@ export const doActualSync = async (
} }
await dispatchOperationToActual( await dispatchOperationToActual(
k2, k2,
vaultRandomID,
v2, v2,
client, client,
db, db,