mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-13 09:45:56 +00:00
New feature:
- (Beta) ignore files handling Fixed: - Buttons on lock-detected-dialogue now can be shown in narrow-width devices. Improved: - Some constant has been flattened to be evaluated. - The usage of the deprecated API of obsidian has been reduced. - Now the indexedDB adapter will be enabled while the importing configuration. Misc: - Compiler, framework, and dependencies have been upgraded. - Due to standing for these impacts (especially in esbuild and svelte,) terser has been introduced. Feel free to notify your opinion to me! I do not like to obfuscate the code too.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
build
|
build
|
||||||
.eslintrc.js.bak
|
.eslintrc.js.bak
|
||||||
src/lib/src/patches/pouchdb-utils
|
src/lib/src/patches/pouchdb-utils
|
||||||
|
esbuild.config.mjs
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@ package-lock.json
|
|||||||
|
|
||||||
# build
|
# build
|
||||||
main.js
|
main.js
|
||||||
|
main_org.js
|
||||||
*.js.map
|
*.js.map
|
||||||
|
|
||||||
# obsidian
|
# obsidian
|
||||||
|
|||||||
@@ -1,46 +1,163 @@
|
|||||||
|
//@ts-check
|
||||||
|
|
||||||
import esbuild from "esbuild";
|
import esbuild from "esbuild";
|
||||||
import process from "process";
|
import process from "process";
|
||||||
import builtins from "builtin-modules";
|
import builtins from "builtin-modules";
|
||||||
import sveltePlugin from "esbuild-svelte";
|
import sveltePlugin from "esbuild-svelte";
|
||||||
import sveltePreprocess from "svelte-preprocess";
|
import sveltePreprocess from "svelte-preprocess";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
// import terser from "terser";
|
||||||
|
import { minify } from "terser";
|
||||||
const banner = `/*
|
const banner = `/*
|
||||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD AND TERSER
|
||||||
if you want to view the source, please visit the github repository of this plugin
|
if you want to view the source, please visit the github repository of this plugin
|
||||||
*/
|
*/
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
const prod = process.argv[2] === "production";
|
const prod = process.argv[2] === "production";
|
||||||
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json"));
|
|
||||||
const packageJson = JSON.parse(fs.readFileSync("./package.json"));
|
const terserOpt = {
|
||||||
|
sourceMap: (!prod ? {
|
||||||
|
url: "inline"
|
||||||
|
} : {}),
|
||||||
|
format: {
|
||||||
|
indent_level: 2,
|
||||||
|
beautify: true,
|
||||||
|
comments: "some",
|
||||||
|
ecma: 2018,
|
||||||
|
preamble: banner,
|
||||||
|
webkit: true
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
// parse options
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
// compress options
|
||||||
|
defaults: false,
|
||||||
|
evaluate: true,
|
||||||
|
inline: 3,
|
||||||
|
join_vars: true,
|
||||||
|
loops: true,
|
||||||
|
passes: prod ? 4 : 1,
|
||||||
|
reduce_vars: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
arrows: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
comparisons: true,
|
||||||
|
lhs_constants: true,
|
||||||
|
hoist_props: true,
|
||||||
|
side_effects: true,
|
||||||
|
// if_return: true,
|
||||||
|
},
|
||||||
|
// mangle: {
|
||||||
|
// // mangle options
|
||||||
|
// keep_classnames: true,
|
||||||
|
// keep_fnames: true,
|
||||||
|
|
||||||
|
// properties: {
|
||||||
|
// // mangle property options
|
||||||
|
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
ecma: 2018, // specify one of: 5, 2015, 2016, etc.
|
||||||
|
enclose: false, // or specify true, or "args:values"
|
||||||
|
keep_classnames: true,
|
||||||
|
keep_fnames: true,
|
||||||
|
ie8: false,
|
||||||
|
module: false,
|
||||||
|
// nameCache: null, // or specify a name cache object
|
||||||
|
safari10: false,
|
||||||
|
toplevel: false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json") + "");
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
|
||||||
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
||||||
esbuild
|
|
||||||
.build({
|
/** @type esbuild.Plugin[] */
|
||||||
banner: {
|
const plugins = [{
|
||||||
js: banner,
|
name: 'my-plugin',
|
||||||
},
|
setup(build) {
|
||||||
entryPoints: ["src/main.ts"],
|
let count = 0;
|
||||||
bundle: true,
|
build.onEnd(async result => {
|
||||||
define: {
|
if (count++ === 0) {
|
||||||
"MANIFEST_VERSION": `"${manifestJson.version}"`,
|
console.log('first build:', result);
|
||||||
"PACKAGE_VERSION": `"${packageJson.version}"`,
|
|
||||||
"UPDATE_INFO": `${updateInfo}`,
|
} else {
|
||||||
"global":"window",
|
console.log('subsequent build:');
|
||||||
},
|
}
|
||||||
external: ["obsidian", "electron", "crypto"],
|
if (prod) {
|
||||||
format: "cjs",
|
console.log("Performing terser");
|
||||||
watch: !prod,
|
const src = fs.readFileSync("./main_org.js").toString();
|
||||||
target: "es2018",
|
// @ts-ignore
|
||||||
logLevel: "info",
|
const ret = await minify(src, terserOpt);
|
||||||
sourcemap: prod ? false : "inline",
|
if (ret && ret.code) {
|
||||||
treeShaking: true,
|
fs.writeFileSync("./main.js", ret.code);
|
||||||
platform: "browser",
|
}
|
||||||
plugins: [
|
console.log("Finished terser");
|
||||||
sveltePlugin({
|
} else {
|
||||||
preprocess: sveltePreprocess(),
|
fs.copyFileSync("./main_org.js", "./main.js");
|
||||||
compilerOptions: { css: true },
|
}
|
||||||
}),
|
});
|
||||||
],
|
},
|
||||||
outfile: "main.js",
|
}];
|
||||||
})
|
|
||||||
.catch(() => process.exit(1));
|
const context = await esbuild.context({
|
||||||
|
banner: {
|
||||||
|
js: banner,
|
||||||
|
},
|
||||||
|
entryPoints: ["src/main.ts"],
|
||||||
|
bundle: true,
|
||||||
|
define: {
|
||||||
|
"MANIFEST_VERSION": `"${manifestJson.version}"`,
|
||||||
|
"PACKAGE_VERSION": `"${packageJson.version}"`,
|
||||||
|
"UPDATE_INFO": `${updateInfo}`,
|
||||||
|
"global": "window",
|
||||||
|
},
|
||||||
|
external: [
|
||||||
|
"obsidian",
|
||||||
|
"electron",
|
||||||
|
"crypto",
|
||||||
|
"@codemirror/autocomplete",
|
||||||
|
"@codemirror/collab",
|
||||||
|
"@codemirror/commands",
|
||||||
|
"@codemirror/language",
|
||||||
|
"@codemirror/lint",
|
||||||
|
"@codemirror/search",
|
||||||
|
"@codemirror/state",
|
||||||
|
"@codemirror/view",
|
||||||
|
"@lezer/common",
|
||||||
|
"@lezer/highlight",
|
||||||
|
"@lezer/lr"],
|
||||||
|
// minifyWhitespace: true,
|
||||||
|
format: "cjs",
|
||||||
|
target: "es2018",
|
||||||
|
logLevel: "info",
|
||||||
|
platform: "browser",
|
||||||
|
sourcemap: prod ? false : "inline",
|
||||||
|
treeShaking: true,
|
||||||
|
outfile: "main_org.js",
|
||||||
|
minifyWhitespace: false,
|
||||||
|
minifySyntax: false,
|
||||||
|
minifyIdentifiers: false,
|
||||||
|
minify: false,
|
||||||
|
|
||||||
|
// keepNames: true,
|
||||||
|
plugins: [
|
||||||
|
sveltePlugin({
|
||||||
|
preprocess: sveltePreprocess(),
|
||||||
|
compilerOptions: { css: true, preserveComments: true },
|
||||||
|
}),
|
||||||
|
...plugins
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (prod) {
|
||||||
|
await context.rebuild();
|
||||||
|
process.exit(0);
|
||||||
|
} else {
|
||||||
|
await context.watch();
|
||||||
|
}
|
||||||
|
|||||||
3284
package-lock.json
generated
3284
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -13,43 +13,51 @@
|
|||||||
"author": "vorotamoroz",
|
"author": "vorotamoroz",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/svelte": "^4.0.1",
|
"@tsconfig/svelte": "^5.0.0",
|
||||||
"@types/diff-match-patch": "^1.0.32",
|
"@types/diff-match-patch": "^1.0.32",
|
||||||
"@types/node": "^20.2.5",
|
"@types/node": "^20.2.5",
|
||||||
"@types/pouchdb": "^6.4.0",
|
"@types/pouchdb": "^6.4.0",
|
||||||
"@types/pouchdb-browser": "^6.1.3",
|
"@types/pouchdb-browser": "^6.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
"@types/pouchdb-adapter-http": "^6.1.3",
|
||||||
"@typescript-eslint/parser": "^5.54.0",
|
"@types/pouchdb-adapter-idb": "^6.1.4",
|
||||||
|
"@types/pouchdb-core": "^7.0.11",
|
||||||
|
"@types/pouchdb-mapreduce": "^6.1.7",
|
||||||
|
"@types/pouchdb-replication": "^6.4.4",
|
||||||
|
"@types/transform-pouch": "^1.0.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||||
|
"@typescript-eslint/parser": "^6.2.1",
|
||||||
"builtin-modules": "^3.3.0",
|
"builtin-modules": "^3.3.0",
|
||||||
"esbuild": "0.15.15",
|
"esbuild": "0.18.17",
|
||||||
"esbuild-svelte": "^0.7.3",
|
"esbuild-svelte": "^0.7.4",
|
||||||
"eslint": "^8.35.0",
|
"eslint": "^8.46.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.28.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"obsidian": "^1.1.1",
|
"obsidian": "^1.3.5",
|
||||||
"postcss": "^8.4.21",
|
"postcss": "^8.4.27",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"pouchdb-adapter-http": "^8.0.1",
|
"pouchdb-adapter-http": "^8.0.1",
|
||||||
"pouchdb-adapter-idb": "^8.0.1",
|
"pouchdb-adapter-idb": "^8.0.1",
|
||||||
"pouchdb-adapter-indexeddb": "^8.0.1",
|
"pouchdb-adapter-indexeddb": "^8.0.1",
|
||||||
"pouchdb-core": "^8.0.1",
|
"pouchdb-core": "^8.0.1",
|
||||||
|
"pouchdb-errors": "^8.0.1",
|
||||||
"pouchdb-find": "^8.0.1",
|
"pouchdb-find": "^8.0.1",
|
||||||
"pouchdb-mapreduce": "^8.0.1",
|
"pouchdb-mapreduce": "^8.0.1",
|
||||||
"pouchdb-merge": "^8.0.1",
|
"pouchdb-merge": "^8.0.1",
|
||||||
"pouchdb-errors": "^8.0.1",
|
|
||||||
"pouchdb-replication": "^8.0.1",
|
"pouchdb-replication": "^8.0.1",
|
||||||
"pouchdb-utils": "^8.0.1",
|
"pouchdb-utils": "^8.0.1",
|
||||||
"svelte": "^3.59.1",
|
"svelte": "^4.1.2",
|
||||||
"svelte-preprocess": "^5.0.3",
|
"svelte-preprocess": "^5.0.4",
|
||||||
|
"terser": "^5.19.2",
|
||||||
"transform-pouch": "^2.0.0",
|
"transform-pouch": "^2.0.0",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.6.1",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
"idb": "^7.1.1",
|
"idb": "^7.1.1",
|
||||||
"xxhash-wasm": "^0.4.2",
|
"minimatch": "^9.0.3",
|
||||||
|
"xxhash-wasm": "0.4.2",
|
||||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import { writable } from 'svelte/store';
|
|||||||
import { Notice, type PluginManifest, parseYaml } from "./deps";
|
import { Notice, type PluginManifest, parseYaml } from "./deps";
|
||||||
|
|
||||||
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID, AnyEntry } from "./lib/src/types";
|
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID, AnyEntry } from "./lib/src/types";
|
||||||
import { LOG_LEVEL } from "./lib/src/types";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "./types";
|
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "./types";
|
||||||
import { delay, getDocData } from "./lib/src/utils";
|
import { delay, getDocData } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
@@ -139,7 +139,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
Logger("Scanning customizations : done");
|
Logger("Scanning customizations : done");
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Scanning customizations : failed");
|
Logger("Scanning customizations : failed");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -165,13 +165,14 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
await this.updatePluginList(showMessage);
|
await this.updatePluginList(showMessage);
|
||||||
}
|
}
|
||||||
async updatePluginList(showMessage: boolean, updatedDocumentPath?: FilePathWithPrefix): Promise<void> {
|
async updatePluginList(showMessage: boolean, updatedDocumentPath?: FilePathWithPrefix): Promise<void> {
|
||||||
const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO;
|
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||||
// pluginList.set([]);
|
// pluginList.set([]);
|
||||||
if (!this.settings.usePluginSync) {
|
if (!this.settings.usePluginSync) {
|
||||||
this.pluginList = [];
|
this.pluginList = [];
|
||||||
pluginList.set(this.pluginList)
|
pluginList.set(this.pluginList)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await Promise.resolve(); // Just to prevent warning.
|
||||||
scheduleTask("update-plugin-list-task", 200, async () => {
|
scheduleTask("update-plugin-list-task", 200, async () => {
|
||||||
await runWithLock("update-plugin-list", false, async () => {
|
await runWithLock("update-plugin-list", false, async () => {
|
||||||
try {
|
try {
|
||||||
@@ -191,7 +192,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
try {
|
try {
|
||||||
count++;
|
count++;
|
||||||
if (count % 10 == 0) Logger(`Enumerating files... ${count}`, logLevel, "get-plugins");
|
if (count % 10 == 0) Logger(`Enumerating files... ${count}`, logLevel, "get-plugins");
|
||||||
Logger(`plugin-${path}`, LOG_LEVEL.VERBOSE);
|
Logger(`plugin-${path}`, LOG_LEVEL_VERBOSE);
|
||||||
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
||||||
if (wx) {
|
if (wx) {
|
||||||
const data = deserialize(getDocData(wx.data), {}) as PluginDataEx;
|
const data = deserialize(getDocData(wx.data), {}) as PluginDataEx;
|
||||||
@@ -211,7 +212,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
// return entries;
|
// return entries;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
//TODO
|
//TODO
|
||||||
Logger(`Something happened at enumerating customization :${path}`, LOG_LEVEL.NOTICE);
|
Logger(`Something happened at enumerating customization :${path}`, LOG_LEVEL_NOTICE);
|
||||||
console.warn(ex);
|
console.warn(ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -257,7 +258,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
const fileB = pluginDataB.files[0];
|
const fileB = pluginDataB.files[0];
|
||||||
const docAx = { ...docA, ...fileA } as LoadedEntry, docBx = { ...docB, ...fileB } as LoadedEntry
|
const docAx = { ...docA, ...fileA } as LoadedEntry, docBx = { ...docB, ...fileB } as LoadedEntry
|
||||||
return runWithLock("config:merge-data", false, () => new Promise((res) => {
|
return runWithLock("config:merge-data", false, () => new Promise((res) => {
|
||||||
Logger("Opening data-merging dialog", LOG_LEVEL.VERBOSE);
|
Logger("Opening data-merging dialog", LOG_LEVEL_VERBOSE);
|
||||||
// const docs = [docA, docB];
|
// const docs = [docA, docB];
|
||||||
const path = stripAllPrefixes(docAx.path.split("/").slice(-1).join("/") as FilePath);
|
const path = stripAllPrefixes(docAx.path.split("/").slice(-1).join("/") as FilePath);
|
||||||
const modal = new JsonResolveModal(this.app, path, [docAx, docBx], async (keep, result) => {
|
const modal = new JsonResolveModal(this.app, path, [docAx, docBx], async (keep, result) => {
|
||||||
@@ -266,7 +267,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
res(await this.applyData(pluginDataA, result));
|
res(await this.applyData(pluginDataA, result));
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Could not apply merged file");
|
Logger("Could not apply merged file");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
res(false);
|
res(false);
|
||||||
}
|
}
|
||||||
}, "📡", "🛰️", "B");
|
}, "📡", "🛰️", "B");
|
||||||
@@ -299,7 +300,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Applying ${f.filename} of ${data.displayName || data.name}.. Failed`);
|
Logger(`Applying ${f.filename} of ${data.displayName || data.name}.. Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -307,7 +308,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
await this.storeCustomizationFiles(uPath);
|
await this.storeCustomizationFiles(uPath);
|
||||||
await this.updatePluginList(true, uPath);
|
await this.updatePluginList(true, uPath);
|
||||||
await delay(100);
|
await delay(100);
|
||||||
Logger(`Config ${data.displayName || data.name} has been applied`, LOG_LEVEL.NOTICE);
|
Logger(`Config ${data.displayName || data.name} has been applied`, LOG_LEVEL_NOTICE);
|
||||||
if (data.category == "PLUGIN_DATA" || data.category == "PLUGIN_MAIN") {
|
if (data.category == "PLUGIN_DATA" || data.category == "PLUGIN_MAIN") {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[];
|
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[];
|
||||||
@@ -315,12 +316,12 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>;
|
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>;
|
||||||
const pluginManifest = manifests.find((manifest) => enabledPlugins.has(manifest.id) && manifest.dir == `${baseDir}/plugins/${data.name}`);
|
const pluginManifest = manifests.find((manifest) => enabledPlugins.has(manifest.id) && manifest.dir == `${baseDir}/plugins/${data.name}`);
|
||||||
if (pluginManifest) {
|
if (pluginManifest) {
|
||||||
Logger(`Unloading plugin: ${pluginManifest.name}`, LOG_LEVEL.NOTICE, "plugin-reload-" + pluginManifest.id);
|
Logger(`Unloading plugin: ${pluginManifest.name}`, LOG_LEVEL_NOTICE, "plugin-reload-" + pluginManifest.id);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.unloadPlugin(pluginManifest.id);
|
await this.app.plugins.unloadPlugin(pluginManifest.id);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.loadPlugin(pluginManifest.id);
|
await this.app.plugins.loadPlugin(pluginManifest.id);
|
||||||
Logger(`Plugin reloaded: ${pluginManifest.name}`, LOG_LEVEL.NOTICE, "plugin-reload-" + pluginManifest.id);
|
Logger(`Plugin reloaded: ${pluginManifest.name}`, LOG_LEVEL_NOTICE, "plugin-reload-" + pluginManifest.id);
|
||||||
}
|
}
|
||||||
} else if (data.category == "CONFIG") {
|
} else if (data.category == "CONFIG") {
|
||||||
scheduleTask("configReload", 250, async () => {
|
scheduleTask("configReload", 250, async () => {
|
||||||
@@ -333,7 +334,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
return true;
|
return true;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Applying ${data.displayName || data.name}.. Failed`);
|
Logger(`Applying ${data.displayName || data.name}.. Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,11 +343,11 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
if (data.documentPath) {
|
if (data.documentPath) {
|
||||||
await this.deleteConfigOnDatabase(data.documentPath);
|
await this.deleteConfigOnDatabase(data.documentPath);
|
||||||
await this.updatePluginList(false, data.documentPath);
|
await this.updatePluginList(false, data.documentPath);
|
||||||
Logger(`Delete: ${data.documentPath}`, LOG_LEVEL.NOTICE);
|
Logger(`Delete: ${data.documentPath}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Failed to delete: ${data.documentPath}`, LOG_LEVEL.NOTICE);
|
Logger(`Failed to delete: ${data.documentPath}`, LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -433,12 +434,12 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
displayName = `${json.name}`;
|
displayName = `${json.name}`;
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Configuration sync data: ${path} looks like manifest, but could not read the version`, LOG_LEVEL.INFO);
|
Logger(`Configuration sync data: ${path} looks like manifest, but could not read the version`, LOG_LEVEL_INFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`The file ${path} could not be encoded`);
|
Logger(`The file ${path} could not be encoded`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const mtime = stat.mtime;
|
const mtime = stat.mtime;
|
||||||
@@ -465,7 +466,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
||||||
const term = termOverRide || this.plugin.deviceAndVaultName;
|
const term = termOverRide || this.plugin.deviceAndVaultName;
|
||||||
if (term == "") {
|
if (term == "") {
|
||||||
Logger("We have to configure the device name", LOG_LEVEL.NOTICE);
|
Logger("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const vf = this.filenameToUnifiedKey(path, term);
|
const vf = this.filenameToUnifiedKey(path, term);
|
||||||
@@ -501,7 +502,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
for (const target of fileTargets) {
|
for (const target of fileTargets) {
|
||||||
const data = await this.makeEntryFromFile(target);
|
const data = await this.makeEntryFromFile(target);
|
||||||
if (data == false) {
|
if (data == false) {
|
||||||
// Logger(`Config: skipped: ${target} `, LOG_LEVEL.VERBOSE);
|
// Logger(`Config: skipped: ${target} `, LOG_LEVEL_VERBOSE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (data.version) {
|
if (data.version) {
|
||||||
@@ -543,7 +544,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (old.mtime == mtime) {
|
if (old.mtime == mtime) {
|
||||||
// Logger(`STORAGE --> DB:${file.path}: (hidden) Not changed`, LOG_LEVEL.VERBOSE);
|
// Logger(`STORAGE --> DB:${file.path}: (hidden) Not changed`, LOG_LEVEL_VERBOSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
saveData =
|
saveData =
|
||||||
@@ -564,7 +565,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
return ret;
|
return ret;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Failed`);
|
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -591,11 +592,11 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
|
|
||||||
|
|
||||||
async scanAllConfigFiles(showMessage: boolean) {
|
async scanAllConfigFiles(showMessage: boolean) {
|
||||||
const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO;
|
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||||
Logger("Scanning customizing files.", logLevel, "scan-all-config");
|
Logger("Scanning customizing files.", logLevel, "scan-all-config");
|
||||||
const term = this.plugin.deviceAndVaultName;
|
const term = this.plugin.deviceAndVaultName;
|
||||||
if (term == "") {
|
if (term == "") {
|
||||||
Logger("We have to configure the device name", LOG_LEVEL.NOTICE);
|
Logger("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filesAll = await this.scanInternalFiles();
|
const filesAll = await this.scanInternalFiles();
|
||||||
@@ -643,7 +644,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
Logger(`STORAGE -x> DB:${prefixedFileName}: (config) Done`);
|
Logger(`STORAGE -x> DB:${prefixedFileName}: (config) Done`);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`STORAGE -x> DB:${prefixedFileName}: (config) Failed`);
|
Logger(`STORAGE -x> DB:${prefixedFileName}: (config) Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Notice, normalizePath, type PluginManifest } from "./deps";
|
import { Notice, normalizePath, type PluginManifest } from "./deps";
|
||||||
import { type EntryDoc, type LoadedEntry, LOG_LEVEL, type InternalFileEntry, type FilePathWithPrefix, type FilePath } from "./lib/src/types";
|
import { type EntryDoc, type LoadedEntry, type InternalFileEntry, type FilePathWithPrefix, type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { type InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
import { type InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
||||||
import { Parallels, delay, isDocContentSame } from "./lib/src/utils";
|
import { Parallels, delay, isDocContentSame } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
@@ -44,7 +44,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
Logger("Synchronizing hidden files done");
|
Logger("Synchronizing hidden files done");
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Synchronizing hidden files failed");
|
Logger("Synchronizing hidden files failed");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
const commonBase = revFrom._revs_info.filter(e => e.status == "available" && Number(e.rev.split("-")[0]) < conflictedRevNo).first()?.rev ?? "";
|
const commonBase = revFrom._revs_info.filter(e => e.status == "available" && Number(e.rev.split("-")[0]) < conflictedRevNo).first()?.rev ?? "";
|
||||||
const result = await this.plugin.mergeObject(path, commonBase, doc._rev, conflictedRev);
|
const result = await this.plugin.mergeObject(path, commonBase, doc._rev, conflictedRev);
|
||||||
if (result) {
|
if (result) {
|
||||||
Logger(`Object merge:${path}`, LOG_LEVEL.INFO);
|
Logger(`Object merge:${path}`, LOG_LEVEL_INFO);
|
||||||
const filename = stripAllPrefixes(path);
|
const filename = stripAllPrefixes(path);
|
||||||
const isExists = await this.app.vault.adapter.exists(filename);
|
const isExists = await this.app.vault.adapter.exists(filename);
|
||||||
if (!isExists) {
|
if (!isExists) {
|
||||||
@@ -174,7 +174,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
await this.localDatabase.removeRaw(id, revB);
|
await this.localDatabase.removeRaw(id, revB);
|
||||||
return this.resolveConflictOnInternalFile(path);
|
return this.resolveConflictOnInternalFile(path);
|
||||||
} else {
|
} else {
|
||||||
Logger(`Object merge is not applicable.`, LOG_LEVEL.VERBOSE);
|
Logger(`Object merge is not applicable.`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const docAMerge = await this.localDatabase.getDBEntry(path, { rev: revA });
|
const docAMerge = await this.localDatabase.getDBEntry(path, { rev: revA });
|
||||||
@@ -203,7 +203,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
return this.resolveConflictOnInternalFile(path);
|
return this.resolveConflictOnInternalFile(path);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Failed to resolve conflict (Hidden): ${path}`);
|
Logger(`Failed to resolve conflict (Hidden): ${path}`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
//TODO: Tidy up. Even though it is experimental feature, So dirty...
|
//TODO: Tidy up. Even though it is experimental feature, So dirty...
|
||||||
async syncInternalFilesAndDatabase(direction: "push" | "pull" | "safe" | "pullForce" | "pushForce", showMessage: boolean, files: InternalFileInfo[] | false = false, targetFiles: string[] | false = false) {
|
async syncInternalFilesAndDatabase(direction: "push" | "pull" | "safe" | "pullForce" | "pushForce", showMessage: boolean, files: InternalFileInfo[] | false = false, targetFiles: string[] | false = false) {
|
||||||
await this.resolveConflictOnInternalFiles();
|
await this.resolveConflictOnInternalFiles();
|
||||||
const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO;
|
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||||
Logger("Scanning hidden files.", logLevel, "sync_internal");
|
Logger("Scanning hidden files.", logLevel, "sync_internal");
|
||||||
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns
|
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns
|
||||||
.replace(/\n| /g, "")
|
.replace(/\n| /g, "")
|
||||||
@@ -273,6 +273,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
if (!filename) continue;
|
if (!filename) continue;
|
||||||
if (ignorePatterns.some(e => filename.match(e)))
|
if (ignorePatterns.some(e => filename.match(e)))
|
||||||
continue;
|
continue;
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(filename)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
const fileOnStorage = filename in filesMap ? filesMap[filename] : undefined;
|
const fileOnStorage = filename in filesMap ? filesMap[filename] : undefined;
|
||||||
const fileOnDatabase = filename in filesOnDBMap ? filesOnDBMap[filename] : undefined;
|
const fileOnDatabase = filename in filesOnDBMap ? filesOnDBMap[filename] : undefined;
|
||||||
@@ -355,12 +358,12 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
a.appendChild(a.createEl("a", null, (anchor) => {
|
a.appendChild(a.createEl("a", null, (anchor) => {
|
||||||
anchor.text = "HERE";
|
anchor.text = "HERE";
|
||||||
anchor.addEventListener("click", async () => {
|
anchor.addEventListener("click", async () => {
|
||||||
Logger(`Unloading plugin: ${updatePluginName}`, LOG_LEVEL.NOTICE, "plugin-reload-" + updatePluginId);
|
Logger(`Unloading plugin: ${updatePluginName}`, LOG_LEVEL_NOTICE, "plugin-reload-" + updatePluginId);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.unloadPlugin(updatePluginId);
|
await this.app.plugins.unloadPlugin(updatePluginId);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.loadPlugin(updatePluginId);
|
await this.app.plugins.loadPlugin(updatePluginId);
|
||||||
Logger(`Plugin reloaded: ${updatePluginName}`, LOG_LEVEL.NOTICE, "plugin-reload-" + updatePluginId);
|
Logger(`Plugin reloaded: ${updatePluginName}`, LOG_LEVEL_NOTICE, "plugin-reload-" + updatePluginId);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -391,7 +394,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Error on checking plugin status.");
|
Logger("Error on checking plugin status.");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +434,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async storeInternalFileToDatabase(file: InternalFileInfo, forceWrite = false) {
|
async storeInternalFileToDatabase(file: InternalFileInfo, forceWrite = false) {
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(file.path)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const id = await this.path2id(file.path, ICHeader);
|
const id = await this.path2id(file.path, ICHeader);
|
||||||
const prefixedFileName = addPrefix(file.path, ICHeader);
|
const prefixedFileName = addPrefix(file.path, ICHeader);
|
||||||
const contentBin = await this.app.vault.adapter.readBinary(file.path);
|
const contentBin = await this.app.vault.adapter.readBinary(file.path);
|
||||||
@@ -439,7 +445,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
content = await arrayBufferToBase64(contentBin);
|
content = await arrayBufferToBase64(contentBin);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`The file ${file.path} could not be encoded`);
|
Logger(`The file ${file.path} could not be encoded`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const mtime = file.mtime;
|
const mtime = file.mtime;
|
||||||
@@ -462,7 +468,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (isDocContentSame(old.data, content) && !forceWrite) {
|
if (isDocContentSame(old.data, content) && !forceWrite) {
|
||||||
// Logger(`STORAGE --> DB:${file.path}: (hidden) Not changed`, LOG_LEVEL.VERBOSE);
|
// Logger(`STORAGE --> DB:${file.path}: (hidden) Not changed`, LOG_LEVEL_VERBOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveData =
|
saveData =
|
||||||
@@ -482,7 +488,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
return ret;
|
return ret;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`STORAGE --> DB:${file.path}: (hidden) Failed`);
|
Logger(`STORAGE --> DB:${file.path}: (hidden) Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -492,6 +498,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
const id = await this.path2id(filename, ICHeader);
|
const id = await this.path2id(filename, ICHeader);
|
||||||
const prefixedFileName = addPrefix(filename, ICHeader);
|
const prefixedFileName = addPrefix(filename, ICHeader);
|
||||||
const mtime = new Date().getTime();
|
const mtime = new Date().getTime();
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(filename)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
await runWithLock("file-" + prefixedFileName, false, async () => {
|
await runWithLock("file-" + prefixedFileName, false, async () => {
|
||||||
try {
|
try {
|
||||||
const old = await this.localDatabase.getDBEntryMeta(prefixedFileName, null, true) as InternalFileEntry | false;
|
const old = await this.localDatabase.getDBEntryMeta(prefixedFileName, null, true) as InternalFileEntry | false;
|
||||||
@@ -526,7 +535,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
Logger(`STORAGE -x> DB:${filename}: (hidden) Done`);
|
Logger(`STORAGE -x> DB:${filename}: (hidden) Done`);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`STORAGE -x> DB:${filename}: (hidden) Failed`);
|
Logger(`STORAGE -x> DB:${filename}: (hidden) Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -535,7 +544,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
async extractInternalFileFromDatabase(filename: FilePath, force = false) {
|
async extractInternalFileFromDatabase(filename: FilePath, force = false) {
|
||||||
const isExists = await this.app.vault.adapter.exists(filename);
|
const isExists = await this.app.vault.adapter.exists(filename);
|
||||||
const prefixedFileName = addPrefix(filename, ICHeader);
|
const prefixedFileName = addPrefix(filename, ICHeader);
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(filename)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return await runWithLock("file-" + prefixedFileName, false, async () => {
|
return await runWithLock("file-" + prefixedFileName, false, async () => {
|
||||||
try {
|
try {
|
||||||
// Check conflicted status
|
// Check conflicted status
|
||||||
@@ -545,7 +556,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
throw new Error(`File not found on database.:${filename}`);
|
throw new Error(`File not found on database.:${filename}`);
|
||||||
// Prevent overwrite for Prevent overwriting while some conflicted revision exists.
|
// Prevent overwrite for Prevent overwriting while some conflicted revision exists.
|
||||||
if (fileOnDB?._conflicts?.length) {
|
if (fileOnDB?._conflicts?.length) {
|
||||||
Logger(`Hidden file ${filename} has conflicted revisions, to keep in safe, writing to storage has been prevented`, LOG_LEVEL.INFO);
|
Logger(`Hidden file ${filename} has conflicted revisions, to keep in safe, writing to storage has been prevented`, LOG_LEVEL_INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const deleted = "deleted" in fileOnDB ? fileOnDB.deleted : false;
|
const deleted = "deleted" in fileOnDB ? fileOnDB.deleted : false;
|
||||||
@@ -559,8 +570,8 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
//@ts-ignore internalAPI
|
//@ts-ignore internalAPI
|
||||||
await app.vault.adapter.reconcileInternalFile(filename);
|
await app.vault.adapter.reconcileInternalFile(filename);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL.VERBOSE);
|
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -572,8 +583,8 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
//@ts-ignore internalAPI
|
//@ts-ignore internalAPI
|
||||||
await app.vault.adapter.reconcileInternalFile(filename);
|
await app.vault.adapter.reconcileInternalFile(filename);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL.VERBOSE);
|
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
Logger(`STORAGE <-- DB:${filename}: written (hidden,new${force ? ", force" : ""})`);
|
Logger(`STORAGE <-- DB:${filename}: written (hidden,new${force ? ", force" : ""})`);
|
||||||
return true;
|
return true;
|
||||||
@@ -581,7 +592,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
const contentBin = await this.app.vault.adapter.readBinary(filename);
|
const contentBin = await this.app.vault.adapter.readBinary(filename);
|
||||||
const content = await arrayBufferToBase64(contentBin);
|
const content = await arrayBufferToBase64(contentBin);
|
||||||
if (content == fileOnDB.data && !force) {
|
if (content == fileOnDB.data && !force) {
|
||||||
// Logger(`STORAGE <-- DB:${filename}: skipped (hidden) Not changed`, LOG_LEVEL.VERBOSE);
|
// Logger(`STORAGE <-- DB:${filename}: skipped (hidden) Not changed`, LOG_LEVEL_VERBOSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
await this.app.vault.adapter.writeBinary(filename, base64ToArrayBuffer(fileOnDB.data), { mtime: fileOnDB.mtime, ctime: fileOnDB.ctime });
|
await this.app.vault.adapter.writeBinary(filename, base64ToArrayBuffer(fileOnDB.data), { mtime: fileOnDB.mtime, ctime: fileOnDB.ctime });
|
||||||
@@ -589,8 +600,8 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
//@ts-ignore internalAPI
|
//@ts-ignore internalAPI
|
||||||
await app.vault.adapter.reconcileInternalFile(filename);
|
await app.vault.adapter.reconcileInternalFile(filename);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL.VERBOSE);
|
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
Logger(`STORAGE <-- DB:${filename}: written (hidden, overwrite${force ? ", force" : ""})`);
|
Logger(`STORAGE <-- DB:${filename}: written (hidden, overwrite${force ? ", force" : ""})`);
|
||||||
return true;
|
return true;
|
||||||
@@ -598,7 +609,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`STORAGE <-- DB:${filename}: written (hidden, overwrite${force ? ", force" : ""}) Failed`);
|
Logger(`STORAGE <-- DB:${filename}: written (hidden, overwrite${force ? ", force" : ""}) Failed`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -608,7 +619,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
|
|
||||||
showJSONMergeDialogAndMerge(docA: LoadedEntry, docB: LoadedEntry): Promise<boolean> {
|
showJSONMergeDialogAndMerge(docA: LoadedEntry, docB: LoadedEntry): Promise<boolean> {
|
||||||
return runWithLock("conflict:merge-data", false, () => new Promise((res) => {
|
return runWithLock("conflict:merge-data", false, () => new Promise((res) => {
|
||||||
Logger("Opening data-merging dialog", LOG_LEVEL.VERBOSE);
|
Logger("Opening data-merging dialog", LOG_LEVEL_VERBOSE);
|
||||||
const docs = [docA, docB];
|
const docs = [docA, docB];
|
||||||
const path = stripAllPrefixes(docA.path);
|
const path = stripAllPrefixes(docA.path);
|
||||||
const modal = new JsonResolveModal(this.app, path, [docA, docB], async (keep, result) => {
|
const modal = new JsonResolveModal(this.app, path, [docA, docB], async (keep, result) => {
|
||||||
@@ -644,8 +655,8 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
//@ts-ignore internalAPI
|
//@ts-ignore internalAPI
|
||||||
await app.vault.adapter.reconcileInternalFile(filename);
|
await app.vault.adapter.reconcileInternalFile(filename);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL.VERBOSE);
|
Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
Logger(`STORAGE <-- DB:${filename}: written (hidden,merged)`);
|
Logger(`STORAGE <-- DB:${filename}: written (hidden,merged)`);
|
||||||
}
|
}
|
||||||
@@ -656,7 +667,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
res(true);
|
res(true);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Could not merge conflicted json");
|
Logger("Could not merge conflicted json");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
res(false);
|
res(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -680,6 +691,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
const result: InternalFileInfo[] = [];
|
const result: InternalFileInfo[] = [];
|
||||||
for (const f of files) {
|
for (const f of files) {
|
||||||
const w = await f;
|
const w = await f;
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(w.path)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
result.push({
|
result.push({
|
||||||
...w,
|
...w,
|
||||||
...w.stat
|
...w.stat
|
||||||
@@ -698,12 +712,18 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
const w = await this.app.vault.adapter.list(path);
|
const w = await this.app.vault.adapter.list(path);
|
||||||
let files = [
|
const filesSrc = [
|
||||||
...w.files
|
...w.files
|
||||||
.filter((e) => !ignoreList.some((ee) => e.endsWith(ee)))
|
.filter((e) => !ignoreList.some((ee) => e.endsWith(ee)))
|
||||||
.filter((e) => !filter || filter.some((ee) => e.match(ee)))
|
.filter((e) => !filter || filter.some((ee) => e.match(ee)))
|
||||||
.filter((e) => !ignoreFilter || ignoreFilter.every((ee) => !e.match(ee))),
|
.filter((e) => !ignoreFilter || ignoreFilter.every((ee) => !e.match(ee))),
|
||||||
];
|
];
|
||||||
|
let files = [] as string[];
|
||||||
|
for (const file of filesSrc) {
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(file)) {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
L1: for (const v of w.folders) {
|
L1: for (const v of w.folders) {
|
||||||
for (const ignore of ignoreList) {
|
for (const ignore of ignoreList) {
|
||||||
@@ -714,6 +734,9 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
if (ignoreFilter && ignoreFilter.some(e => v.match(e))) {
|
if (ignoreFilter && ignoreFilter.some(e => v.match(e))) {
|
||||||
continue L1;
|
continue L1;
|
||||||
}
|
}
|
||||||
|
if (!await this.plugin.isIgnoredByIgnoreFiles(v)) {
|
||||||
|
continue L1;
|
||||||
|
}
|
||||||
files = files.concat(await this.getFiles(v, ignoreList, filter, ignoreFilter));
|
files = files.concat(await this.getFiles(v, ignoreList, filter, ignoreFilter));
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { normalizePath, type PluginManifest } from "./deps";
|
import { normalizePath, type PluginManifest } from "./deps";
|
||||||
import type { DocumentID, EntryDoc, FilePathWithPrefix, LoadedEntry } from "./lib/src/types";
|
import type { DocumentID, EntryDoc, FilePathWithPrefix, LoadedEntry } from "./lib/src/types";
|
||||||
import { LOG_LEVEL } from "./lib/src/types";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { type PluginDataEntry, PERIODIC_PLUGIN_SWEEP, type PluginList, type DevicePluginList, PSCHeader, PSCHeaderEnd } from "./types";
|
import { type PluginDataEntry, PERIODIC_PLUGIN_SWEEP, type PluginList, type DevicePluginList, PSCHeader, PSCHeaderEnd } from "./types";
|
||||||
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
@@ -79,7 +79,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
Logger("Scanning plugins done");
|
Logger("Scanning plugins done");
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Scanning plugins failed");
|
Logger("Scanning plugins failed");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
});
|
});
|
||||||
NewNotice(fragment, 10000);
|
NewNotice(fragment, 10000);
|
||||||
} else {
|
} else {
|
||||||
Logger("Everything is up to date.", LOG_LEVEL.NOTICE);
|
Logger("Everything is up to date.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +165,9 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
specificPlugin = manifests.find(e => e.dir.endsWith("/" + specificPluginPath))?.id ?? "";
|
specificPlugin = manifests.find(e => e.dir.endsWith("/" + specificPluginPath))?.id ?? "";
|
||||||
}
|
}
|
||||||
await runWithLock("sweepplugin", true, async () => {
|
await runWithLock("sweepplugin", true, async () => {
|
||||||
const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO;
|
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||||
if (!this.deviceAndVaultName) {
|
if (!this.deviceAndVaultName) {
|
||||||
Logger("You have to set your device name.", LOG_LEVEL.NOTICE);
|
Logger("You have to set your device name.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger("Scanning plugins", logLevel);
|
Logger("Scanning plugins", logLevel);
|
||||||
@@ -176,7 +176,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
endkey: `ps:${this.deviceAndVaultName}-${specificPlugin}\u{10ffff}`,
|
endkey: `ps:${this.deviceAndVaultName}-${specificPlugin}\u{10ffff}`,
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
});
|
});
|
||||||
// Logger("OLD DOCS.", LOG_LEVEL.VERBOSE);
|
// Logger("OLD DOCS.", LOG_LEVEL_VERBOSE);
|
||||||
// sweep current plugin.
|
// sweep current plugin.
|
||||||
const procs = manifests.map(async (m) => {
|
const procs = manifests.map(async (m) => {
|
||||||
const pluginDataEntryID = `ps:${this.deviceAndVaultName}-${m.id}` as DocumentID;
|
const pluginDataEntryID = `ps:${this.deviceAndVaultName}-${m.id}` as DocumentID;
|
||||||
@@ -184,7 +184,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
if (specificPlugin && m.id != specificPlugin) {
|
if (specificPlugin && m.id != specificPlugin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger(`Reading plugin:${m.name}(${m.id})`, LOG_LEVEL.VERBOSE);
|
Logger(`Reading plugin:${m.name}(${m.id})`, LOG_LEVEL_VERBOSE);
|
||||||
const path = normalizePath(m.dir) + "/";
|
const path = normalizePath(m.dir) + "/";
|
||||||
const adapter = this.app.vault.adapter;
|
const adapter = this.app.vault.adapter;
|
||||||
const files = ["manifest.json", "main.js", "styles.css", "data.json"];
|
const files = ["manifest.json", "main.js", "styles.css", "data.json"];
|
||||||
@@ -222,7 +222,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
datatype: "plain",
|
datatype: "plain",
|
||||||
type: "plain"
|
type: "plain"
|
||||||
};
|
};
|
||||||
Logger(`check diff:${m.name}(${m.id})`, LOG_LEVEL.VERBOSE);
|
Logger(`check diff:${m.name}(${m.id})`, LOG_LEVEL_VERBOSE);
|
||||||
await runWithLock("plugin-" + m.id, false, async () => {
|
await runWithLock("plugin-" + m.id, false, async () => {
|
||||||
const old = await this.localDatabase.getDBEntry(p._id as string as FilePathWithPrefix /* This also should be explained */, null, false, false);
|
const old = await this.localDatabase.getDBEntry(p._id as string as FilePathWithPrefix /* This also should be explained */, null, false, false);
|
||||||
if (old !== false) {
|
if (old !== false) {
|
||||||
@@ -237,7 +237,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
Logger(`Plugin saved:${m.name}`, logLevel);
|
Logger(`Plugin saved:${m.name}`, logLevel);
|
||||||
});
|
});
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Plugin save failed:${m.name}`, LOG_LEVEL.NOTICE);
|
Logger(`Plugin save failed:${m.name}`, LOG_LEVEL_NOTICE);
|
||||||
} finally {
|
} finally {
|
||||||
oldDocs.rows = oldDocs.rows.filter((e) => e.id != pluginDataEntryID);
|
oldDocs.rows = oldDocs.rows.filter((e) => e.id != pluginDataEntryID);
|
||||||
}
|
}
|
||||||
@@ -259,7 +259,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
return e.doc;
|
return e.doc;
|
||||||
});
|
});
|
||||||
Logger(`Deleting old plugin:(${delDocs.length})`, LOG_LEVEL.VERBOSE);
|
Logger(`Deleting old plugin:(${delDocs.length})`, LOG_LEVEL_VERBOSE);
|
||||||
await this.localDatabase.bulkDocsRaw(delDocs);
|
await this.localDatabase.bulkDocsRaw(delDocs);
|
||||||
Logger(`Scan plugin done.`, logLevel);
|
Logger(`Scan plugin done.`, logLevel);
|
||||||
});
|
});
|
||||||
@@ -274,15 +274,15 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
if (stat) {
|
if (stat) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.unloadPlugin(plugin.manifest.id);
|
await this.app.plugins.unloadPlugin(plugin.manifest.id);
|
||||||
Logger(`Unload plugin:${plugin.manifest.id}`, LOG_LEVEL.NOTICE);
|
Logger(`Unload plugin:${plugin.manifest.id}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
if (plugin.dataJson)
|
if (plugin.dataJson)
|
||||||
await adapter.write(pluginTargetFolderPath + "data.json", plugin.dataJson);
|
await adapter.write(pluginTargetFolderPath + "data.json", plugin.dataJson);
|
||||||
Logger("wrote:" + pluginTargetFolderPath + "data.json", LOG_LEVEL.NOTICE);
|
Logger("wrote:" + pluginTargetFolderPath + "data.json", LOG_LEVEL_NOTICE);
|
||||||
if (stat) {
|
if (stat) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.loadPlugin(plugin.manifest.id);
|
await this.app.plugins.loadPlugin(plugin.manifest.id);
|
||||||
Logger(`Load plugin:${plugin.manifest.id}`, LOG_LEVEL.NOTICE);
|
Logger(`Load plugin:${plugin.manifest.id}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
if (stat) {
|
if (stat) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.unloadPlugin(plugin.manifest.id);
|
await this.app.plugins.unloadPlugin(plugin.manifest.id);
|
||||||
Logger(`Unload plugin:${plugin.manifest.id}`, LOG_LEVEL.NOTICE);
|
Logger(`Unload plugin:${plugin.manifest.id}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pluginTargetFolderPath = normalizePath(plugin.manifest.dir) + "/";
|
const pluginTargetFolderPath = normalizePath(plugin.manifest.dir) + "/";
|
||||||
@@ -309,7 +309,7 @@ export class PluginAndTheirSettings extends LiveSyncCommands {
|
|||||||
if (stat) {
|
if (stat) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await this.app.plugins.loadPlugin(plugin.manifest.id);
|
await this.app.plugins.loadPlugin(plugin.manifest.id);
|
||||||
Logger(`Load plugin:${plugin.manifest.id}`, LOG_LEVEL.NOTICE);
|
Logger(`Load plugin:${plugin.manifest.id}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type EntryDoc, type ObsidianLiveSyncSettings, LOG_LEVEL, DEFAULT_SETTINGS } from "./lib/src/types";
|
import { type EntryDoc, type ObsidianLiveSyncSettings, DEFAULT_SETTINGS, LOG_LEVEL_NOTICE } from "./lib/src/types";
|
||||||
import { configURIBase } from "./types";
|
import { configURIBase } from "./types";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
@@ -55,7 +55,7 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false));
|
const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false));
|
||||||
const uri = `${configURIBase}${encryptedSetting}`;
|
const uri = `${configURIBase}${encryptedSetting}`;
|
||||||
await navigator.clipboard.writeText(uri);
|
await navigator.clipboard.writeText(uri);
|
||||||
Logger("Setup URI copied to clipboard", LOG_LEVEL.NOTICE);
|
Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
async command_copySetupURIFull() {
|
async command_copySetupURIFull() {
|
||||||
const encryptingPassphrase = await askString(this.app, "Encrypt your settings", "The passphrase to encrypt the setup URI", "", true);
|
const encryptingPassphrase = await askString(this.app, "Encrypt your settings", "The passphrase to encrypt the setup URI", "", true);
|
||||||
@@ -65,14 +65,14 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false));
|
const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false));
|
||||||
const uri = `${configURIBase}${encryptedSetting}`;
|
const uri = `${configURIBase}${encryptedSetting}`;
|
||||||
await navigator.clipboard.writeText(uri);
|
await navigator.clipboard.writeText(uri);
|
||||||
Logger("Setup URI copied to clipboard", LOG_LEVEL.NOTICE);
|
Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
async command_openSetupURI() {
|
async command_openSetupURI() {
|
||||||
const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`);
|
const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`);
|
||||||
if (setupURI === false)
|
if (setupURI === false)
|
||||||
return;
|
return;
|
||||||
if (!setupURI.startsWith(`${configURIBase}`)) {
|
if (!setupURI.startsWith(`${configURIBase}`)) {
|
||||||
Logger("Set up URI looks wrong.", LOG_LEVEL.NOTICE);
|
Logger("Set up URI looks wrong.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const config = decodeURIComponent(setupURI.substring(configURIBase.length));
|
const config = decodeURIComponent(setupURI.substring(configURIBase.length));
|
||||||
@@ -103,6 +103,11 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
const setupManually = "Leave everything to me";
|
const setupManually = "Leave everything to me";
|
||||||
newSettingW.syncInternalFiles = false;
|
newSettingW.syncInternalFiles = false;
|
||||||
newSettingW.usePluginSync = false;
|
newSettingW.usePluginSync = false;
|
||||||
|
// Migrate completely obsoleted configuration.
|
||||||
|
if (!newSettingW.useIndexedDBAdapter) {
|
||||||
|
newSettingW.useIndexedDBAdapter = true;
|
||||||
|
}
|
||||||
|
|
||||||
const setupType = await askSelectString(this.app, "How would you like to set it up?", [setupAsNew, setupAgain, setupJustImport, setupManually]);
|
const setupType = await askSelectString(this.app, "How would you like to set it up?", [setupAsNew, setupAgain, setupJustImport, setupManually]);
|
||||||
if (setupType == setupJustImport) {
|
if (setupType == setupJustImport) {
|
||||||
this.plugin.settings = newSettingW;
|
this.plugin.settings = newSettingW;
|
||||||
@@ -135,13 +140,13 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
await this.plugin.replicate(true);
|
await this.plugin.replicate(true);
|
||||||
await this.plugin.markRemoteUnlocked();
|
await this.plugin.markRemoteUnlocked();
|
||||||
}
|
}
|
||||||
Logger("Configuration loaded.", LOG_LEVEL.NOTICE);
|
Logger("Configuration loaded.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (keepLocalDB == "no" && keepRemoteDB == "no") {
|
if (keepLocalDB == "no" && keepRemoteDB == "no") {
|
||||||
const reset = await askYesNo(this.app, "Drop everything?");
|
const reset = await askYesNo(this.app, "Drop everything?");
|
||||||
if (reset != "yes") {
|
if (reset != "yes") {
|
||||||
Logger("Cancelled", LOG_LEVEL.NOTICE);
|
Logger("Cancelled", LOG_LEVEL_NOTICE);
|
||||||
this.plugin.settings = oldConf;
|
this.plugin.settings = oldConf;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -176,17 +181,17 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger("Configuration loaded.", LOG_LEVEL.NOTICE);
|
Logger("Configuration loaded.", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
Logger("Cancelled.", LOG_LEVEL.NOTICE);
|
Logger("Cancelled.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Couldn't parse or decrypt configuration uri.", LOG_LEVEL.NOTICE);
|
Logger("Couldn't parse or decrypt configuration uri.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspendExtraSync() {
|
suspendExtraSync() {
|
||||||
Logger("Hidden files and plugin synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL.NOTICE)
|
Logger("Hidden files and plugin synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE)
|
||||||
this.plugin.settings.syncInternalFiles = false;
|
this.plugin.settings.syncInternalFiles = false;
|
||||||
this.plugin.settings.usePluginSync = false;
|
this.plugin.settings.usePluginSync = false;
|
||||||
this.plugin.settings.autoSweepPlugins = false;
|
this.plugin.settings.autoSweepPlugins = false;
|
||||||
@@ -231,7 +236,7 @@ Of course, we are able to disable these features.`
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mode != "CUSTOMIZE") {
|
if (mode != "CUSTOMIZE") {
|
||||||
Logger("Gathering files for enabling Hidden File Sync", LOG_LEVEL.NOTICE);
|
Logger("Gathering files for enabling Hidden File Sync", LOG_LEVEL_NOTICE);
|
||||||
if (mode == "FETCH") {
|
if (mode == "FETCH") {
|
||||||
await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pullForce", true);
|
await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pullForce", true);
|
||||||
} else if (mode == "OVERWRITE") {
|
} else if (mode == "OVERWRITE") {
|
||||||
@@ -241,7 +246,7 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
this.plugin.settings.syncInternalFiles = true;
|
this.plugin.settings.syncInternalFiles = true;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
Logger(`Done! Restarting the app is strongly recommended!`, LOG_LEVEL.NOTICE);
|
Logger(`Done! Restarting the app is strongly recommended!`, LOG_LEVEL_NOTICE);
|
||||||
} else if (mode == "CUSTOMIZE") {
|
} else if (mode == "CUSTOMIZE") {
|
||||||
if (!this.plugin.deviceAndVaultName) {
|
if (!this.plugin.deviceAndVaultName) {
|
||||||
let name = await askString(this.app, "Device name", "Please set this device name", `desktop`);
|
let name = await askString(this.app, "Device name", "Please set this device name", `desktop`);
|
||||||
@@ -287,14 +292,14 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async suspendReflectingDatabase() {
|
async suspendReflectingDatabase() {
|
||||||
if (this.plugin.settings.doNotSuspendOnFetching) return;
|
if (this.plugin.settings.doNotSuspendOnFetching) return;
|
||||||
Logger(`Suspending reflection: Database and storage changes will not be reflected in each other until completely finished the fetching.`, LOG_LEVEL.NOTICE);
|
Logger(`Suspending reflection: Database and storage changes will not be reflected in each other until completely finished the fetching.`, LOG_LEVEL_NOTICE);
|
||||||
this.plugin.settings.suspendParseReplicationResult = true;
|
this.plugin.settings.suspendParseReplicationResult = true;
|
||||||
this.plugin.settings.suspendFileWatching = true;
|
this.plugin.settings.suspendFileWatching = true;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
}
|
}
|
||||||
async resumeReflectingDatabase() {
|
async resumeReflectingDatabase() {
|
||||||
if (this.plugin.settings.doNotSuspendOnFetching) return;
|
if (this.plugin.settings.doNotSuspendOnFetching) return;
|
||||||
Logger(`Database and storage reflection has been resumed!`, LOG_LEVEL.NOTICE);
|
Logger(`Database and storage reflection has been resumed!`, LOG_LEVEL_NOTICE);
|
||||||
this.plugin.settings.suspendParseReplicationResult = false;
|
this.plugin.settings.suspendParseReplicationResult = false;
|
||||||
this.plugin.settings.suspendFileWatching = false;
|
this.plugin.settings.suspendFileWatching = false;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
@@ -320,14 +325,14 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async fetchRemoteChunks() {
|
async fetchRemoteChunks() {
|
||||||
if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) {
|
if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) {
|
||||||
Logger(`Fetching chunks`, LOG_LEVEL.NOTICE);
|
Logger(`Fetching chunks`, LOG_LEVEL_NOTICE);
|
||||||
const remoteDB = await this.plugin.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.plugin.getIsMobile(), true);
|
const remoteDB = await this.plugin.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.plugin.getIsMobile(), true);
|
||||||
if (typeof remoteDB == "string") {
|
if (typeof remoteDB == "string") {
|
||||||
Logger(remoteDB, LOG_LEVEL.NOTICE);
|
Logger(remoteDB, LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
await fetchAllUsedChunks(this.localDatabase.localDatabase, remoteDB.db);
|
await fetchAllUsedChunks(this.localDatabase.localDatabase, remoteDB.db);
|
||||||
}
|
}
|
||||||
Logger(`Fetching chunks done`, LOG_LEVEL.NOTICE);
|
Logger(`Fetching chunks done`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fetchLocal() {
|
async fetchLocal() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { App, Modal } from "./deps";
|
import { App, Modal } from "./deps";
|
||||||
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT } from "diff-match-patch";
|
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT } from "diff-match-patch";
|
||||||
import { diff_result } from "./lib/src/types";
|
import { type diff_result } from "./lib/src/types";
|
||||||
import { escapeStringToHTML } from "./lib/src/strbin";
|
import { escapeStringToHTML } from "./lib/src/strbin";
|
||||||
|
|
||||||
export class ConflictResolveModal extends Modal {
|
export class ConflictResolveModal extends Modal {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { TFile, Modal, App, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_pat
|
|||||||
import { getPathFromTFile, isValidPath } from "./utils";
|
import { getPathFromTFile, isValidPath } from "./utils";
|
||||||
import { base64ToArrayBuffer, base64ToString, escapeStringToHTML } from "./lib/src/strbin";
|
import { base64ToArrayBuffer, base64ToString, escapeStringToHTML } from "./lib/src/strbin";
|
||||||
import ObsidianLiveSyncPlugin from "./main";
|
import ObsidianLiveSyncPlugin from "./main";
|
||||||
import { type DocumentID, type FilePathWithPrefix, type LoadedEntry, LOG_LEVEL } from "./lib/src/types";
|
import { type DocumentID, type FilePathWithPrefix, type LoadedEntry, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { isErrorOfMissingDoc } from "./lib/src/utils_couchdb";
|
import { isErrorOfMissingDoc } from "./lib/src/utils_couchdb";
|
||||||
import { getDocData } from "./lib/src/utils";
|
import { getDocData } from "./lib/src/utils";
|
||||||
@@ -60,7 +60,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
this.contentView.setText(`History of this file was not recorded.`);
|
this.contentView.setText(`History of this file was not recorded.`);
|
||||||
} else {
|
} else {
|
||||||
this.contentView.setText(`Error occurred.`);
|
this.contentView.setText(`Error occurred.`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
e.addClass("mod-cta");
|
e.addClass("mod-cta");
|
||||||
e.addEventListener("click", async () => {
|
e.addEventListener("click", async () => {
|
||||||
await navigator.clipboard.writeText(this.currentText);
|
await navigator.clipboard.writeText(this.currentText);
|
||||||
Logger(`Old content copied to clipboard`, LOG_LEVEL.NOTICE);
|
Logger(`Old content copied to clipboard`, LOG_LEVEL_NOTICE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
async function focusFile(path: string) {
|
async function focusFile(path: string) {
|
||||||
@@ -189,7 +189,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
const leaf = app.workspace.getLeaf(false);
|
const leaf = app.workspace.getLeaf(false);
|
||||||
await leaf.openFile(targetFile);
|
await leaf.openFile(targetFile);
|
||||||
} else {
|
} else {
|
||||||
Logger("The file could not view on the editor", LOG_LEVEL.NOTICE)
|
Logger("The file could not view on the editor", LOG_LEVEL_NOTICE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buttons.createEl("button", { text: "Back to this revision" }, (e) => {
|
buttons.createEl("button", { text: "Back to this revision" }, (e) => {
|
||||||
@@ -198,7 +198,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
// const pathToWrite = this.plugin.id2path(this.id, true);
|
// const pathToWrite = this.plugin.id2path(this.id, true);
|
||||||
const pathToWrite = stripPrefix(this.file);
|
const pathToWrite = stripPrefix(this.file);
|
||||||
if (!isValidPath(pathToWrite)) {
|
if (!isValidPath(pathToWrite)) {
|
||||||
Logger("Path is not valid to write content.", LOG_LEVEL.INFO);
|
Logger("Path is not valid to write content.", LOG_LEVEL_INFO);
|
||||||
}
|
}
|
||||||
if (this.currentDoc?.datatype == "plain") {
|
if (this.currentDoc?.datatype == "plain") {
|
||||||
await this.app.vault.adapter.write(pathToWrite, getDocData(this.currentDoc.data));
|
await this.app.vault.adapter.write(pathToWrite, getDocData(this.currentDoc.data));
|
||||||
@@ -210,7 +210,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
this.close();
|
this.close();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Logger(`Could not parse entry`, LOG_LEVEL.NOTICE);
|
Logger(`Could not parse entry`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export class GlobalHistoryView extends ItemView {
|
|||||||
return "Vault history";
|
return "Vault history";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
async onOpen() {
|
async onOpen() {
|
||||||
this.component = new GlobalHistoryComponent({
|
this.component = new GlobalHistoryComponent({
|
||||||
target: this.contentEl,
|
target: this.contentEl,
|
||||||
@@ -41,6 +42,7 @@ export class GlobalHistoryView extends ItemView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
async onClose() {
|
async onClose() {
|
||||||
this.component.$destroy();
|
this.component.$destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { App, Modal } from "./deps";
|
import { App, Modal } from "./deps";
|
||||||
import { FilePath, LoadedEntry } from "./lib/src/types";
|
import { type FilePath, type LoadedEntry } from "./lib/src/types";
|
||||||
import JsonResolvePane from "./JsonResolvePane.svelte";
|
import JsonResolvePane from "./JsonResolvePane.svelte";
|
||||||
|
|
||||||
export class JsonResolveModal extends Modal {
|
export class JsonResolveModal extends Modal {
|
||||||
@@ -41,7 +41,7 @@ export class JsonResolveModal extends Modal {
|
|||||||
nameA: this.nameA,
|
nameA: this.nameA,
|
||||||
nameB: this.nameB,
|
nameB: this.nameB,
|
||||||
defaultSelect: this.defaultSelect,
|
defaultSelect: this.defaultSelect,
|
||||||
callback: (keepRev, mergedStr) => this.UICallback(keepRev, mergedStr),
|
callback: (keepRev: string, mergedStr: string) => this.UICallback(keepRev, mergedStr),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { deleteDB, IDBPDatabase, openDB } from "idb";
|
import { deleteDB, type IDBPDatabase, openDB } from "idb";
|
||||||
export interface KeyValueDatabase {
|
export interface KeyValueDatabase {
|
||||||
get<T>(key: string): Promise<T>;
|
get<T>(key: string): Promise<T>;
|
||||||
set<T>(key: string, value: T): Promise<IDBValidKey>;
|
set<T>(key: string, value: T): Promise<IDBValidKey>;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AnyEntry, DocumentID, EntryDoc, EntryHasPath, FilePath, FilePathWithPrefix } from "./lib/src/types";
|
import { type AnyEntry, type DocumentID, type EntryDoc, type EntryHasPath, type FilePath, type FilePathWithPrefix } from "./lib/src/types";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
import type ObsidianLiveSyncPlugin from "./main";
|
import type ObsidianLiveSyncPlugin from "./main";
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
import LogPaneComponent from "./LogPane.svelte";
|
import LogPaneComponent from "./LogPane.svelte";
|
||||||
import type ObsidianLiveSyncPlugin from "./main";
|
import type ObsidianLiveSyncPlugin from "./main";
|
||||||
export const VIEW_TYPE_LOG = "log-log";
|
export const VIEW_TYPE_LOG = "log-log";
|
||||||
// Show notes as like scroll.
|
//Log view
|
||||||
export class LogPaneView extends ItemView {
|
export class LogPaneView extends ItemView {
|
||||||
|
|
||||||
component: LogPaneComponent;
|
component: LogPaneComponent;
|
||||||
@@ -32,6 +32,7 @@ export class LogPaneView extends ItemView {
|
|||||||
return "Self-hosted LiveSync Log";
|
return "Self-hosted LiveSync Log";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
async onOpen() {
|
async onOpen() {
|
||||||
this.component = new LogPaneComponent({
|
this.component = new LogPaneComponent({
|
||||||
target: this.contentEl,
|
target: this.contentEl,
|
||||||
@@ -40,6 +41,7 @@ export class LogPaneView extends ItemView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
async onClose() {
|
async onClose() {
|
||||||
this.component.$destroy();
|
this.component.$destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { App, PluginSettingTab, Setting, sanitizeHTMLToDom, TextAreaComponent, MarkdownRenderer, stringifyYaml } from "./deps";
|
import { App, PluginSettingTab, Setting, sanitizeHTMLToDom, TextAreaComponent, MarkdownRenderer, stringifyYaml } from "./deps";
|
||||||
import { DEFAULT_SETTINGS, LOG_LEVEL, type ObsidianLiveSyncSettings, type ConfigPassphraseStore, type RemoteDBSettings, type FilePathWithPrefix, type HashAlgorithm, type DocumentID } from "./lib/src/types";
|
import { DEFAULT_SETTINGS, type ObsidianLiveSyncSettings, type ConfigPassphraseStore, type RemoteDBSettings, type FilePathWithPrefix, type HashAlgorithm, type DocumentID, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { delay } from "./lib/src/utils";
|
import { delay } from "./lib/src/utils";
|
||||||
import { Semaphore } from "./lib/src/semaphore";
|
import { Semaphore } from "./lib/src/semaphore";
|
||||||
import { versionNumberString2Number } from "./lib/src/strbin";
|
import { versionNumberString2Number } from "./lib/src/strbin";
|
||||||
@@ -21,10 +21,10 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
async testConnection(): Promise<void> {
|
async testConnection(): Promise<void> {
|
||||||
const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(this.plugin.settings, this.plugin.isMobile, true);
|
const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(this.plugin.settings, this.plugin.isMobile, true);
|
||||||
if (typeof db === "string") {
|
if (typeof db === "string") {
|
||||||
this.plugin.addLog(`could not connect to ${this.plugin.settings.couchDB_URI} : ${this.plugin.settings.couchDB_DBNAME} \n(${db})`, LOG_LEVEL.NOTICE);
|
this.plugin.addLog(`could not connect to ${this.plugin.settings.couchDB_URI} : ${this.plugin.settings.couchDB_DBNAME} \n(${db})`, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL.NOTICE);
|
this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
display(): void {
|
display(): void {
|
||||||
const { containerEl } = this;
|
const { containerEl } = this;
|
||||||
@@ -111,7 +111,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkdownRenderer.renderMarkdown(updateInformation, informationDivEl, "/", this.plugin);
|
MarkdownRenderer.render(this.plugin.app, updateInformation, informationDivEl, "/", this.plugin);
|
||||||
|
|
||||||
|
|
||||||
addScreenElement("100", containerInformationEl);
|
addScreenElement("100", containerInformationEl);
|
||||||
@@ -133,12 +133,13 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
new Setting(setupWizardEl)
|
new Setting(setupWizardEl)
|
||||||
.setName("Discard the existing configuration and set up")
|
.setName("Discard the existing configuration and set up")
|
||||||
.addButton((text) => {
|
.addButton((text) => {
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
text.setButtonText("Next").onClick(async () => {
|
text.setButtonText("Next").onClick(async () => {
|
||||||
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
|
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
|
||||||
this.plugin.replicator.closeReplication();
|
this.plugin.replicator.closeReplication();
|
||||||
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
Logger("Configuration has been flushed, please open it again", LOG_LEVEL.NOTICE)
|
Logger("Configuration has been flushed, please open it again", LOG_LEVEL_NOTICE)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.plugin.app.setting.close()
|
this.plugin.app.setting.close()
|
||||||
} else {
|
} else {
|
||||||
@@ -302,7 +303,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const checkConfig = async () => {
|
const checkConfig = async () => {
|
||||||
try {
|
try {
|
||||||
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
|
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
|
||||||
Logger("This feature cannot be used with IBM Cloudant.", LOG_LEVEL.NOTICE);
|
Logger("This feature cannot be used with IBM Cloudant.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,11 +335,11 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const res = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, undefined, key, value);
|
const res = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, undefined, key, value);
|
||||||
console.dir(res);
|
console.dir(res);
|
||||||
if (res.status == 200) {
|
if (res.status == 200) {
|
||||||
Logger(`${title} successfully updated`, LOG_LEVEL.NOTICE);
|
Logger(`${title} successfully updated`, LOG_LEVEL_NOTICE);
|
||||||
checkResultDiv.removeChild(x);
|
checkResultDiv.removeChild(x);
|
||||||
checkConfig();
|
checkConfig();
|
||||||
} else {
|
} else {
|
||||||
Logger(`${title} failed`, LOG_LEVEL.NOTICE);
|
Logger(`${title} failed`, LOG_LEVEL_NOTICE);
|
||||||
Logger(res.text);
|
Logger(res.text);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -451,7 +452,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
addResult("--Done--", ["ob-btn-config-head"]);
|
addResult("--Done--", ["ob-btn-config-head"]);
|
||||||
addResult("If you have some trouble with Connection-check even though all Config-check has been passed, Please check your reverse proxy's configuration.", ["ob-btn-config-info"]);
|
addResult("If you have some trouble with Connection-check even though all Config-check has been passed, Please check your reverse proxy's configuration.", ["ob-btn-config-info"]);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Checking configuration failed`, LOG_LEVEL.NOTICE);
|
Logger(`Checking configuration failed`, LOG_LEVEL_NOTICE);
|
||||||
Logger(ex);
|
Logger(ex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -609,25 +610,25 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
console.dir(settingForCheck);
|
console.dir(settingForCheck);
|
||||||
const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(settingForCheck, this.plugin.isMobile, true);
|
const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(settingForCheck, this.plugin.isMobile, true);
|
||||||
if (typeof db === "string") {
|
if (typeof db === "string") {
|
||||||
Logger("Could not connect to the database.", LOG_LEVEL.NOTICE);
|
Logger("Could not connect to the database.", LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (await checkSyncInfo(db.db)) {
|
if (await checkSyncInfo(db.db)) {
|
||||||
// Logger("Database connected", LOG_LEVEL.NOTICE);
|
// Logger("Database connected", LOG_LEVEL_NOTICE);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Logger("Failed to read remote database", LOG_LEVEL.NOTICE);
|
Logger("Failed to read remote database", LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const applyEncryption = async (sendToServer: boolean) => {
|
const applyEncryption = async (sendToServer: boolean) => {
|
||||||
if (encrypt && passphrase == "") {
|
if (encrypt && passphrase == "") {
|
||||||
Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL.NOTICE);
|
Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (encrypt && !(await testCrypt())) {
|
if (encrypt && !(await testCrypt())) {
|
||||||
Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.NOTICE);
|
Logger("WARNING! Your device would not support encryption.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(await checkWorkingPassphrase()) && !sendToServer) {
|
if (!(await checkWorkingPassphrase()) && !sendToServer) {
|
||||||
@@ -654,11 +655,11 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") => {
|
const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") => {
|
||||||
if (encrypt && passphrase == "") {
|
if (encrypt && passphrase == "") {
|
||||||
Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL.NOTICE);
|
Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (encrypt && !(await testCrypt())) {
|
if (encrypt && !(await testCrypt())) {
|
||||||
Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.NOTICE);
|
Logger("WARNING! Your device would not support encryption.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!encrypt) {
|
if (!encrypt) {
|
||||||
@@ -670,7 +671,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings.passphrase = passphrase;
|
this.plugin.settings.passphrase = passphrase;
|
||||||
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
||||||
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
||||||
Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL.NOTICE)
|
Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE)
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
updateE2EControls();
|
updateE2EControls();
|
||||||
applyDisplayEnabled();
|
applyDisplayEnabled();
|
||||||
@@ -882,7 +883,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
.setCta()
|
.setCta()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
if (currentPreset == "") {
|
if (currentPreset == "") {
|
||||||
Logger("Select any preset.", LOG_LEVEL.NOTICE);
|
Logger("Select any preset.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const presetAllDisabled = {
|
const presetAllDisabled = {
|
||||||
@@ -913,15 +914,15 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
...this.plugin.settings,
|
...this.plugin.settings,
|
||||||
...presetLiveSync
|
...presetLiveSync
|
||||||
}
|
}
|
||||||
Logger("Synchronization setting configured as LiveSync.", LOG_LEVEL.NOTICE);
|
Logger("Synchronization setting configured as LiveSync.", LOG_LEVEL_NOTICE);
|
||||||
} else if (currentPreset == "PERIODIC") {
|
} else if (currentPreset == "PERIODIC") {
|
||||||
this.plugin.settings = {
|
this.plugin.settings = {
|
||||||
...this.plugin.settings,
|
...this.plugin.settings,
|
||||||
...presetPeriodic
|
...presetPeriodic
|
||||||
}
|
}
|
||||||
Logger("Synchronization setting configured as Periodic sync with batch database update.", LOG_LEVEL.NOTICE);
|
Logger("Synchronization setting configured as Periodic sync with batch database update.", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
Logger("All synchronization disabled.", LOG_LEVEL.NOTICE);
|
Logger("All synchronization disabled.", LOG_LEVEL_NOTICE);
|
||||||
this.plugin.settings = {
|
this.plugin.settings = {
|
||||||
...this.plugin.settings,
|
...this.plugin.settings,
|
||||||
...presetAllDisabled
|
...presetAllDisabled
|
||||||
@@ -943,7 +944,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
}
|
}
|
||||||
await this.plugin.replicate(true);
|
await this.plugin.replicate(true);
|
||||||
|
|
||||||
Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL.NOTICE);
|
Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL_NOTICE);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
|
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
|
||||||
}
|
}
|
||||||
@@ -1330,7 +1331,38 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
new Setting(containerSyncSettingEl)
|
||||||
|
.setName("(Beta) Use ignore files")
|
||||||
|
.setDesc("If this is set, changes to local files which are matched by the ignore files will be skipped. Remote changes are determined using local ignore files.")
|
||||||
|
.setClass("wizardHidden")
|
||||||
|
.addToggle((toggle) => {
|
||||||
|
toggle
|
||||||
|
.setValue(this.plugin.settings.useIgnoreFiles)
|
||||||
|
.onChange(async (value) => {
|
||||||
|
this.plugin.settings.useIgnoreFiles = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
this.display();
|
||||||
|
})
|
||||||
|
return toggle;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (this.plugin.settings.useIgnoreFiles) {
|
||||||
|
new Setting(containerSyncSettingEl)
|
||||||
|
.setName("Ignore files")
|
||||||
|
.setDesc("We can use multiple ignore files, e.g.) `.gitignore, .dockerignore`")
|
||||||
|
.setClass("wizardHidden")
|
||||||
|
.addTextArea((text) => {
|
||||||
|
text
|
||||||
|
.setValue(this.plugin.settings.ignoreFiles)
|
||||||
|
.setPlaceholder(".gitignore, .dockerignore")
|
||||||
|
.onChange(async (value) => {
|
||||||
|
this.plugin.settings.ignoreFiles = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
})
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
containerSyncSettingEl.createEl("h4", {
|
containerSyncSettingEl.createEl("h4", {
|
||||||
text: sanitizeHTMLToDom(`Advanced settings`),
|
text: sanitizeHTMLToDom(`Advanced settings`),
|
||||||
}).addClass("wizardHidden");
|
}).addClass("wizardHidden");
|
||||||
@@ -1468,7 +1500,7 @@ ${stringifyYaml(responseConfig)}
|
|||||||
${stringifyYaml(pluginConfig)}`;
|
${stringifyYaml(pluginConfig)}`;
|
||||||
console.log(msgConfig);
|
console.log(msgConfig);
|
||||||
await navigator.clipboard.writeText(msgConfig);
|
await navigator.clipboard.writeText(msgConfig);
|
||||||
Logger(`Information has been copied to clipboard`, LOG_LEVEL.NOTICE);
|
Logger(`Information has been copied to clipboard`, LOG_LEVEL_NOTICE);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1521,11 +1553,11 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
Logger(`UPDATE DATABASE ${file.path}`);
|
Logger(`UPDATE DATABASE ${file.path}`);
|
||||||
await this.plugin.updateIntoDB(file, false, null, true);
|
await this.plugin.updateIntoDB(file, false, null, true);
|
||||||
i++;
|
i++;
|
||||||
Logger(`${i}/${files.length}\n${file.path}`, LOG_LEVEL.NOTICE, "verify");
|
Logger(`${i}/${files.length}\n${file.path}`, LOG_LEVEL_NOTICE, "verify");
|
||||||
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
i++;
|
i++;
|
||||||
Logger(`Error while verifyAndRepair`, LOG_LEVEL.NOTICE);
|
Logger(`Error while verifyAndRepair`, LOG_LEVEL_NOTICE);
|
||||||
Logger(ex);
|
Logger(ex);
|
||||||
} finally {
|
} finally {
|
||||||
releaser();
|
releaser();
|
||||||
@@ -1533,7 +1565,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
}
|
}
|
||||||
)(e));
|
)(e));
|
||||||
await Promise.all(processes);
|
await Promise.all(processes);
|
||||||
Logger("done", LOG_LEVEL.NOTICE, "verify");
|
Logger("done", LOG_LEVEL_NOTICE, "verify");
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
@@ -1573,35 +1605,35 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
}
|
}
|
||||||
const ret = await this.plugin.localDatabase.putRaw(newDoc, { force: true });
|
const ret = await this.plugin.localDatabase.putRaw(newDoc, { force: true });
|
||||||
if (ret.ok) {
|
if (ret.ok) {
|
||||||
Logger(`${docName} has been converted as conflicted document`, LOG_LEVEL.NOTICE);
|
Logger(`${docName} has been converted as conflicted document`, LOG_LEVEL_NOTICE);
|
||||||
doc._deleted = true;
|
doc._deleted = true;
|
||||||
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
||||||
Logger(`Old ${docName} has been deleted`, LOG_LEVEL.NOTICE);
|
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
await this.plugin.showIfConflicted(docName as FilePathWithPrefix);
|
await this.plugin.showIfConflicted(docName as FilePathWithPrefix);
|
||||||
} else {
|
} else {
|
||||||
Logger(`Converting ${docName} Failed!`, LOG_LEVEL.NOTICE);
|
Logger(`Converting ${docName} Failed!`, LOG_LEVEL_NOTICE);
|
||||||
Logger(ret, LOG_LEVEL.VERBOSE);
|
Logger(ret, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex?.status == 404) {
|
if (ex?.status == 404) {
|
||||||
// We can perform this safely
|
// We can perform this safely
|
||||||
if ((await this.plugin.localDatabase.putRaw(newDoc)).ok) {
|
if ((await this.plugin.localDatabase.putRaw(newDoc)).ok) {
|
||||||
Logger(`${docName} has been converted`, LOG_LEVEL.NOTICE);
|
Logger(`${docName} has been converted`, LOG_LEVEL_NOTICE);
|
||||||
doc._deleted = true;
|
doc._deleted = true;
|
||||||
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
||||||
Logger(`Old ${docName} has been deleted`, LOG_LEVEL.NOTICE);
|
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger(`Something went wrong on converting ${docName}`, LOG_LEVEL.NOTICE);
|
Logger(`Something went wrong on converting ${docName}`, LOG_LEVEL_NOTICE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
// Something wrong.
|
// Something wrong.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger(`Converting finished`, LOG_LEVEL.NOTICE);
|
Logger(`Converting finished`, LOG_LEVEL_NOTICE);
|
||||||
}));
|
}));
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
.setName("Suspend file watching")
|
.setName("Suspend file watching")
|
||||||
@@ -1727,12 +1759,12 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
button.setButtonText("Change")
|
button.setButtonText("Change")
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
if (this.plugin.settings.additionalSuffixOfDatabaseName == newDatabaseName) {
|
if (this.plugin.settings.additionalSuffixOfDatabaseName == newDatabaseName) {
|
||||||
Logger("Suffix was not changed.", LOG_LEVEL.NOTICE);
|
Logger("Suffix was not changed.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.plugin.settings.additionalSuffixOfDatabaseName = newDatabaseName;
|
this.plugin.settings.additionalSuffixOfDatabaseName = newDatabaseName;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
Logger("Suffix has been changed. Reopening database...", LOG_LEVEL.NOTICE);
|
Logger("Suffix has been changed. Reopening database...", LOG_LEVEL_NOTICE);
|
||||||
await this.plugin.initializeDatabase();
|
await this.plugin.initializeDatabase();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -1786,11 +1818,11 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
vaultName.setDisabled(this.plugin.settings.usePluginSync);
|
vaultName.setDisabled(this.plugin.settings.usePluginSync);
|
||||||
// vaultName.setTooltip(this.plugin.settings.autoSweepPlugins || this.plugin.settings.autoSweepPluginsPeriodic ? "You could not change when you enabling auto scan." : "");
|
// vaultName.setTooltip(this.plugin.settings.autoSweepPlugins || this.plugin.settings.autoSweepPluginsPeriodic ? "You could not change when you enabling auto scan." : "");
|
||||||
};
|
};
|
||||||
updateDisabledOfDeviceAndVaultName
|
updateDisabledOfDeviceAndVaultName();
|
||||||
new Setting(containerPluginSettings).setName("Enable customization sync").addToggle((toggle) =>
|
new Setting(containerPluginSettings).setName("Enable customization sync").addToggle((toggle) =>
|
||||||
toggle.setValue(this.plugin.settings.usePluginSync).onChange(async (value) => {
|
toggle.setValue(this.plugin.settings.usePluginSync).onChange(async (value) => {
|
||||||
if (value && this.plugin.deviceAndVaultName.trim() == "") {
|
if (value && this.plugin.deviceAndVaultName.trim() == "") {
|
||||||
Logger("We have to configure `Device name` to use this feature.", LOG_LEVEL.NOTICE);
|
Logger("We have to configure `Device name` to use this feature.", LOG_LEVEL_NOTICE);
|
||||||
toggle.setValue(false);
|
toggle.setValue(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import type { PluginDataExDisplay } from "./CmdConfigSync";
|
import type { PluginDataExDisplay } from "./CmdConfigSync";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { versionNumberString2Number } from "./lib/src/strbin";
|
import { versionNumberString2Number } from "./lib/src/strbin";
|
||||||
import { type FilePath, LOG_LEVEL } from "./lib/src/types";
|
import { type FilePath, LOG_LEVEL_NOTICE } from "./lib/src/types";
|
||||||
import { getDocData } from "./lib/src/utils";
|
import { getDocData } from "./lib/src/utils";
|
||||||
import type ObsidianLiveSyncPlugin from "./main";
|
import type ObsidianLiveSyncPlugin from "./main";
|
||||||
import { askString, scheduleTask } from "./utils";
|
import { askString, scheduleTask } from "./utils";
|
||||||
@@ -229,7 +229,7 @@
|
|||||||
const duplicateTermName = await askString(plugin.app, "Duplicate", "device name", "");
|
const duplicateTermName = await askString(plugin.app, "Duplicate", "device name", "");
|
||||||
if (duplicateTermName) {
|
if (duplicateTermName) {
|
||||||
if (duplicateTermName.contains("/")) {
|
if (duplicateTermName.contains("/")) {
|
||||||
Logger(`We can not use "/" to the device name`, LOG_LEVEL.NOTICE);
|
Logger(`We can not use "/" to the device name`, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const key = `${plugin.app.vault.configDir}/${local.files[0].filename}`;
|
const key = `${plugin.app.vault.configDir}/${local.files[0].filename}`;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Plugin_2, TAbstractFile, TFile, TFolder } from "./deps";
|
import { Plugin, TAbstractFile, TFile, TFolder } from "./deps";
|
||||||
import { isPlainText, shouldBeIgnored } from "./lib/src/path";
|
import { isPlainText, shouldBeIgnored } from "./lib/src/path";
|
||||||
import { getGlobalStore } from "./lib/src/store";
|
import { getGlobalStore } from "./lib/src/store";
|
||||||
import { FilePath, ObsidianLiveSyncSettings } from "./lib/src/types";
|
import { type FilePath, type ObsidianLiveSyncSettings } from "./lib/src/types";
|
||||||
import { FileEventItem, FileEventType, FileInfo, InternalFileInfo, queueItem } from "./types";
|
import { type FileEventItem, type FileEventType, type FileInfo, type InternalFileInfo, type queueItem } from "./types";
|
||||||
import { recentlyTouched } from "./utils";
|
import { recentlyTouched } from "./utils";
|
||||||
|
|
||||||
|
|
||||||
@@ -12,12 +12,13 @@ export abstract class StorageEventManager {
|
|||||||
abstract getQueueLength(): number;
|
abstract getQueueLength(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LiveSyncForStorageEventManager = Plugin_2 &
|
type LiveSyncForStorageEventManager = Plugin &
|
||||||
{
|
{
|
||||||
settings: ObsidianLiveSyncSettings
|
settings: ObsidianLiveSyncSettings
|
||||||
|
ignoreFiles: string[],
|
||||||
} & {
|
} & {
|
||||||
isTargetFile: (file: string | TAbstractFile) => boolean,
|
isTargetFile: (file: string | TAbstractFile) => Promise<boolean>,
|
||||||
procFileEvent: (applyBatch?: boolean) => Promise<boolean>
|
procFileEvent: (applyBatch?: boolean) => Promise<boolean>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -35,12 +36,12 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
this.watchVaultDelete = this.watchVaultDelete.bind(this);
|
this.watchVaultDelete = this.watchVaultDelete.bind(this);
|
||||||
this.watchVaultRename = this.watchVaultRename.bind(this);
|
this.watchVaultRename = this.watchVaultRename.bind(this);
|
||||||
this.watchVaultRawEvents = this.watchVaultRawEvents.bind(this);
|
this.watchVaultRawEvents = this.watchVaultRawEvents.bind(this);
|
||||||
plugin.registerEvent(app.vault.on("modify", this.watchVaultChange));
|
plugin.registerEvent(plugin.app.vault.on("modify", this.watchVaultChange));
|
||||||
plugin.registerEvent(app.vault.on("delete", this.watchVaultDelete));
|
plugin.registerEvent(plugin.app.vault.on("delete", this.watchVaultDelete));
|
||||||
plugin.registerEvent(app.vault.on("rename", this.watchVaultRename));
|
plugin.registerEvent(plugin.app.vault.on("rename", this.watchVaultRename));
|
||||||
plugin.registerEvent(app.vault.on("create", this.watchVaultCreate));
|
plugin.registerEvent(plugin.app.vault.on("create", this.watchVaultCreate));
|
||||||
//@ts-ignore : Internal API
|
//@ts-ignore : Internal API
|
||||||
plugin.registerEvent(app.vault.on("raw", this.watchVaultRawEvents));
|
plugin.registerEvent(plugin.app.vault.on("raw", this.watchVaultRawEvents));
|
||||||
}
|
}
|
||||||
|
|
||||||
watchVaultCreate(file: TAbstractFile, ctx?: any) {
|
watchVaultCreate(file: TAbstractFile, ctx?: any) {
|
||||||
@@ -64,9 +65,18 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
}
|
}
|
||||||
// Watch raw events (Internal API)
|
// Watch raw events (Internal API)
|
||||||
watchVaultRawEvents(path: FilePath) {
|
watchVaultRawEvents(path: FilePath) {
|
||||||
|
if (this.plugin.settings.useIgnoreFiles && this.plugin.ignoreFiles.some(e => path.endsWith(e.trim()))) {
|
||||||
|
// If it is one of ignore files, refresh the cached one.
|
||||||
|
this.plugin.isTargetFile(path).then(() => this._watchVaultRawEvents(path));
|
||||||
|
} else {
|
||||||
|
this._watchVaultRawEvents(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_watchVaultRawEvents(path: FilePath) {
|
||||||
if (!this.plugin.settings.syncInternalFiles && !this.plugin.settings.usePluginSync) return;
|
if (!this.plugin.settings.syncInternalFiles && !this.plugin.settings.usePluginSync) return;
|
||||||
if (!this.plugin.settings.watchInternalFileChanges) return;
|
if (!this.plugin.settings.watchInternalFileChanges) return;
|
||||||
if (!path.startsWith(app.vault.configDir)) return;
|
if (!path.startsWith(this.plugin.app.vault.configDir)) return;
|
||||||
const ignorePatterns = this.plugin.settings.syncInternalFilesIgnorePatterns
|
const ignorePatterns = this.plugin.settings.syncInternalFilesIgnorePatterns
|
||||||
.replace(/\n| /g, "")
|
.replace(/\n| /g, "")
|
||||||
.split(",").filter(e => e).map(e => new RegExp(e, "i"));
|
.split(",").filter(e => e).map(e => new RegExp(e, "i"));
|
||||||
@@ -77,7 +87,6 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
file: { path, mtime: 0, ctime: 0, size: 0 }
|
file: { path, mtime: 0, ctime: 0, size: 0 }
|
||||||
}], null);
|
}], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache file and waiting to can be proceed.
|
// Cache file and waiting to can be proceed.
|
||||||
async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) {
|
async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) {
|
||||||
let forcePerform = false;
|
let forcePerform = false;
|
||||||
@@ -90,7 +99,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
const file = param.file;
|
const file = param.file;
|
||||||
const oldPath = param.oldPath;
|
const oldPath = param.oldPath;
|
||||||
if (file instanceof TFolder) continue;
|
if (file instanceof TFolder) continue;
|
||||||
if (!this.plugin.isTargetFile(file.path)) continue;
|
if (!await this.plugin.isTargetFile(file.path)) continue;
|
||||||
if (this.plugin.settings.suspendFileWatching) continue;
|
if (this.plugin.settings.suspendFileWatching) continue;
|
||||||
|
|
||||||
let cache: null | string | ArrayBuffer;
|
let cache: null | string | ArrayBuffer;
|
||||||
@@ -100,11 +109,11 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isPlainText(file.name)) {
|
if (!isPlainText(file.name)) {
|
||||||
cache = await app.vault.readBinary(file);
|
cache = await this.plugin.app.vault.readBinary(file);
|
||||||
} else {
|
} else {
|
||||||
// cache = await this.app.vault.read(file);
|
// cache = await this.app.vault.read(file);
|
||||||
cache = await app.vault.cachedRead(file);
|
cache = await this.plugin.app.vault.cachedRead(file);
|
||||||
if (!cache) cache = await app.vault.read(file);
|
if (!cache) cache = await this.plugin.app.vault.read(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type == "DELETE" || type == "RENAME") {
|
if (type == "DELETE" || type == "RENAME") {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { type FilePath } from "./lib/src/types";
|
import { type FilePath } from "./lib/src/types";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
addIcon, App, debounce, Editor, FuzzySuggestModal, MarkdownRenderer, MarkdownView, Modal, Notice, Platform, Plugin, PluginSettingTab, Plugin_2, requestUrl, sanitizeHTMLToDom, Setting, stringifyYaml, TAbstractFile, TextAreaComponent, TFile, TFolder,
|
addIcon, App, debounce, Editor, FuzzySuggestModal, MarkdownRenderer, MarkdownView, Modal, Notice, Platform, Plugin, PluginSettingTab, requestUrl, sanitizeHTMLToDom, Setting, stringifyYaml, TAbstractFile, TextAreaComponent, TFile, TFolder,
|
||||||
parseYaml, ItemView, WorkspaceLeaf
|
parseYaml, ItemView, WorkspaceLeaf
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
export type { DataWriteOptions, PluginManifest, RequestUrlParam, RequestUrlResponse } from "obsidian";
|
export type { DataWriteOptions, PluginManifest, RequestUrlParam, RequestUrlResponse } from "obsidian";
|
||||||
|
|||||||
@@ -183,8 +183,9 @@ export class MessageBox extends Modal {
|
|||||||
})
|
})
|
||||||
contentEl.createEl("h1", { text: this.title });
|
contentEl.createEl("h1", { text: this.title });
|
||||||
const div = contentEl.createDiv();
|
const div = contentEl.createDiv();
|
||||||
MarkdownRenderer.renderMarkdown(this.contentMd, div, "/", this.plugin);
|
MarkdownRenderer.render(this.plugin.app, this.contentMd, div, "/", this.plugin);
|
||||||
const buttonSetting = new Setting(contentEl);
|
const buttonSetting = new Setting(contentEl);
|
||||||
|
buttonSetting.controlEl.style.flexWrap = "wrap";
|
||||||
for (const button of this.buttons) {
|
for (const button of this.buttons) {
|
||||||
buttonSetting.addButton((btn) => {
|
buttonSetting.addButton((btn) => {
|
||||||
btn
|
btn
|
||||||
|
|||||||
2
src/lib
2
src/lib
Submodule src/lib updated: 1a5cac6d65...6efd115e0e
270
src/main.ts
270
src/main.ts
@@ -2,7 +2,7 @@ const isDebug = false;
|
|||||||
|
|
||||||
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "./deps";
|
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "./deps";
|
||||||
import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl } from "./deps";
|
import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl } from "./deps";
|
||||||
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry } from "./lib/src/types";
|
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_URGENT, LOG_LEVEL_VERBOSE } from "./lib/src/types";
|
||||||
import { type InternalFileInfo, type queueItem, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./types";
|
import { type InternalFileInfo, type queueItem, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./types";
|
||||||
import { arrayToChunkedArray, getDocData, isDocContentSame } from "./lib/src/utils";
|
import { arrayToChunkedArray, getDocData, isDocContentSame } from "./lib/src/utils";
|
||||||
import { Logger, setGlobalLogFunction } from "./lib/src/logger";
|
import { Logger, setGlobalLogFunction } from "./lib/src/logger";
|
||||||
@@ -17,7 +17,7 @@ import { getGlobalStore, ObservableStore, observeStores } from "./lib/src/store"
|
|||||||
import { lockStore, logMessageStore, logStore, type LogEntry } from "./lib/src/stores";
|
import { lockStore, logMessageStore, logStore, type LogEntry } from "./lib/src/stores";
|
||||||
import { setNoticeClass } from "./lib/src/wrapper";
|
import { setNoticeClass } from "./lib/src/wrapper";
|
||||||
import { base64ToString, versionNumberString2Number, base64ToArrayBuffer, arrayBufferToBase64 } from "./lib/src/strbin";
|
import { base64ToString, versionNumberString2Number, base64ToArrayBuffer, arrayBufferToBase64 } from "./lib/src/strbin";
|
||||||
import { addPrefix, isPlainText, shouldBeIgnored, stripAllPrefixes } from "./lib/src/path";
|
import { addPrefix, isAcceptedAll, isPlainText, shouldBeIgnored, stripAllPrefixes } from "./lib/src/path";
|
||||||
import { isLockAcquired, runWithLock } from "./lib/src/lock";
|
import { isLockAcquired, runWithLock } from "./lib/src/lock";
|
||||||
import { Semaphore } from "./lib/src/semaphore";
|
import { Semaphore } from "./lib/src/semaphore";
|
||||||
import { StorageEventManager, StorageEventManagerObsidian } from "./StorageEventManager";
|
import { StorageEventManager, StorageEventManagerObsidian } from "./StorageEventManager";
|
||||||
@@ -32,6 +32,7 @@ import { confirmWithMessage } from "./dialogs";
|
|||||||
import { GlobalHistoryView, VIEW_TYPE_GLOBAL_HISTORY } from "./GlobalHistoryView";
|
import { GlobalHistoryView, VIEW_TYPE_GLOBAL_HISTORY } from "./GlobalHistoryView";
|
||||||
import { LogPaneView, VIEW_TYPE_LOG } from "./LogPaneView";
|
import { LogPaneView, VIEW_TYPE_LOG } from "./LogPaneView";
|
||||||
import { mapAllTasksWithConcurrencyLimit, processAllTasksWithConcurrencyLimit } from "./lib/src/task";
|
import { mapAllTasksWithConcurrencyLimit, processAllTasksWithConcurrencyLimit } from "./lib/src/task";
|
||||||
|
import { LRUCache } from "./lib/src/LRUCache";
|
||||||
|
|
||||||
setNoticeClass(Notice);
|
setNoticeClass(Notice);
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
// over 10MB
|
// over 10MB
|
||||||
if (isCloudantURI(uri)) {
|
if (isCloudantURI(uri)) {
|
||||||
this.last_successful_post = false;
|
this.last_successful_post = false;
|
||||||
Logger("This request should fail on IBM Cloudant.", LOG_LEVEL.VERBOSE);
|
Logger("This request should fail on IBM Cloudant.", LOG_LEVEL_VERBOSE);
|
||||||
throw new Error("This request should fail on IBM Cloudant.");
|
throw new Error("This request should fail on IBM Cloudant.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +157,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
} else {
|
} else {
|
||||||
this.last_successful_post = true;
|
this.last_successful_post = true;
|
||||||
}
|
}
|
||||||
Logger(`HTTP:${method}${size} to:${localURL} -> ${r.status}`, LOG_LEVEL.DEBUG);
|
Logger(`HTTP:${method}${size} to:${localURL} -> ${r.status}`, LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
return new Response(r.arrayBuffer, {
|
return new Response(r.arrayBuffer, {
|
||||||
headers: r.headers,
|
headers: r.headers,
|
||||||
@@ -164,7 +165,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
statusText: `${r.status}`,
|
statusText: `${r.status}`,
|
||||||
});
|
});
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL.VERBOSE);
|
Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL_VERBOSE);
|
||||||
// limit only in bulk_docs.
|
// limit only in bulk_docs.
|
||||||
if (url.toString().indexOf("_bulk_docs") !== -1) {
|
if (url.toString().indexOf("_bulk_docs") !== -1) {
|
||||||
this.last_successful_post = false;
|
this.last_successful_post = false;
|
||||||
@@ -183,10 +184,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
} else {
|
} else {
|
||||||
this.last_successful_post = true;
|
this.last_successful_post = true;
|
||||||
}
|
}
|
||||||
Logger(`HTTP:${method}${size} to:${localURL} -> ${response.status}`, LOG_LEVEL.DEBUG);
|
Logger(`HTTP:${method}${size} to:${localURL} -> ${response.status}`, LOG_LEVEL_DEBUG);
|
||||||
return response;
|
return response;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL.VERBOSE);
|
Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL_VERBOSE);
|
||||||
// limit only in bulk_docs.
|
// limit only in bulk_docs.
|
||||||
if (url.toString().indexOf("_bulk_docs") !== -1) {
|
if (url.toString().indexOf("_bulk_docs") !== -1) {
|
||||||
this.last_successful_post = false;
|
this.last_successful_post = false;
|
||||||
@@ -213,7 +214,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (ex.name == "TypeError" && ex.message == "Failed to fetch") {
|
if (ex.name == "TypeError" && ex.message == "Failed to fetch") {
|
||||||
msg += "\n**Note** This error caused by many reasons. The only sure thing is you didn't touch the server.\nTo check details, open inspector.";
|
msg += "\n**Note** This error caused by many reasons. The only sure thing is you didn't touch the server.\nTo check details, open inspector.";
|
||||||
}
|
}
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,7 +346,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
notes.sort((a, b) => b.mtime - a.mtime);
|
notes.sort((a, b) => b.mtime - a.mtime);
|
||||||
const notesList = notes.map(e => e.dispPath);
|
const notesList = notes.map(e => e.dispPath);
|
||||||
if (notesList.length == 0) {
|
if (notesList.length == 0) {
|
||||||
Logger("There are no conflicted documents", LOG_LEVEL.NOTICE);
|
Logger("There are no conflicted documents", LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const target = await askSelectString(this.app, "File to view History", notesList);
|
const target = await askSelectString(this.app, "File to view History", notesList);
|
||||||
@@ -397,7 +398,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
async onLayoutReady() {
|
async onLayoutReady() {
|
||||||
this.registerFileWatchEvents();
|
this.registerFileWatchEvents();
|
||||||
if (!this.localDatabase.isReady) {
|
if (!this.localDatabase.isReady) {
|
||||||
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL.NOTICE);
|
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,7 +410,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
this.settings.suspendFileWatching = true;
|
this.settings.suspendFileWatching = true;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
if (this.isRedFlag2Raised()) {
|
if (this.isRedFlag2Raised()) {
|
||||||
Logger(`${FLAGMD_REDFLAG2} has been detected! Self-hosted LiveSync suspends all sync and rebuild everything.`, LOG_LEVEL.NOTICE);
|
Logger(`${FLAGMD_REDFLAG2} has been detected! Self-hosted LiveSync suspends all sync and rebuild everything.`, LOG_LEVEL_NOTICE);
|
||||||
await this.addOnSetup.rebuildEverything();
|
await this.addOnSetup.rebuildEverything();
|
||||||
await this.deleteRedFlag2();
|
await this.deleteRedFlag2();
|
||||||
if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") {
|
if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") {
|
||||||
@@ -419,7 +420,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
this.app.commands.executeCommandById("app:reload")
|
this.app.commands.executeCommandById("app:reload")
|
||||||
}
|
}
|
||||||
} else if (this.isRedFlag3Raised()) {
|
} else if (this.isRedFlag3Raised()) {
|
||||||
Logger(`${FLAGMD_REDFLAG3} has been detected! Self-hosted LiveSync will discard the local database and fetch everything from the remote once again.`, LOG_LEVEL.NOTICE);
|
Logger(`${FLAGMD_REDFLAG3} has been detected! Self-hosted LiveSync will discard the local database and fetch everything from the remote once again.`, LOG_LEVEL_NOTICE);
|
||||||
await this.addOnSetup.fetchLocal();
|
await this.addOnSetup.fetchLocal();
|
||||||
await this.deleteRedFlag3();
|
await this.deleteRedFlag3();
|
||||||
if (this.settings.suspendFileWatching) {
|
if (this.settings.suspendFileWatching) {
|
||||||
@@ -434,15 +435,15 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
this.settings.writeLogToTheFile = true;
|
this.settings.writeLogToTheFile = true;
|
||||||
await this.openDatabase();
|
await this.openDatabase();
|
||||||
const warningMessage = "The red flag is raised! The whole initialize steps are skipped, and any file changes are not captured.";
|
const warningMessage = "The red flag is raised! The whole initialize steps are skipped, and any file changes are not captured.";
|
||||||
Logger(warningMessage, LOG_LEVEL.NOTICE);
|
Logger(warningMessage, LOG_LEVEL_NOTICE);
|
||||||
this.setStatusBarText(warningMessage);
|
this.setStatusBarText(warningMessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.settings.suspendFileWatching) {
|
if (this.settings.suspendFileWatching) {
|
||||||
Logger("'Suspend file watching' turned on. Are you sure this is what you intended? Every modification on the vault will be ignored.", LOG_LEVEL.NOTICE);
|
Logger("'Suspend file watching' turned on. Are you sure this is what you intended? Every modification on the vault will be ignored.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
if (this.settings.suspendParseReplicationResult) {
|
if (this.settings.suspendParseReplicationResult) {
|
||||||
Logger("'Suspend database reflecting' turned on. Are you sure this is what you intended? Every replicated change will be postponed until disabling this option.", LOG_LEVEL.NOTICE);
|
Logger("'Suspend database reflecting' turned on. Are you sure this is what you intended? Every replicated change will be postponed until disabling this option.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
const isInitialized = await this.initializeDatabase(false, false);
|
const isInitialized = await this.initializeDatabase(false, false);
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
@@ -457,8 +458,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
this.scanStat();
|
this.scanStat();
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Error while loading Self-hosted LiveSync", LOG_LEVEL.NOTICE);
|
Logger("Error while loading Self-hosted LiveSync", LOG_LEVEL_NOTICE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,20 +468,20 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
*/
|
*/
|
||||||
async scanStat() {
|
async scanStat() {
|
||||||
const notes: { path: string, mtime: number }[] = [];
|
const notes: { path: string, mtime: number }[] = [];
|
||||||
Logger(`Additional safety scan..`, LOG_LEVEL.VERBOSE);
|
Logger(`Additional safety scan..`, LOG_LEVEL_VERBOSE);
|
||||||
for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) {
|
for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) {
|
||||||
if (!("_conflicts" in doc)) continue;
|
if (!("_conflicts" in doc)) continue;
|
||||||
notes.push({ path: this.getPath(doc), mtime: doc.mtime });
|
notes.push({ path: this.getPath(doc), mtime: doc.mtime });
|
||||||
}
|
}
|
||||||
if (notes.length > 0) {
|
if (notes.length > 0) {
|
||||||
Logger(`Some files have been left conflicted! Please resolve them by "Pick a file to resolve conflict". The list is written in the log.`, LOG_LEVEL.NOTICE);
|
Logger(`Some files have been left conflicted! Please resolve them by "Pick a file to resolve conflict". The list is written in the log.`, LOG_LEVEL_NOTICE);
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
Logger(`Conflicted: ${note.path}`);
|
Logger(`Conflicted: ${note.path}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger(`There are no conflicted files`, LOG_LEVEL.VERBOSE);
|
Logger(`There are no conflicted files`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
Logger(`Additional safety scan done`, LOG_LEVEL.VERBOSE);
|
Logger(`Additional safety scan done`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
@@ -501,7 +502,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
|
|
||||||
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
||||||
if (lastVersion > this.settings.lastReadUpdates) {
|
if (lastVersion > this.settings.lastReadUpdates) {
|
||||||
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL.NOTICE);
|
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (this.app.isMobile) {
|
if (this.app.isMobile) {
|
||||||
@@ -589,10 +590,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
callback: async () => {
|
callback: async () => {
|
||||||
if (this.settings.liveSync) {
|
if (this.settings.liveSync) {
|
||||||
this.settings.liveSync = false;
|
this.settings.liveSync = false;
|
||||||
Logger("LiveSync Disabled.", LOG_LEVEL.NOTICE);
|
Logger("LiveSync Disabled.", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
this.settings.liveSync = true;
|
this.settings.liveSync = true;
|
||||||
Logger("LiveSync Enabled.", LOG_LEVEL.NOTICE);
|
Logger("LiveSync Enabled.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
await this.realizeSettingSyncMode();
|
await this.realizeSettingSyncMode();
|
||||||
this.saveSettings();
|
this.saveSettings();
|
||||||
@@ -604,10 +605,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
callback: async () => {
|
callback: async () => {
|
||||||
if (this.suspended) {
|
if (this.suspended) {
|
||||||
this.suspended = false;
|
this.suspended = false;
|
||||||
Logger("Self-hosted LiveSync resumed", LOG_LEVEL.NOTICE);
|
Logger("Self-hosted LiveSync resumed", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
this.suspended = true;
|
this.suspended = true;
|
||||||
Logger("Self-hosted LiveSync suspended", LOG_LEVEL.NOTICE);
|
Logger("Self-hosted LiveSync suspended", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
await this.realizeSettingSyncMode();
|
await this.realizeSettingSyncMode();
|
||||||
this.saveSettings();
|
this.saveSettings();
|
||||||
@@ -772,7 +773,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
|
|
||||||
const passphrase = await this.getPassphrase(settings);
|
const passphrase = await this.getPassphrase(settings);
|
||||||
if (passphrase === false) {
|
if (passphrase === false) {
|
||||||
Logger("Could not determine passphrase to save data.json! You probably make the configuration sure again!", LOG_LEVEL.URGENT);
|
Logger("Could not determine passphrase to save data.json! You probably make the configuration sure again!", LOG_LEVEL_URGENT);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const dec = await encrypt(src, passphrase + SALT_OF_PASSPHRASE, false);
|
const dec = await encrypt(src, passphrase + SALT_OF_PASSPHRASE, false);
|
||||||
@@ -788,7 +789,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings;
|
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings;
|
||||||
const passphrase = await this.getPassphrase(settings);
|
const passphrase = await this.getPassphrase(settings);
|
||||||
if (passphrase === false) {
|
if (passphrase === false) {
|
||||||
Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT);
|
Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
|
||||||
} else {
|
} else {
|
||||||
if (settings.encryptedCouchDBConnection) {
|
if (settings.encryptedCouchDBConnection) {
|
||||||
const keys = ["couchDB_URI", "couchDB_USER", "couchDB_PASSWORD", "couchDB_DBNAME"] as (keyof CouchDBConnection)[];
|
const keys = ["couchDB_URI", "couchDB_USER", "couchDB_PASSWORD", "couchDB_DBNAME"] as (keyof CouchDBConnection)[];
|
||||||
@@ -800,7 +801,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT);
|
Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
settings[key] = "";
|
settings[key] = "";
|
||||||
}
|
}
|
||||||
@@ -812,7 +813,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
settings.passphrase = decrypted;
|
settings.passphrase = decrypted;
|
||||||
} else {
|
} else {
|
||||||
Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT);
|
Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
|
||||||
settings.passphrase = "";
|
settings.passphrase = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,10 +841,11 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isCloudantURI(this.settings.couchDB_URI) && this.settings.customChunkSize != 0) {
|
if (isCloudantURI(this.settings.couchDB_URI) && this.settings.customChunkSize != 0) {
|
||||||
Logger("Configuration verification founds problems with your configuration. This has been fixed automatically. But you may already have data that cannot be synchronised. If this is the case, please rebuild everything.", LOG_LEVEL.NOTICE)
|
Logger("Configuration verification founds problems with your configuration. This has been fixed automatically. But you may already have data that cannot be synchronised. If this is the case, please rebuild everything.", LOG_LEVEL_NOTICE)
|
||||||
this.settings.customChunkSize = 0;
|
this.settings.customChunkSize = 0;
|
||||||
}
|
}
|
||||||
this.deviceAndVaultName = localStorage.getItem(lsKey) || "";
|
this.deviceAndVaultName = localStorage.getItem(lsKey) || "";
|
||||||
|
this.ignoreFiles = this.settings.ignoreFiles.split(",").map(e => e.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerRealizeSettingSyncMode() {
|
triggerRealizeSettingSyncMode() {
|
||||||
@@ -854,9 +856,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName();
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName();
|
||||||
|
|
||||||
localStorage.setItem(lsKey, this.deviceAndVaultName || "");
|
localStorage.setItem(lsKey, this.deviceAndVaultName || "");
|
||||||
|
|
||||||
const settings = { ...this.settings };
|
const settings = { ...this.settings };
|
||||||
if (this.usedPassphrase == "" && !await this.getPassphrase(settings)) {
|
if (this.usedPassphrase == "" && !await this.getPassphrase(settings)) {
|
||||||
Logger("Could not determine passphrase for saving data.json! Our data.json have insecure items!", LOG_LEVEL.NOTICE);
|
Logger("Could not determine passphrase for saving data.json! Our data.json have insecure items!", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
if (settings.couchDB_PASSWORD != "" || settings.couchDB_URI != "" || settings.couchDB_USER != "" || settings.couchDB_DBNAME) {
|
if (settings.couchDB_PASSWORD != "" || settings.couchDB_URI != "" || settings.couchDB_USER != "" || settings.couchDB_DBNAME) {
|
||||||
const connectionSetting: CouchDBConnection = {
|
const connectionSetting: CouchDBConnection = {
|
||||||
@@ -878,6 +881,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
await this.saveData(settings);
|
await this.saveData(settings);
|
||||||
this.localDatabase.settings = this.settings;
|
this.localDatabase.settings = this.settings;
|
||||||
|
this.ignoreFiles = this.settings.ignoreFiles.split(",").map(e => e.trim());
|
||||||
this.triggerRealizeSettingSyncMode();
|
this.triggerRealizeSettingSyncMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,12 +971,12 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
} else {
|
} else {
|
||||||
const targetFile = this.app.vault.getAbstractFileByPath(file.path);
|
const targetFile = this.app.vault.getAbstractFileByPath(file.path);
|
||||||
if (!(targetFile instanceof TFile)) {
|
if (!(targetFile instanceof TFile)) {
|
||||||
Logger(`Target file was not found: ${file.path}`, LOG_LEVEL.INFO);
|
Logger(`Target file was not found: ${file.path}`, LOG_LEVEL_INFO);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//TODO: check from cache time.
|
//TODO: check from cache time.
|
||||||
if (file.mtime == last) {
|
if (file.mtime == last) {
|
||||||
Logger(`File has been already scanned on ${queue.type}, skip: ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`File has been already scanned on ${queue.type}, skip: ${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +985,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const keyD1 = `file-last-proc-DELETED-${file.path}`;
|
const keyD1 = `file-last-proc-DELETED-${file.path}`;
|
||||||
await this.kvDB.set(keyD1, mtime);
|
await this.kvDB.set(keyD1, mtime);
|
||||||
if (!await this.updateIntoDB(targetFile, false, cache)) {
|
if (!await this.updateIntoDB(targetFile, false, cache)) {
|
||||||
Logger(`DB -> STORAGE: failed, cancel the relative operations: ${targetFile.path}`, LOG_LEVEL.INFO);
|
Logger(`DB -> STORAGE: failed, cancel the relative operations: ${targetFile.path}`, LOG_LEVEL_INFO);
|
||||||
// cancel running queues and remove one of atomic operation
|
// cancel running queues and remove one of atomic operation
|
||||||
this.vaultManager.cancelRelativeEvent(queue);
|
this.vaultManager.cancelRelativeEvent(queue);
|
||||||
continue;
|
continue;
|
||||||
@@ -1038,7 +1042,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
async watchVaultRenameAsync(file: TFile, oldFile: any, cache?: CacheData) {
|
async watchVaultRenameAsync(file: TFile, oldFile: any, cache?: CacheData) {
|
||||||
Logger(`${oldFile} renamed to ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`${oldFile} renamed to ${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
try {
|
try {
|
||||||
// Logger(`RENAMING.. ${file.path} into db`);
|
// Logger(`RENAMING.. ${file.path} into db`);
|
||||||
@@ -1046,7 +1050,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
// Logger(`deleted ${oldFile} from db`);
|
// Logger(`deleted ${oldFile} from db`);
|
||||||
await this.deleteFromDBbyPath(oldFile);
|
await this.deleteFromDBbyPath(oldFile);
|
||||||
} else {
|
} else {
|
||||||
Logger(`Could not save new file: ${file.path} `, LOG_LEVEL.NOTICE);
|
Logger(`Could not save new file: ${file.path} `, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(ex);
|
Logger(ex);
|
||||||
@@ -1059,14 +1063,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
|
|
||||||
lastLog = "";
|
lastLog = "";
|
||||||
// eslint-disable-next-line require-await
|
// eslint-disable-next-line require-await
|
||||||
async addLog(message: any, level: LOG_LEVEL = LOG_LEVEL.INFO, key = "") {
|
async addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = "") {
|
||||||
if (level == LOG_LEVEL.DEBUG && !isDebug) {
|
if (level == LOG_LEVEL_DEBUG && !isDebug) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (level < LOG_LEVEL.INFO && this.settings && this.settings.lessInformationInLog) {
|
if (level < LOG_LEVEL_INFO && this.settings && this.settings.lessInformationInLog) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.settings && !this.settings.showVerboseLog && level == LOG_LEVEL.VERBOSE) {
|
if (this.settings && !this.settings.showVerboseLog && level == LOG_LEVEL_VERBOSE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const vaultName = this.getVaultName();
|
const vaultName = this.getVaultName();
|
||||||
@@ -1092,7 +1096,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
logMessageStore.apply(e => [...e, newMessage].slice(-100));
|
logMessageStore.apply(e => [...e, newMessage].slice(-100));
|
||||||
this.setStatusBarText(null, messageContent);
|
this.setStatusBarText(null, messageContent);
|
||||||
|
|
||||||
if (level >= LOG_LEVEL.NOTICE) {
|
if (level >= LOG_LEVEL_NOTICE) {
|
||||||
if (!key) key = messageContent;
|
if (!key) key = messageContent;
|
||||||
if (key in this.notifies) {
|
if (key in this.notifies) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -1159,13 +1163,13 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (shouldBeIgnored(path)) {
|
if (shouldBeIgnored(path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.isTargetFile(path)) return;
|
if (!await this.isTargetFile(path)) return;
|
||||||
if (docEntry._deleted || docEntry.deleted) {
|
if (docEntry._deleted || docEntry.deleted) {
|
||||||
// This occurs not only when files are deleted, but also when conflicts are resolved.
|
// This occurs not only when files are deleted, but also when conflicts are resolved.
|
||||||
// We have to check no other revisions are left.
|
// We have to check no other revisions are left.
|
||||||
const lastDocs = await this.localDatabase.getDBEntry(path);
|
const lastDocs = await this.localDatabase.getDBEntry(path);
|
||||||
if (path != file.path) {
|
if (path != file.path) {
|
||||||
Logger(`delete skipped: ${file.path} :Not exactly matched`, LOG_LEVEL.VERBOSE);
|
Logger(`delete skipped: ${file.path} :Not exactly matched`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
if (lastDocs === false) {
|
if (lastDocs === false) {
|
||||||
await this.deleteVaultItem(file);
|
await this.deleteVaultItem(file);
|
||||||
@@ -1173,7 +1177,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
// it perhaps delete some revisions.
|
// it perhaps delete some revisions.
|
||||||
// may be we have to reload this
|
// may be we have to reload this
|
||||||
await this.pullFile(path, null, true);
|
await this.pullFile(path, null, true);
|
||||||
Logger(`delete skipped:${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`delete skipped:${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1184,12 +1188,12 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (doc === false) return;
|
if (doc === false) return;
|
||||||
const msg = `DB -> STORAGE (${mode}${force ? ",force" : ""},${doc.datatype}) `;
|
const msg = `DB -> STORAGE (${mode}${force ? ",force" : ""},${doc.datatype}) `;
|
||||||
if (doc.datatype != "newnote" && doc.datatype != "plain") {
|
if (doc.datatype != "newnote" && doc.datatype != "plain") {
|
||||||
Logger(msg + "ERROR, Invalid datatype: " + path + "(" + doc.datatype + ")", LOG_LEVEL.NOTICE);
|
Logger(msg + "ERROR, Invalid datatype: " + path + "(" + doc.datatype + ")", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!force && localMtime >= docMtime) return;
|
if (!force && localMtime >= docMtime) return;
|
||||||
if (!isValidPath(path)) {
|
if (!isValidPath(path)) {
|
||||||
Logger(msg + "ERROR, invalid path: " + path, LOG_LEVEL.NOTICE);
|
Logger(msg + "ERROR, invalid path: " + path, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const writeData = doc.datatype == "newnote" ? base64ToArrayBuffer(doc.data) : getDocData(doc.data);
|
const writeData = doc.datatype == "newnote" ? base64ToArrayBuffer(doc.data) : getDocData(doc.data);
|
||||||
@@ -1207,14 +1211,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
this.app.vault.trigger(mode, outFile);
|
this.app.vault.trigger(mode, outFile);
|
||||||
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(msg + "ERROR, Could not write: " + path, LOG_LEVEL.NOTICE);
|
Logger(msg + "ERROR, Could not write: " + path, LOG_LEVEL_NOTICE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteVaultItem(file: TFile | TFolder) {
|
async deleteVaultItem(file: TFile | TFolder) {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
if (!this.isTargetFile(file)) return;
|
if (!await this.isTargetFile(file)) return;
|
||||||
}
|
}
|
||||||
const dir = file.parent;
|
const dir = file.parent;
|
||||||
if (this.settings.trashInsteadDelete) {
|
if (this.settings.trashInsteadDelete) {
|
||||||
@@ -1258,7 +1262,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
try {
|
try {
|
||||||
const releaser = await semaphore.acquire(1);
|
const releaser = await semaphore.acquire(1);
|
||||||
runWithLock(`dbchanged-${path}`, false, async () => {
|
runWithLock(`dbchanged-${path}`, false, async () => {
|
||||||
Logger(`Applying ${path} (${entry._id}: ${entry._rev}) change...`, LOG_LEVEL.VERBOSE);
|
Logger(`Applying ${path} (${entry._id}: ${entry._rev}) change...`, LOG_LEVEL_VERBOSE);
|
||||||
await this.handleDBChangedAsync(entry);
|
await this.handleDBChangedAsync(entry);
|
||||||
Logger(`Applied ${path} (${entry._id}:${entry._rev}) change...`);
|
Logger(`Applied ${path} (${entry._id}:${entry._rev}) change...`);
|
||||||
}).finally(() => { releaser(); });
|
}).finally(() => { releaser(); });
|
||||||
@@ -1304,7 +1308,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
await this.doc2storage(doc, file);
|
await this.doc2storage(doc, file);
|
||||||
} else {
|
} else {
|
||||||
if (!queueConflictCheck()) {
|
if (!queueConflictCheck()) {
|
||||||
Logger(`${this.getPath(change)} is conflicted, write to the storage has been pended.`, LOG_LEVEL.NOTICE);
|
Logger(`${this.getPath(change)} is conflicted, write to the storage has been pended.`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1350,10 +1354,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
} else if (isValidPath(this.getPath(queue.entry))) {
|
} else if (isValidPath(this.getPath(queue.entry))) {
|
||||||
this.handleDBChanged(queue.entry);
|
this.handleDBChanged(queue.entry);
|
||||||
} else {
|
} else {
|
||||||
Logger(`Skipped: ${queue.entry._id}`, LOG_LEVEL.VERBOSE);
|
Logger(`Skipped: ${queue.entry._id}`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
} else if (now > queue.timeout) {
|
} else if (now > queue.timeout) {
|
||||||
if (!queue.warned) Logger(`Timed out: ${queue.entry._id} could not collect ${queue.missingChildren.length} chunks. plugin keeps watching, but you have to check the file after the replication.`, LOG_LEVEL.NOTICE);
|
if (!queue.warned) Logger(`Timed out: ${queue.entry._id} could not collect ${queue.missingChildren.length} chunks. plugin keeps watching, but you have to check the file after the replication.`, LOG_LEVEL_NOTICE);
|
||||||
queue.warned = true;
|
queue.warned = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1385,7 +1389,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
async parseIncomingDoc(doc: PouchDB.Core.ExistingDocument<EntryBody>) {
|
async parseIncomingDoc(doc: PouchDB.Core.ExistingDocument<EntryBody>) {
|
||||||
const path = this.getPath(doc);
|
const path = this.getPath(doc);
|
||||||
if (!this.isTargetFile(path)) return;
|
if (!await this.isTargetFile(path)) return;
|
||||||
const skipOldFile = this.settings.skipOlderFilesOnSync && false; //patched temporary.
|
const skipOldFile = this.settings.skipOlderFilesOnSync && false; //patched temporary.
|
||||||
// Do not handle internal files if the feature has not been enabled.
|
// Do not handle internal files if the feature has not been enabled.
|
||||||
if (isInternalMetadata(doc._id) && !this.settings.syncInternalFiles) return;
|
if (isInternalMetadata(doc._id) && !this.settings.syncInternalFiles) return;
|
||||||
@@ -1409,7 +1413,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const docMtime = ~~(doc.mtime / 1000);
|
const docMtime = ~~(doc.mtime / 1000);
|
||||||
//TODO: some margin required.
|
//TODO: some margin required.
|
||||||
if (localMtime >= docMtime) {
|
if (localMtime >= docMtime) {
|
||||||
Logger(`${path} (${doc._id}, ${doc._rev}) Skipped, older than storage.`, LOG_LEVEL.VERBOSE);
|
Logger(`${path} (${doc._id}, ${doc._rev}) Skipped, older than storage.`, LOG_LEVEL_VERBOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1425,7 +1429,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if ((!this.settings.readChunksOnline) && "children" in doc) {
|
if ((!this.settings.readChunksOnline) && "children" in doc) {
|
||||||
const c = await this.localDatabase.collectChunksWithCache(doc.children as DocumentID[]);
|
const c = await this.localDatabase.collectChunksWithCache(doc.children as DocumentID[]);
|
||||||
const missing = c.filter((e) => e.chunk === false).map((e) => e.id);
|
const missing = c.filter((e) => e.chunk === false).map((e) => e.id);
|
||||||
if (missing.length > 0) Logger(`${path} (${doc._id}, ${doc._rev}) Queued (waiting ${missing.length} items)`, LOG_LEVEL.VERBOSE);
|
if (missing.length > 0) Logger(`${path} (${doc._id}, ${doc._rev}) Queued (waiting ${missing.length} items)`, LOG_LEVEL_VERBOSE);
|
||||||
newQueue.missingChildren = missing;
|
newQueue.missingChildren = missing;
|
||||||
this.queuedFiles.push(newQueue);
|
this.queuedFiles.push(newQueue);
|
||||||
} else {
|
} else {
|
||||||
@@ -1467,7 +1471,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
missingChildren: [] as string[],
|
missingChildren: [] as string[],
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
};
|
};
|
||||||
Logger(`Processing scheduled: ${change.path}`, LOG_LEVEL.INFO);
|
Logger(`Processing scheduled: ${change.path}`, LOG_LEVEL_INFO);
|
||||||
this.queuedFiles.push(newQueue);
|
this.queuedFiles.push(newQueue);
|
||||||
this.saveQueuedFiles();
|
this.saveQueuedFiles();
|
||||||
continue;
|
continue;
|
||||||
@@ -1479,7 +1483,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (change.type == "versioninfo") {
|
if (change.type == "versioninfo") {
|
||||||
if (change.version > VER) {
|
if (change.version > VER) {
|
||||||
this.replicator.closeReplication();
|
this.replicator.closeReplication();
|
||||||
Logger(`Remote database updated to incompatible version. update your self-hosted-livesync plugin.`, LOG_LEVEL.NOTICE);
|
Logger(`Remote database updated to incompatible version. update your self-hosted-livesync plugin.`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1619,11 +1623,11 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
async replicate(showMessage?: boolean) {
|
async replicate(showMessage?: boolean) {
|
||||||
if (!this.isReady) return;
|
if (!this.isReady) return;
|
||||||
if (isLockAcquired("cleanup")) {
|
if (isLockAcquired("cleanup")) {
|
||||||
Logger("Database cleaning up is in process. replication has been cancelled", LOG_LEVEL.NOTICE);
|
Logger("Database cleaning up is in process. replication has been cancelled", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.settings.versionUpFlash != "") {
|
if (this.settings.versionUpFlash != "") {
|
||||||
Logger("Open settings and check message, please. replication has been cancelled.", LOG_LEVEL.NOTICE);
|
Logger("Open settings and check message, please. replication has been cancelled.", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
@@ -1632,8 +1636,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const ret = await this.replicator.openReplication(this.settings, false, showMessage);
|
const ret = await this.replicator.openReplication(this.settings, false, showMessage);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (this.replicator.remoteLockedAndDeviceNotAccepted) {
|
if (this.replicator.remoteLockedAndDeviceNotAccepted) {
|
||||||
if (this.replicator.remoteCleaned) {
|
if (this.replicator.remoteCleaned && this.settings.useIndexedDBAdapter) {
|
||||||
Logger(`The remote database has been cleaned.`, showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO);
|
Logger(`The remote database has been cleaned.`, showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
||||||
await runWithLock("cleanup", true, async () => {
|
await runWithLock("cleanup", true, async () => {
|
||||||
const count = await purgeUnreferencedChunks(this.localDatabase.localDatabase, true);
|
const count = await purgeUnreferencedChunks(this.localDatabase.localDatabase, true);
|
||||||
const message = `The remote database has been cleaned up.
|
const message = `The remote database has been cleaned up.
|
||||||
@@ -1651,7 +1655,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
if (ret == CHOICE_CLEAN) {
|
if (ret == CHOICE_CLEAN) {
|
||||||
const remoteDB = await this.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.getIsMobile(), true);
|
const remoteDB = await this.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.getIsMobile(), true);
|
||||||
if (typeof remoteDB == "string") {
|
if (typeof remoteDB == "string") {
|
||||||
Logger(remoteDB, LOG_LEVEL.NOTICE);
|
Logger(remoteDB, LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1663,9 +1667,9 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
await purgeUnreferencedChunks(this.localDatabase.localDatabase, false);
|
await purgeUnreferencedChunks(this.localDatabase.localDatabase, false);
|
||||||
this.localDatabase.hashCaches.clear();
|
this.localDatabase.hashCaches.clear();
|
||||||
await this.getReplicator().markRemoteResolved(this.settings);
|
await this.getReplicator().markRemoteResolved(this.settings);
|
||||||
Logger("The local database has been cleaned up.", showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO)
|
Logger("The local database has been cleaned up.", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO)
|
||||||
} else {
|
} else {
|
||||||
Logger("Replication has been cancelled. Please try it again.", showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO)
|
Logger("Replication has been cancelled. Please try it again.", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1733,28 +1737,36 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
// synchronize all files between database and storage.
|
// synchronize all files between database and storage.
|
||||||
let initialScan = false;
|
let initialScan = false;
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
Logger("Initializing", LOG_LEVEL.NOTICE, "syncAll");
|
Logger("Initializing", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger("Initialize and checking database files");
|
Logger("Initialize and checking database files");
|
||||||
Logger("Checking deleted files");
|
Logger("Checking deleted files");
|
||||||
await this.collectDeletedFiles();
|
await this.collectDeletedFiles();
|
||||||
|
|
||||||
Logger("Collecting local files on the storage", LOG_LEVEL.VERBOSE);
|
Logger("Collecting local files on the storage", LOG_LEVEL_VERBOSE);
|
||||||
const filesStorage = this.app.vault.getFiles().filter(e => this.isTargetFile(e));
|
const filesStorageSrc = this.app.vault.getFiles();
|
||||||
|
|
||||||
|
const filesStorage = [] as typeof filesStorageSrc;
|
||||||
|
for (const f of filesStorageSrc) {
|
||||||
|
if (await this.isTargetFile(f.path)) {
|
||||||
|
filesStorage.push(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const filesStorageName = filesStorage.map((e) => e.path);
|
const filesStorageName = filesStorage.map((e) => e.path);
|
||||||
Logger("Collecting local files on the DB", LOG_LEVEL.VERBOSE);
|
Logger("Collecting local files on the DB", LOG_LEVEL_VERBOSE);
|
||||||
const filesDatabase = [] as FilePathWithPrefix[]
|
const filesDatabase = [] as FilePathWithPrefix[]
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for await (const doc of this.localDatabase.findAllNormalDocs()) {
|
for await (const doc of this.localDatabase.findAllNormalDocs()) {
|
||||||
count++;
|
count++;
|
||||||
if (count % 25 == 0) Logger(`Collecting local files on the DB: ${count}`, showingNotice ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "syncAll");
|
if (count % 25 == 0) Logger(`Collecting local files on the DB: ${count}`, showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll");
|
||||||
const path = getPath(doc);
|
const path = getPath(doc);
|
||||||
if (isValidPath(path) && this.isTargetFile(path)) {
|
if (isValidPath(path) && await this.isTargetFile(path)) {
|
||||||
filesDatabase.push(path);
|
filesDatabase.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger("Opening the key-value database", LOG_LEVEL.VERBOSE);
|
Logger("Opening the key-value database", LOG_LEVEL_VERBOSE);
|
||||||
const isInitialized = await (this.kvDB.get<boolean>("initialized")) || false;
|
const isInitialized = await (this.kvDB.get<boolean>("initialized")) || false;
|
||||||
// Make chunk bigger if it is the initial scan. There must be non-active docs.
|
// Make chunk bigger if it is the initial scan. There must be non-active docs.
|
||||||
if (filesDatabase.length == 0 && !isInitialized) {
|
if (filesDatabase.length == 0 && !isInitialized) {
|
||||||
@@ -1778,8 +1790,8 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
await callback(e);
|
await callback(e);
|
||||||
return true;
|
return true;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
|
Logger(`Error while ${procedureName}`, LOG_LEVEL_NOTICE);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1808,7 +1820,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
await this.pullFile(e, filesStorage, false, null, false);
|
await this.pullFile(e, filesStorage, false, null, false);
|
||||||
Logger(`Check or pull from db:${e} OK`);
|
Logger(`Check or pull from db:${e} OK`);
|
||||||
} else if (w) {
|
} else if (w) {
|
||||||
Logger(`Deletion history skipped: ${e}`, LOG_LEVEL.VERBOSE);
|
Logger(`Deletion history skipped: ${e}`, LOG_LEVEL_VERBOSE);
|
||||||
} else {
|
} else {
|
||||||
Logger(`entry not found: ${e}`);
|
Logger(`entry not found: ${e}`);
|
||||||
}
|
}
|
||||||
@@ -1839,7 +1851,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
await (this.kvDB.set("initialized", true))
|
await (this.kvDB.set("initialized", true))
|
||||||
}
|
}
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
Logger("Initialize done!", LOG_LEVEL.NOTICE, "syncAll");
|
Logger("Initialize done!", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1990,7 +2002,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
// except insertion, the line should not be different.
|
// except insertion, the line should not be different.
|
||||||
if (rightItem[1] != leftItem[1]) {
|
if (rightItem[1] != leftItem[1]) {
|
||||||
//TODO: SHOULD BE PANIC.
|
//TODO: SHOULD BE PANIC.
|
||||||
Logger(`MERGING PANIC:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL.VERBOSE);
|
Logger(`MERGING PANIC:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL_VERBOSE);
|
||||||
autoMerge = false;
|
autoMerge = false;
|
||||||
break LOOP_MERGE;
|
break LOOP_MERGE;
|
||||||
}
|
}
|
||||||
@@ -2014,12 +2026,12 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
break LOOP_MERGE;
|
break LOOP_MERGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger(`Weird condition:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL.VERBOSE);
|
Logger(`Weird condition:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL_VERBOSE);
|
||||||
// here is the exception
|
// here is the exception
|
||||||
break LOOP_MERGE;
|
break LOOP_MERGE;
|
||||||
} while (leftIdx < diffLeft.length || rightIdx < diffRight.length);
|
} while (leftIdx < diffLeft.length || rightIdx < diffRight.length);
|
||||||
if (autoMerge) {
|
if (autoMerge) {
|
||||||
Logger(`Sensibly merge available`, LOG_LEVEL.VERBOSE);
|
Logger(`Sensibly merge available`, LOG_LEVEL_VERBOSE);
|
||||||
return merged;
|
return merged;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -2071,7 +2083,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
return JSON.stringify(newObj.data);
|
return JSON.stringify(newObj.data);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger("Could not merge object");
|
Logger("Could not merge object");
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE)
|
Logger(ex, LOG_LEVEL_VERBOSE)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2101,18 +2113,18 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
if (result) {
|
if (result) {
|
||||||
p = result.filter(e => e[0] != DIFF_DELETE).map((e) => e[1]).join("");
|
p = result.filter(e => e[0] != DIFF_DELETE).map((e) => e[1]).join("");
|
||||||
// can be merged.
|
// can be merged.
|
||||||
Logger(`Sensible merge:${path}`, LOG_LEVEL.INFO);
|
Logger(`Sensible merge:${path}`, LOG_LEVEL_INFO);
|
||||||
} else {
|
} else {
|
||||||
Logger(`Sensible merge is not applicable.`, LOG_LEVEL.VERBOSE);
|
Logger(`Sensible merge is not applicable.`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
} else if (isObjectMargeApplicable(path)) {
|
} else if (isObjectMargeApplicable(path)) {
|
||||||
// can be merged.
|
// can be merged.
|
||||||
const result = await this.mergeObject(path, commonBase, test._rev, conflictedRev);
|
const result = await this.mergeObject(path, commonBase, test._rev, conflictedRev);
|
||||||
if (result) {
|
if (result) {
|
||||||
Logger(`Object merge:${path}`, LOG_LEVEL.INFO);
|
Logger(`Object merge:${path}`, LOG_LEVEL_INFO);
|
||||||
p = result;
|
p = result;
|
||||||
} else {
|
} else {
|
||||||
Logger(`Object merge is not applicable.`, LOG_LEVEL.VERBOSE);
|
Logger(`Object merge is not applicable.`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2129,7 +2141,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
await this.updateIntoDB(newFile);
|
await this.updateIntoDB(newFile);
|
||||||
}
|
}
|
||||||
await this.pullFile(path);
|
await this.pullFile(path);
|
||||||
Logger(`Automatically merged (sensible) :${path}`, LOG_LEVEL.INFO);
|
Logger(`Automatically merged (sensible) :${path}`, LOG_LEVEL_INFO);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2139,14 +2151,14 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
const rightLeaf = await this.getConflictedDoc(path, conflicts[0]);
|
const rightLeaf = await this.getConflictedDoc(path, conflicts[0]);
|
||||||
if (leftLeaf == false) {
|
if (leftLeaf == false) {
|
||||||
// what's going on..
|
// what's going on..
|
||||||
Logger(`could not get current revisions:${path}`, LOG_LEVEL.NOTICE);
|
Logger(`could not get current revisions:${path}`, LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (rightLeaf == false) {
|
if (rightLeaf == false) {
|
||||||
// Conflicted item could not load, delete this.
|
// Conflicted item could not load, delete this.
|
||||||
await this.localDatabase.deleteDBEntry(path, { rev: conflicts[0] });
|
await this.localDatabase.deleteDBEntry(path, { rev: conflicts[0] });
|
||||||
await this.pullFile(path, null, true);
|
await this.pullFile(path, null, true);
|
||||||
Logger(`could not get old revisions, automatically used newer one:${path}`, LOG_LEVEL.NOTICE);
|
Logger(`could not get old revisions, automatically used newer one:${path}`, LOG_LEVEL_NOTICE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// first, check for same contents and deletion status.
|
// first, check for same contents and deletion status.
|
||||||
@@ -2169,7 +2181,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
}
|
}
|
||||||
await this.localDatabase.deleteDBEntry(path, { rev: loser.rev });
|
await this.localDatabase.deleteDBEntry(path, { rev: loser.rev });
|
||||||
await this.pullFile(path, null, true);
|
await this.pullFile(path, null, true);
|
||||||
Logger(`Automatically merged (newerFileResolve) :${path}`, LOG_LEVEL.NOTICE);
|
Logger(`Automatically merged (newerFileResolve) :${path}`, LOG_LEVEL_NOTICE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// make diff.
|
// make diff.
|
||||||
@@ -2187,15 +2199,15 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
showMergeDialog(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise<boolean> {
|
showMergeDialog(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise<boolean> {
|
||||||
return runWithLock("resolve-conflict:" + filename, false, () =>
|
return runWithLock("resolve-conflict:" + filename, false, () =>
|
||||||
new Promise((res, rej) => {
|
new Promise((res, rej) => {
|
||||||
Logger("open conflict dialog", LOG_LEVEL.VERBOSE);
|
Logger("open conflict dialog", LOG_LEVEL_VERBOSE);
|
||||||
new ConflictResolveModal(this.app, filename, conflictCheckResult, async (selected) => {
|
new ConflictResolveModal(this.app, filename, conflictCheckResult, async (selected) => {
|
||||||
const testDoc = await this.localDatabase.getDBEntry(filename, { conflicts: true }, false, false, true);
|
const testDoc = await this.localDatabase.getDBEntry(filename, { conflicts: true }, false, false, true);
|
||||||
if (testDoc === false) {
|
if (testDoc === false) {
|
||||||
Logger("Missing file..", LOG_LEVEL.VERBOSE);
|
Logger("Missing file..", LOG_LEVEL_VERBOSE);
|
||||||
return res(true);
|
return res(true);
|
||||||
}
|
}
|
||||||
if (!testDoc._conflicts) {
|
if (!testDoc._conflicts) {
|
||||||
Logger("Nothing have to do with this conflict", LOG_LEVEL.VERBOSE);
|
Logger("Nothing have to do with this conflict", LOG_LEVEL_VERBOSE);
|
||||||
return res(true);
|
return res(true);
|
||||||
}
|
}
|
||||||
const toDelete = selected;
|
const toDelete = selected;
|
||||||
@@ -2288,7 +2300,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
|
|
||||||
async pullFile(filename: FilePathWithPrefix, fileList?: TFile[], force?: boolean, rev?: string, waitForReady = true) {
|
async pullFile(filename: FilePathWithPrefix, fileList?: TFile[], force?: boolean, rev?: string, waitForReady = true) {
|
||||||
const targetFile = getAbstractFileByPath(stripAllPrefixes(filename));
|
const targetFile = getAbstractFileByPath(stripAllPrefixes(filename));
|
||||||
if (!this.isTargetFile(filename)) return;
|
if (!await this.isTargetFile(filename)) return;
|
||||||
if (targetFile == null) {
|
if (targetFile == null) {
|
||||||
//have to create;
|
//have to create;
|
||||||
const doc = await this.localDatabase.getDBEntry(filename, rev ? { rev: rev } : null, false, waitForReady);
|
const doc = await this.localDatabase.getDBEntry(filename, rev ? { rev: rev } : null, false, waitForReady);
|
||||||
@@ -2331,7 +2343,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
const dK = `${file.path}-diff`;
|
const dK = `${file.path}-diff`;
|
||||||
const isLastDiff = dK in caches ? caches[dK] : { storageMtime: 0, docMtime: 0 };
|
const isLastDiff = dK in caches ? caches[dK] : { storageMtime: 0, docMtime: 0 };
|
||||||
if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) {
|
if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) {
|
||||||
// Logger("STORAGE .. DB :" + file.path, LOG_LEVEL.VERBOSE);
|
// Logger("STORAGE .. DB :" + file.path, LOG_LEVEL_VERBOSE);
|
||||||
caches[dK] = { storageMtime, docMtime };
|
caches[dK] = { storageMtime, docMtime };
|
||||||
return caches;
|
return caches;
|
||||||
}
|
}
|
||||||
@@ -2355,14 +2367,14 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
caches[dK] = { storageMtime, docMtime };
|
caches[dK] = { storageMtime, docMtime };
|
||||||
return caches;
|
return caches;
|
||||||
}
|
}
|
||||||
Logger("STORAGE == DB :" + file.path + "", LOG_LEVEL.VERBOSE);
|
Logger("STORAGE == DB :" + file.path + "", LOG_LEVEL_VERBOSE);
|
||||||
caches[dK] = { storageMtime, docMtime };
|
caches[dK] = { storageMtime, docMtime };
|
||||||
return caches;
|
return caches;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateIntoDB(file: TFile, initialScan?: boolean, cache?: CacheData, force?: boolean) {
|
async updateIntoDB(file: TFile, initialScan?: boolean, cache?: CacheData, force?: boolean) {
|
||||||
if (!this.isTargetFile(file)) return true;
|
if (!await this.isTargetFile(file)) return true;
|
||||||
if (shouldBeIgnored(file.path)) {
|
if (shouldBeIgnored(file.path)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2370,14 +2382,14 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
let datatype: "plain" | "newnote" = "newnote";
|
let datatype: "plain" | "newnote" = "newnote";
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
if (!isPlainText(file.name)) {
|
if (!isPlainText(file.name)) {
|
||||||
Logger(`Reading : ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`Reading : ${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
const contentBin = await this.app.vault.readBinary(file);
|
const contentBin = await this.app.vault.readBinary(file);
|
||||||
Logger(`Processing: ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`Processing: ${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
try {
|
try {
|
||||||
content = await arrayBufferToBase64(contentBin);
|
content = await arrayBufferToBase64(contentBin);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`The file ${file.path} could not be encoded`);
|
Logger(`The file ${file.path} could not be encoded`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
datatype = "newnote";
|
datatype = "newnote";
|
||||||
@@ -2387,12 +2399,12 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cache instanceof ArrayBuffer) {
|
if (cache instanceof ArrayBuffer) {
|
||||||
Logger(`Processing: ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`Processing: ${file.path}`, LOG_LEVEL_VERBOSE);
|
||||||
try {
|
try {
|
||||||
content = await arrayBufferToBase64(cache);
|
content = await arrayBufferToBase64(cache);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Logger(`The file ${file.path} could not be encoded`);
|
Logger(`The file ${file.path} could not be encoded`);
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
datatype = "newnote"
|
datatype = "newnote"
|
||||||
@@ -2427,15 +2439,15 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
const newData = { data: d.data, deleted: d._deleted || d.deleted };
|
const newData = { data: d.data, deleted: d._deleted || d.deleted };
|
||||||
if (oldData.deleted != newData.deleted) return false;
|
if (oldData.deleted != newData.deleted) return false;
|
||||||
if (!isDocContentSame(old.data, newData.data)) return false;
|
if (!isDocContentSame(old.data, newData.data)) return false;
|
||||||
Logger(msg + "Skipped (not changed) " + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL.VERBOSE);
|
Logger(msg + "Skipped (not changed) " + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL_VERBOSE);
|
||||||
return true;
|
return true;
|
||||||
// d._rev = old._rev;
|
// d._rev = old._rev;
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (force) {
|
if (force) {
|
||||||
Logger(msg + "Error, Could not check the diff for the old one." + (force ? "force writing." : "") + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL.VERBOSE);
|
Logger(msg + "Error, Could not check the diff for the old one." + (force ? "force writing." : "") + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL_VERBOSE);
|
||||||
} else {
|
} else {
|
||||||
Logger(msg + "Error, Could not check the diff for the old one." + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL.VERBOSE);
|
Logger(msg + "Error, Could not check the diff for the old one." + fullPath + ((d._deleted || d.deleted) ? " (deleted)" : ""), LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
return !force;
|
return !force;
|
||||||
}
|
}
|
||||||
@@ -2453,7 +2465,7 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteFromDB(file: TFile) {
|
async deleteFromDB(file: TFile) {
|
||||||
if (!this.isTargetFile(file)) return;
|
if (!await this.isTargetFile(file)) return;
|
||||||
const fullPath = getPathFromTFile(file);
|
const fullPath = getPathFromTFile(file);
|
||||||
Logger(`deleteDB By path:${fullPath}`);
|
Logger(`deleteDB By path:${fullPath}`);
|
||||||
await this.deleteFromDBbyPath(fullPath);
|
await this.deleteFromDBbyPath(fullPath);
|
||||||
@@ -2536,15 +2548,49 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignoreFileCache = new LRUCache<string, string[] | false>(300, 250000, true);
|
||||||
|
ignoreFiles = [] as string[]
|
||||||
isTargetFile(file: string | TAbstractFile) {
|
async readIgnoreFile(path: string) {
|
||||||
if (file instanceof TFile) {
|
try {
|
||||||
return this.localDatabase.isTargetFile(file.path);
|
const file = await this.app.vault.adapter.read(path);
|
||||||
} else if (typeof file == "string") {
|
const gitignore = file.split(/\r?\n/g);
|
||||||
return this.localDatabase.isTargetFile(file);
|
this.ignoreFileCache.set(path, gitignore);
|
||||||
|
return gitignore;
|
||||||
|
} catch (ex) {
|
||||||
|
this.ignoreFileCache.set(path, false);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async getIgnoreFile(path: string) {
|
||||||
|
if (this.ignoreFileCache.has(path)) {
|
||||||
|
return this.ignoreFileCache.get(path);
|
||||||
|
} else {
|
||||||
|
return await this.readIgnoreFile(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async isIgnoredByIgnoreFiles(file: string | TAbstractFile) {
|
||||||
|
if (!this.settings.useIgnoreFiles) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const filepath = file instanceof TFile ? file.path : file as string;
|
||||||
|
if (this.ignoreFileCache.has(filepath)) {
|
||||||
|
// Renew
|
||||||
|
await this.readIgnoreFile(filepath);
|
||||||
|
}
|
||||||
|
if (!await isAcceptedAll(stripAllPrefixes(filepath as FilePathWithPrefix), this.ignoreFiles, (filename) => this.getIgnoreFile(filename))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isTargetFile(file: string | TAbstractFile) {
|
||||||
|
const filepath = file instanceof TFile ? file.path : file as string;
|
||||||
|
if (this.settings.useIgnoreFiles && !await this.isIgnoredByIgnoreFiles(file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.localDatabase.isTargetFile(filepath);
|
||||||
|
}
|
||||||
async dryRunGC() {
|
async dryRunGC() {
|
||||||
await runWithLock("cleanup", true, async () => {
|
await runWithLock("cleanup", true, async () => {
|
||||||
const remoteDBConn = await this.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.isMobile)
|
const remoteDBConn = await this.getReplicator().connectRemoteCouchDBWithSetting(this.settings, this.isMobile)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { PluginManifest, TFile } from "./deps";
|
import { type PluginManifest, TFile } from "./deps";
|
||||||
import { DatabaseEntry, EntryBody, FilePath } from "./lib/src/types";
|
import { type DatabaseEntry, type EntryBody, type FilePath } from "./lib/src/types";
|
||||||
|
|
||||||
export interface PluginDataEntry extends DatabaseEntry {
|
export interface PluginDataEntry extends DatabaseEntry {
|
||||||
deviceVaultName: string;
|
deviceVaultName: string;
|
||||||
|
|||||||
10
src/utils.ts
10
src/utils.ts
@@ -1,8 +1,8 @@
|
|||||||
import { type DataWriteOptions, normalizePath, TFile, Platform, TAbstractFile, App, Plugin_2, type RequestUrlParam, requestUrl } from "./deps";
|
import { type DataWriteOptions, normalizePath, TFile, Platform, TAbstractFile, App, Plugin, type RequestUrlParam, requestUrl } from "./deps";
|
||||||
import { path2id_base, id2path_base, isValidFilenameInLinux, isValidFilenameInDarwin, isValidFilenameInWidows, isValidFilenameInAndroid, stripAllPrefixes } from "./lib/src/path";
|
import { path2id_base, id2path_base, isValidFilenameInLinux, isValidFilenameInDarwin, isValidFilenameInWidows, isValidFilenameInAndroid, stripAllPrefixes } from "./lib/src/path";
|
||||||
|
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { type AnyEntry, type DocumentID, type EntryHasPath, type FilePath, type FilePathWithPrefix, LOG_LEVEL } from "./lib/src/types";
|
import { LOG_LEVEL_VERBOSE, type AnyEntry, type DocumentID, type EntryHasPath, type FilePath, type FilePathWithPrefix } from "./lib/src/types";
|
||||||
import { CHeader, ICHeader, ICHeaderLength, PSCHeader } from "./types";
|
import { CHeader, ICHeader, ICHeaderLength, PSCHeader } from "./types";
|
||||||
import { InputStringDialog, PopoverSelectString } from "./dialogs";
|
import { InputStringDialog, PopoverSelectString } from "./dialogs";
|
||||||
import ObsidianLiveSyncPlugin from "./main";
|
import ObsidianLiveSyncPlugin from "./main";
|
||||||
@@ -327,7 +327,7 @@ export function isValidPath(filename: string) {
|
|||||||
if (Platform.isAndroidApp) return isValidFilenameInAndroid(filename);
|
if (Platform.isAndroidApp) return isValidFilenameInAndroid(filename);
|
||||||
if (Platform.isIosApp) return isValidFilenameInDarwin(filename);
|
if (Platform.isIosApp) return isValidFilenameInDarwin(filename);
|
||||||
//Fallback
|
//Fallback
|
||||||
Logger("Could not determine platform for checking filename", LOG_LEVEL.VERBOSE);
|
Logger("Could not determine platform for checking filename", LOG_LEVEL_VERBOSE);
|
||||||
return isValidFilenameInWidows(filename);
|
return isValidFilenameInWidows(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,8 +415,8 @@ export const askString = (app: App, title: string, key: string, placeholder: str
|
|||||||
export class PeriodicProcessor {
|
export class PeriodicProcessor {
|
||||||
_process: () => Promise<any>;
|
_process: () => Promise<any>;
|
||||||
_timer?: number;
|
_timer?: number;
|
||||||
_plugin: Plugin_2;
|
_plugin: Plugin;
|
||||||
constructor(plugin: Plugin_2, process: () => Promise<any>) {
|
constructor(plugin: Plugin, process: () => Promise<any>) {
|
||||||
this._plugin = plugin;
|
this._plugin = plugin;
|
||||||
this._process = process;
|
this._process = process;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user