- Fixed a bug on `fetch chunks on demand` that could not fetch the chunks on demand.
- Improved:
  - `fetch chunks on demand` works more smoothly.
  - Initialisation `Fetch` is now more efficient.
- Tidied:
  - Removed some meaningless codes.
This commit is contained in:
vorotamoroz
2024-02-28 08:27:17 +00:00
parent 60cf8fe640
commit 3c6dae7814
8 changed files with 140 additions and 136 deletions

View File

@@ -178,9 +178,7 @@ export class ConfigSync extends LiveSyncCommands {
get kvDB() { get kvDB() {
return this.plugin.kvDB; return this.plugin.kvDB;
} }
ensureDirectoryEx(fullPath: string) {
return this.plugin.ensureDirectoryEx(fullPath);
}
pluginDialog: PluginDialogModal = null; pluginDialog: PluginDialogModal = null;
periodicPluginSweepProcessor = new PeriodicProcessor(this.plugin, async () => await this.scanAllConfigFiles(false)); periodicPluginSweepProcessor = new PeriodicProcessor(this.plugin, async () => await this.scanAllConfigFiles(false));
@@ -433,7 +431,7 @@ export class ConfigSync extends LiveSyncCommands {
try { try {
// console.dir(f); // console.dir(f);
const path = `${baseDir}/${f.filename}`; const path = `${baseDir}/${f.filename}`;
await this.ensureDirectoryEx(path); await this.vaultAccess.ensureDirectory(path);
if (!content) { if (!content) {
const dt = decodeBinary(f.data); const dt = decodeBinary(f.data);
await this.vaultAccess.adapterWrite(path, dt); await this.vaultAccess.adapterWrite(path, dt);

View File

@@ -20,9 +20,6 @@ export class HiddenFileSync extends LiveSyncCommands {
get kvDB() { get kvDB() {
return this.plugin.kvDB; return this.plugin.kvDB;
} }
ensureDirectoryEx(fullPath: string) {
return this.plugin.ensureDirectoryEx(fullPath);
}
getConflictedDoc(path: FilePathWithPrefix, rev: string) { getConflictedDoc(path: FilePathWithPrefix, rev: string) {
return this.plugin.getConflictedDoc(path, rev); return this.plugin.getConflictedDoc(path, rev);
} }
@@ -202,7 +199,7 @@ export class HiddenFileSync extends LiveSyncCommands {
const filename = stripAllPrefixes(path); const filename = stripAllPrefixes(path);
const isExists = await this.plugin.vaultAccess.adapterExists(filename); const isExists = await this.plugin.vaultAccess.adapterExists(filename);
if (!isExists) { if (!isExists) {
await this.ensureDirectoryEx(filename); await this.vaultAccess.ensureDirectory(filename);
} }
await this.plugin.vaultAccess.adapterWrite(filename, result); await this.plugin.vaultAccess.adapterWrite(filename, result);
const stat = await this.vaultAccess.adapterStat(filename); const stat = await this.vaultAccess.adapterStat(filename);
@@ -498,7 +495,7 @@ export class HiddenFileSync extends LiveSyncCommands {
type: "newnote", type: "newnote",
}; };
} }
const ret = await this.localDatabase.putDBEntry(saveData, true); const ret = await this.localDatabase.putDBEntry(saveData);
Logger(`STORAGE --> DB:${file.path}: (hidden) Done`); Logger(`STORAGE --> DB:${file.path}: (hidden) Done`);
return ret; return ret;
} catch (ex) { } catch (ex) {
@@ -599,7 +596,7 @@ export class HiddenFileSync extends LiveSyncCommands {
return true; return true;
} }
if (!isExists) { if (!isExists) {
await this.ensureDirectoryEx(filename); await this.vaultAccess.ensureDirectory(filename);
await this.plugin.vaultAccess.adapterWrite(filename, decodeBinary(fileOnDB.data), { mtime: fileOnDB.mtime, ctime: fileOnDB.ctime }); await this.plugin.vaultAccess.adapterWrite(filename, decodeBinary(fileOnDB.data), { mtime: fileOnDB.mtime, ctime: fileOnDB.ctime });
try { try {
//@ts-ignore internalAPI //@ts-ignore internalAPI
@@ -668,7 +665,7 @@ export class HiddenFileSync extends LiveSyncCommands {
if (!keep && result) { if (!keep && result) {
const isExists = await this.plugin.vaultAccess.adapterExists(filename); const isExists = await this.plugin.vaultAccess.adapterExists(filename);
if (!isExists) { if (!isExists) {
await this.ensureDirectoryEx(filename); await this.vaultAccess.ensureDirectory(filename);
} }
await this.plugin.vaultAccess.adapterWrite(filename, result); await this.plugin.vaultAccess.adapterWrite(filename, result);
const stat = await this.plugin.vaultAccess.adapterStat(filename); const stat = await this.plugin.vaultAccess.adapterStat(filename);

View File

@@ -359,7 +359,7 @@ Of course, we are able to disable these features.`
Logger(`Fetching chunks done`, LOG_LEVEL_NOTICE); Logger(`Fetching chunks done`, LOG_LEVEL_NOTICE);
} }
} }
async fetchLocal() { async fetchLocal(makeLocalChunkBeforeSync?: boolean) {
this.suspendExtraSync(); this.suspendExtraSync();
await this.askUseNewAdapter(); await this.askUseNewAdapter();
this.plugin.settings.isConfigured = true; this.plugin.settings.isConfigured = true;
@@ -368,8 +368,11 @@ Of course, we are able to disable these features.`
await this.resetLocalDatabase(); await this.resetLocalDatabase();
await delay(1000); await delay(1000);
await this.plugin.openDatabase(); await this.plugin.openDatabase();
await this.plugin.markRemoteResolved();
this.plugin.isReady = true; this.plugin.isReady = true;
if (makeLocalChunkBeforeSync) {
await this.plugin.initializeDatabase(true);
}
await this.plugin.markRemoteResolved();
await delay(500); await delay(500);
await this.plugin.replicateAllFromServer(true); await this.plugin.replicateAllFromServer(true);
await delay(1000); await delay(1000);
@@ -379,24 +382,7 @@ Of course, we are able to disable these features.`
await this.askHiddenFileConfiguration({ enableFetch: true }); await this.askHiddenFileConfiguration({ enableFetch: true });
} }
async fetchLocalWithKeepLocal() { async fetchLocalWithKeepLocal() {
this.suspendExtraSync(); return await this.fetchLocal(true);
await this.askUseNewAdapter();
this.plugin.settings.isConfigured = true;
await this.suspendReflectingDatabase();
await this.plugin.realizeSettingSyncMode();
await this.resetLocalDatabase();
await delay(1000);
await this.plugin.initializeDatabase(true);
await this.plugin.openDatabase();
await this.plugin.markRemoteResolved();
this.plugin.isReady = true;
await delay(500);
await this.plugin.replicateAllFromServer(true);
await delay(1000);
await this.plugin.replicateAllFromServer(true);
await this.fetchRemoteChunks();
await this.resumeReflectingDatabase();
await this.askHiddenFileConfiguration({ enableFetch: true });
} }
async rebuildRemote() { async rebuildRemote() {
this.suspendExtraSync(); this.suspendExtraSync();

View File

@@ -663,7 +663,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
.setWarning() .setWarning()
.setDisabled(false) .setDisabled(false)
.onClick(async () => { .onClick(async () => {
await rebuildDB("localOnly"); await rebuildDB("localOnlyWithChunks");
}) })
) )
.addButton((button) => .addButton((button) =>
@@ -732,7 +732,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
} }
}; };
const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") => { const rebuildDB = async (method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks") => {
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;
@@ -1053,9 +1053,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
if (!this.plugin.settings.isConfigured) { if (!this.plugin.settings.isConfigured) {
this.plugin.settings.isConfigured = true; this.plugin.settings.isConfigured = true;
await this.plugin.saveSettings(); await this.plugin.saveSettings();
await rebuildDB("localOnly"); await rebuildDB("localOnlyWithChunks");
Logger("All done! Please set up subsequent devices with 'Copy current settings as a new setup URI' and 'Use the copied setup URI'.", LOG_LEVEL_NOTICE); Logger("All done! Please set up subsequent devices with 'Copy current settings as a new setup URI' and 'Use the copied setup URI'.", LOG_LEVEL_NOTICE);
await this.plugin.addOnSetup.command_openSetupURI(); await this.plugin.addOnSetup.command_copySetupURI();
} else { } else {
this.askReload(); this.askReload();
} }
@@ -1922,7 +1922,7 @@ ${stringifyYaml(pluginConfig)}`;
toggle.setValue(!this.plugin.settings.useIndexedDBAdapter).onChange(async (value) => { toggle.setValue(!this.plugin.settings.useIndexedDBAdapter).onChange(async (value) => {
this.plugin.settings.useIndexedDBAdapter = !value; this.plugin.settings.useIndexedDBAdapter = !value;
await this.plugin.saveSettings(); await this.plugin.saveSettings();
await rebuildDB("localOnly"); await rebuildDB("localOnlyWithChunks");
}) })
); );
@@ -2119,6 +2119,19 @@ ${stringifyYaml(pluginConfig)}`;
.setButtonText("Fetch") .setButtonText("Fetch")
.setWarning() .setWarning()
.setDisabled(false) .setDisabled(false)
.onClick(async () => {
await rebuildDB("localOnlyWithChunks");
})
)
new Setting(containerMaintenanceEl)
.setName("Fetch rebuilt DB with all remote chunks")
.setDesc("Restore or reconstruct local database from remote database but use remote chunk .")
.addButton((button) =>
button
.setButtonText("Fetch all")
.setWarning()
.setDisabled(false)
.onClick(async () => { .onClick(async () => {
await rebuildDB("localOnly"); await rebuildDB("localOnly");
}) })

View File

@@ -1,5 +1,6 @@
import { type App, TFile, type DataWriteOptions, TFolder, TAbstractFile } from "./deps"; import { type App, TFile, type DataWriteOptions, TFolder, TAbstractFile } from "./deps";
import { serialized } from "./lib/src/lock"; import { serialized } from "./lib/src/lock";
import { Logger } from "./lib/src/logger";
import type { FilePath } from "./lib/src/types"; import type { FilePath } from "./lib/src/types";
import { createBinaryBlob, isDocContentSame } from "./lib/src/utils"; import { createBinaryBlob, isDocContentSame } from "./lib/src/utils";
import type { InternalFileInfo } from "./types"; import type { InternalFileInfo } from "./types";
@@ -107,6 +108,15 @@ export class SerializedFileAccess {
return await processWriteFile(path, () => this.app.vault.createBinary(path, toArrayBuffer(data), options)); return await processWriteFile(path, () => this.app.vault.createBinary(path, toArrayBuffer(data), options));
} }
} }
trigger(name: string, ...data: any[]) {
return this.app.vault.trigger(name, ...data);
}
async adapterAppend(normalizedPath: string, data: string, options?: DataWriteOptions) {
return await this.app.vault.adapter.append(normalizedPath, data, options)
}
async delete(file: TFile | TFolder, force = false) { async delete(file: TFile | TFolder, force = false) {
return await processWriteFile(file, () => this.app.vault.delete(file, force)); return await processWriteFile(file, () => this.app.vault.delete(file, force));
} }
@@ -127,6 +137,31 @@ export class SerializedFileAccess {
// } // }
} }
getFiles() {
return this.app.vault.getFiles();
}
async ensureDirectory(fullPath: string) {
const pathElements = fullPath.split("/");
pathElements.pop();
let c = "";
for (const v of pathElements) {
c += v;
try {
await this.app.vault.adapter.mkdir(c);
} catch (ex) {
// basically skip exceptions.
if (ex.message && ex.message == "Folder already exists.") {
// especially this message is.
} else {
Logger("Folder Create Error");
Logger(ex);
}
}
c += "/";
}
}
touchedFiles: string[] = []; touchedFiles: string[] = [];

Submodule src/lib updated: 1a3488339e...8a8177c1f0

View File

@@ -84,7 +84,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin
this._suspended = value; this._suspended = value;
} }
deviceAndVaultName = ""; deviceAndVaultName = "";
isMobile = false;
isReady = false; isReady = false;
packageVersion = ""; packageVersion = "";
manifestVersion = ""; manifestVersion = "";
@@ -248,6 +247,22 @@ export default class ObsidianLiveSyncPlugin extends Plugin
} }
} }
get isMobile() {
// @ts-ignore: internal API
return this.app.isMobile
}
get vaultName() {
return this.app.vault.getName()
}
getActiveFile() {
return this.app.workspace.getActiveFile();
}
get appId() {
return `${("appId" in this.app ? this.app.appId : "")}`;
}
id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix { id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix {
const tempId = id2path(id, entry); const tempId = id2path(id, entry);
if (stripPrefix && isInternalMetadata(tempId)) { if (stripPrefix && isInternalMetadata(tempId)) {
@@ -309,13 +324,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
// end interfaces // end interfaces
getVaultName(): string { getVaultName(): string {
return this.app.vault.getName() + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : ""); return this.vaultName + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : "");
}
setInterval(handler: () => any, timeout?: number): number {
const timer = window.setInterval(handler, timeout);
this.registerInterval(timer);
return timer;
} }
isFlagFileExist(path: string) { isFlagFileExist(path: string) {
@@ -361,7 +370,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);
const target = await askSelectString(this.app, "File to view History", notesList); const target = await this.askSelectString("File to view History", notesList);
if (target) { if (target) {
const targetId = notes.find(e => e.dispPath == target); const targetId = notes.find(e => e.dispPath == target);
this.showHistory(targetId.path, targetId.id); this.showHistory(targetId.path, targetId.id);
@@ -379,7 +388,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
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 resolve conflict", notesList); const target = await this.askSelectString("File to resolve conflict", notesList);
if (target) { if (target) {
const targetItem = notes.find(e => e.dispPath == target); const targetItem = notes.find(e => e.dispPath == target);
this.resolveConflicted(targetItem.path); this.resolveConflicted(targetItem.path);
@@ -458,10 +467,7 @@ Click anywhere to stop counting down.
const ret = await confirmWithMessage(this, "Welcome to Self-hosted LiveSync", message, [USE_SETUP, OPEN_SETUP, DISMISS], DISMISS, 40); const ret = await confirmWithMessage(this, "Welcome to Self-hosted LiveSync", message, [USE_SETUP, OPEN_SETUP, DISMISS], DISMISS, 40);
if (ret === OPEN_SETUP) { if (ret === OPEN_SETUP) {
try { try {
//@ts-ignore: undocumented api this.openSetting();
this.app.setting.open();
//@ts-ignore: undocumented api
this.app.setting.openTabById("obsidian-livesync");
} catch (ex) { } catch (ex) {
Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE); Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE);
} }
@@ -482,22 +488,20 @@ Click anywhere to stop counting down.
Logger(`${FLAGMD_REDFLAG2} or ${FLAGMD_REDFLAG2_HR} has been detected! Self-hosted LiveSync suspends all sync and rebuild everything.`, LOG_LEVEL_NOTICE); Logger(`${FLAGMD_REDFLAG2} or ${FLAGMD_REDFLAG2_HR} 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 this.askYesNo("Do you want to disable Suspend file watching and restart obsidian now?") == "yes") {
this.settings.suspendFileWatching = false; this.settings.suspendFileWatching = false;
await this.saveSettings(); await this.saveSettings();
// @ts-ignore this.performAppReload();
this.app.commands.executeCommandById("app:reload")
} }
} else if (this.isRedFlag3Raised()) { } else if (this.isRedFlag3Raised()) {
Logger(`${FLAGMD_REDFLAG3} or ${FLAGMD_REDFLAG3_HR} 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} or ${FLAGMD_REDFLAG3_HR} 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) {
if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { if (await this.askYesNo("Do you want to disable Suspend file watching and restart obsidian now?") == "yes") {
this.settings.suspendFileWatching = false; this.settings.suspendFileWatching = false;
await this.saveSettings(); await this.saveSettings();
// @ts-ignore this.performAppReload();
this.app.commands.executeCommandById("app:reload")
} }
} }
} else { } else {
@@ -546,8 +550,7 @@ Click anywhere to stop counting down.
this.askInPopup(`conflicting-detected-on-safety`, `Some files have been left conflicted! Press {HERE} to resolve them, or you can do it later by "Pick a file to resolve conflict`, (anchor) => { this.askInPopup(`conflicting-detected-on-safety`, `Some files have been left conflicted! Press {HERE} to resolve them, or you can do it later by "Pick a file to resolve conflict`, (anchor) => {
anchor.text = "HERE"; anchor.text = "HERE";
anchor.addEventListener("click", () => { anchor.addEventListener("click", () => {
// @ts-ignore this.performCommand("obsidian-livesync:livesync-all-conflictcheck");
this.app.commands.executeCommandById("obsidian-livesync:livesync-all-conflictcheck");
}); });
} }
); );
@@ -629,7 +632,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
// this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false); // this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false);
// }, // },
callback: () => { callback: () => {
const file = this.app.workspace.getActiveFile(); const file = this.getActiveFile();
if (!file) return; if (!file) return;
this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false); this.localDatabase.getDBEntry(getPathFromTFile(file), {}, true, false);
}, },
@@ -678,7 +681,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
id: "livesync-history", id: "livesync-history",
name: "Show history", name: "Show history",
callback: () => { callback: () => {
const file = this.app.workspace.getActiveFile(); const file = this.getActiveFile();
if (file) this.showHistory(file, null); if (file) this.showHistory(file, null);
} }
}); });
@@ -791,8 +794,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
} }
//@ts-ignore //@ts-ignore
if (this.app.isMobile) { if (this.isMobile) {
this.isMobile = true;
this.settings.disableRequestURI = true; this.settings.disableRequestURI = true;
} }
if (last_version && Number(last_version) < VER) { if (last_version && Number(last_version) < VER) {
@@ -869,8 +871,6 @@ Note: We can always able to read V1 format. It will be progressively converted.
} }
const vaultName = this.getVaultName(); const vaultName = this.getVaultName();
Logger("Waiting for ready..."); Logger("Waiting for ready...");
//@ts-ignore
this.isMobile = this.app.isMobile;
this.localDatabase = new LiveSyncLocalDB(vaultName, this); this.localDatabase = new LiveSyncLocalDB(vaultName, this);
initializeStores(vaultName); initializeStores(vaultName);
return await this.localDatabase.initializeDatabase(); return await this.localDatabase.initializeDatabase();
@@ -933,7 +933,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) { if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) {
settings.isConfigured = true; settings.isConfigured = true;
} else { } else {
settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}` settings.additionalSuffixOfDatabaseName = this.appId;
settings.isConfigured = false; settings.isConfigured = false;
} }
} }
@@ -1057,7 +1057,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
} }
async parseSettingFromMarkdown(filename: string, data?: string) { async parseSettingFromMarkdown(filename: string, data?: string) {
const file = this.app.vault.getAbstractFileByPath(filename); const file = this.vaultAccess.getAbstractFileByPath(filename);
if (!(file instanceof TFile)) return { if (!(file instanceof TFile)) return {
preamble: "", preamble: "",
body: "", body: "",
@@ -1066,7 +1066,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
if (data) { if (data) {
return this.extractSettingFromWholeText(data); return this.extractSettingFromWholeText(data);
} }
const parseData = data ?? await this.app.vault.read(file); const parseData = data ?? await this.vaultAccess.vaultRead(file);
return this.extractSettingFromWholeText(parseData); return this.extractSettingFromWholeText(parseData);
} }
@@ -1115,7 +1115,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
const APPLY_AND_REBUILD = "Apply settings and restart obsidian with red_flag_rebuild.md"; const APPLY_AND_REBUILD = "Apply settings and restart obsidian with red_flag_rebuild.md";
const APPLY_AND_FETCH = "Apply settings and restart obsidian with red_flag_fetch.md"; const APPLY_AND_FETCH = "Apply settings and restart obsidian with red_flag_fetch.md";
const CANCEL = "Cancel"; const CANCEL = "Cancel";
const result = await askSelectString(this.app, "Ready for apply the setting.", [APPLY_AND_RESTART, APPLY_ONLY, APPLY_AND_FETCH, APPLY_AND_REBUILD, CANCEL]); const result = await this.askSelectString("Ready for apply the setting.", [APPLY_AND_RESTART, APPLY_ONLY, APPLY_AND_FETCH, APPLY_AND_REBUILD, CANCEL]);
if (result == APPLY_ONLY || result == APPLY_AND_RESTART || result == APPLY_AND_REBUILD || result == APPLY_AND_FETCH) { if (result == APPLY_ONLY || result == APPLY_AND_RESTART || result == APPLY_AND_REBUILD || result == APPLY_AND_FETCH) {
this.settings = settingToApply; this.settings = settingToApply;
await this.saveSettingData(); await this.saveSettingData();
@@ -1124,13 +1124,12 @@ Note: We can always able to read V1 format. It will be progressively converted.
return; return;
} }
if (result == APPLY_AND_REBUILD) { if (result == APPLY_AND_REBUILD) {
await this.app.vault.create(FLAGMD_REDFLAG2_HR, ""); await this.vaultAccess.vaultCreate(FLAGMD_REDFLAG2_HR, "");
} }
if (result == APPLY_AND_FETCH) { if (result == APPLY_AND_FETCH) {
await this.app.vault.create(FLAGMD_REDFLAG3_HR, ""); await this.vaultAccess.vaultCreate(FLAGMD_REDFLAG3_HR, "");
} }
// @ts-ignore this.performAppReload();
this.app.commands.executeCommandById("app:reload");
} }
} }
) )
@@ -1150,11 +1149,11 @@ Note: We can always able to read V1 format. It will be progressively converted.
async saveSettingToMarkdown(filename: string) { async saveSettingToMarkdown(filename: string) {
const saveData = this.generateSettingForMarkdown(); const saveData = this.generateSettingForMarkdown();
let file = this.app.vault.getAbstractFileByPath(filename); let file = this.vaultAccess.getAbstractFileByPath(filename);
if (!file) { if (!file) {
await this.ensureDirectoryEx(filename); await this.vaultAccess.ensureDirectory(filename);
const initialContent = `This file contains Self-hosted LiveSync settings as YAML. const initialContent = `This file contains Self-hosted LiveSync settings as YAML.
Except for the \`livesync-setting\` code block, we can add a note for free. Except for the \`livesync-setting\` code block, we can add a note for free.
@@ -1167,21 +1166,21 @@ We can perform a command in this file.
` `
file = await this.app.vault.create(filename, initialContent + SETTING_HEADER + "\n" + SETTING_FOOTER); file = await this.vaultAccess.vaultCreate(filename, initialContent + SETTING_HEADER + "\n" + SETTING_FOOTER);
} }
if (!(file instanceof TFile)) { if (!(file instanceof TFile)) {
Logger(`Markdown Setting: ${filename} already exists as a folder`, LOG_LEVEL_NOTICE); Logger(`Markdown Setting: ${filename} already exists as a folder`, LOG_LEVEL_NOTICE);
return; return;
} }
const data = await this.app.vault.read(file); const data = await this.vaultAccess.vaultRead(file);
const { preamble, body, postscript } = this.extractSettingFromWholeText(data); const { preamble, body, postscript } = this.extractSettingFromWholeText(data);
const newBody = stringifyYaml(saveData); const newBody = stringifyYaml(saveData);
if (newBody == body) { if (newBody == body) {
Logger("Markdown setting: Nothing had been changed", LOG_LEVEL_VERBOSE); Logger("Markdown setting: Nothing had been changed", LOG_LEVEL_VERBOSE);
} else { } else {
await this.app.vault.modify(file, preamble + SETTING_HEADER + newBody + SETTING_FOOTER + postscript); await this.vaultAccess.vaultModify(file, preamble + SETTING_HEADER + newBody + SETTING_FOOTER + postscript);
Logger(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE); Logger(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE);
} }
} }
@@ -1224,8 +1223,7 @@ We can perform a command in this file.
const _this = this; const _this = this;
//@ts-ignore //@ts-ignore
window.CodeMirrorAdapter.commands.save = () => { window.CodeMirrorAdapter.commands.save = () => {
//@ts-ignore _this.performCommand('editor:save-file');
_this.app.commands.executeCommandById('editor:save-file');
}; };
} }
registerWatchEvents() { registerWatchEvents() {
@@ -1235,7 +1233,6 @@ We can perform a command in this file.
this.registerDomEvent(window, "offline", this.watchOnline); this.registerDomEvent(window, "offline", this.watchOnline);
} }
watchOnline() { watchOnline() {
scheduleTask("watch-online", 500, () => fireAndForget(() => this.watchOnlineAsync())); scheduleTask("watch-online", 500, () => fireAndForget(() => this.watchOnlineAsync()));
} }
@@ -1456,9 +1453,9 @@ We can perform a command in this file.
const logDate = `${PREFIXMD_LOGFILE}${time}.md`; const logDate = `${PREFIXMD_LOGFILE}${time}.md`;
const file = this.vaultAccess.getAbstractFileByPath(normalizePath(logDate)); const file = this.vaultAccess.getAbstractFileByPath(normalizePath(logDate));
if (!file) { if (!file) {
this.app.vault.adapter.append(normalizePath(logDate), "```\n"); this.vaultAccess.adapterAppend(normalizePath(logDate), "```\n");
} }
this.app.vault.adapter.append(normalizePath(logDate), vaultName + ":" + newMessage + "\n"); this.vaultAccess.adapterAppend(normalizePath(logDate), vaultName + ":" + newMessage + "\n");
} }
recentLogProcessor.enqueue(newMessage); recentLogProcessor.enqueue(newMessage);
@@ -1496,28 +1493,6 @@ We can perform a command in this file.
}) })
} }
} }
async ensureDirectory(fullPath: string) {
const pathElements = fullPath.split("/");
pathElements.pop();
let c = "";
for (const v of pathElements) {
c += v;
try {
await this.app.vault.createFolder(c);
} catch (ex) {
// basically skip exceptions.
if (ex.message && ex.message == "Folder already exists.") {
// especially this message is.
} else {
Logger("Folder Create Error");
Logger(ex);
}
}
c += "/";
}
}
async processEntryDoc(docEntry: EntryBody, file: TFile | undefined, force?: boolean) { async processEntryDoc(docEntry: EntryBody, file: TFile | undefined, force?: boolean) {
const mode = file == undefined ? "create" : "modify"; const mode = file == undefined ? "create" : "modify";
@@ -1577,7 +1552,7 @@ We can perform a command in this file.
return; return;
} }
const writeData = doc.datatype == "newnote" ? decodeBinary(doc.data) : getDocData(doc.data); const writeData = doc.datatype == "newnote" ? decodeBinary(doc.data) : getDocData(doc.data);
await this.ensureDirectoryEx(path); await this.vaultAccess.ensureDirectory(path);
try { try {
let outFile; let outFile;
let isChanged = true; let isChanged = true;
@@ -1592,7 +1567,7 @@ We can perform a command in this file.
if (isChanged) { if (isChanged) {
Logger(msg + path); Logger(msg + path);
this.vaultAccess.touch(outFile); this.vaultAccess.touch(outFile);
this.app.vault.trigger(mode, outFile); this.vaultAccess.trigger(mode, outFile);
} else { } else {
Logger(msg + "Skipped, the file is the same: " + path, LOG_LEVEL_VERBOSE); Logger(msg + "Skipped, the file is the same: " + path, LOG_LEVEL_VERBOSE);
} }
@@ -1626,7 +1601,7 @@ We can perform a command in this file.
queueConflictCheck(file: FilePathWithPrefix | TFile) { queueConflictCheck(file: FilePathWithPrefix | TFile) {
const path = file instanceof TFile ? getPathFromTFile(file) : file; const path = file instanceof TFile ? getPathFromTFile(file) : file;
if (this.settings.checkConflictOnlyOnOpen) { if (this.settings.checkConflictOnlyOnOpen) {
const af = this.app.workspace.getActiveFile(); const af = this.getActiveFile();
if (af && af.path != path) { if (af && af.path != path) {
Logger(`${file} is conflicted, merging process has been postponed.`, LOG_LEVEL_NOTICE); Logger(`${file} is conflicted, merging process has been postponed.`, LOG_LEVEL_NOTICE);
return; return;
@@ -1927,7 +1902,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
const CHOICE_DISMISS = "Dismiss"; const CHOICE_DISMISS = "Dismiss";
const ret = await confirmWithMessage(this, "Cleaned", message, [CHOICE_FETCH, CHOICE_CLEAN, CHOICE_DISMISS], CHOICE_DISMISS, 30); const ret = await confirmWithMessage(this, "Cleaned", message, [CHOICE_FETCH, CHOICE_CLEAN, CHOICE_DISMISS], CHOICE_DISMISS, 30);
if (ret == CHOICE_FETCH) { if (ret == CHOICE_FETCH) {
await performRebuildDB(this, "localOnly"); await performRebuildDB(this, "localOnlyWithChunks");
} }
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);
@@ -1961,7 +1936,7 @@ Or if you are sure know what had been happened, we can unlock the database from
const CHOICE_DISMISS = "Dismiss"; const CHOICE_DISMISS = "Dismiss";
const ret = await confirmWithMessage(this, "Locked", message, [CHOICE_FETCH, CHOICE_DISMISS], CHOICE_DISMISS, 10); const ret = await confirmWithMessage(this, "Locked", message, [CHOICE_FETCH, CHOICE_DISMISS], CHOICE_DISMISS, 10);
if (ret == CHOICE_FETCH) { if (ret == CHOICE_FETCH) {
await performRebuildDB(this, "localOnly"); await performRebuildDB(this, "localOnlyWithChunks");
} }
} }
} }
@@ -2036,7 +2011,7 @@ Or if you are sure know what had been happened, we can unlock the database from
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 filesStorageSrc = this.app.vault.getFiles(); const filesStorageSrc = this.vaultAccess.getFiles();
const filesStorage = [] as typeof filesStorageSrc; const filesStorage = [] as typeof filesStorageSrc;
for (const f of filesStorageSrc) { for (const f of filesStorageSrc) {
@@ -2534,7 +2509,7 @@ Or if you are sure know what had been happened, we can unlock the database from
return; return;
} }
if (this.settings.showMergeDialogOnlyOnActive) { if (this.settings.showMergeDialogOnlyOnActive) {
const af = this.app.workspace.getActiveFile(); const af = this.getActiveFile();
if (af && af.path != filename) { if (af && af.path != filename) {
Logger(`${filename} is conflicted. Merging process has been postponed to the file have got opened.`, LOG_LEVEL_NOTICE); Logger(`${filename} is conflicted. Merging process has been postponed to the file have got opened.`, LOG_LEVEL_NOTICE);
return; return;
@@ -2820,27 +2795,6 @@ Or if you are sure know what had been happened, we can unlock the database from
await this.replicator.tryCreateRemoteDatabase(this.settings); await this.replicator.tryCreateRemoteDatabase(this.settings);
} }
async ensureDirectoryEx(fullPath: string) {
const pathElements = fullPath.split("/");
pathElements.pop();
let c = "";
for (const v of pathElements) {
c += v;
try {
await this.app.vault.adapter.mkdir(c);
} catch (ex) {
// basically skip exceptions.
if (ex.message && ex.message == "Folder already exists.") {
// especially this message is.
} else {
Logger("Folder Create Error");
Logger(ex);
}
}
c += "/";
}
}
filterTargetFiles(files: InternalFileInfo[], targetFiles: string[] | false = false) { filterTargetFiles(files: InternalFileInfo[], targetFiles: string[] | false = false) {
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns
.replace(/\n| /g, "") .replace(/\n| /g, "")
@@ -2949,6 +2903,12 @@ Or if you are sure know what had been happened, we can unlock the database from
}); });
} }
askYesNo(message: string): Promise<"yes" | "no"> {
return askYesNo(this.app, message);
}
askSelectString(message: string, items: string[]): Promise<string> {
return askSelectString(this.app, message, items);
}
askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void) { askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void) {
@@ -2967,7 +2927,6 @@ Or if you are sure know what had been happened, we can unlock the database from
const popupKey = "popup-" + key; const popupKey = "popup-" + key;
scheduleTask(popupKey, 1000, async () => { scheduleTask(popupKey, 1000, async () => {
const popup = await memoIfNotExist(popupKey, () => new Notice(fragment, 0)); const popup = await memoIfNotExist(popupKey, () => new Notice(fragment, 0));
//@ts-ignore
const isShown = popup?.noticeEl?.isShown(); const isShown = popup?.noticeEl?.isShown();
if (!isShown) { if (!isShown) {
memoObject(popupKey, new Notice(fragment, 0)); memoObject(popupKey, new Notice(fragment, 0));
@@ -2976,7 +2935,6 @@ Or if you are sure know what had been happened, we can unlock the database from
const popup = retrieveMemoObject<Notice>(popupKey); const popup = retrieveMemoObject<Notice>(popupKey);
if (!popup) if (!popup)
return; return;
//@ts-ignore
if (popup?.noticeEl?.isShown()) { if (popup?.noticeEl?.isShown()) {
popup.hide(); popup.hide();
} }
@@ -2984,5 +2942,19 @@ Or if you are sure know what had been happened, we can unlock the database from
}); });
}); });
} }
openSetting() {
//@ts-ignore: undocumented api
this.app.setting.open();
//@ts-ignore: undocumented api
this.app.setting.openTabById("obsidian-livesync");
}
performAppReload() {
this.performCommand("app:reload");
}
performCommand(id: string) {
// @ts-ignore
this.app.commands.executeCommandById(id)
}
} }

View File

@@ -405,10 +405,13 @@ export const requestToCouchDB = async (baseUri: string, username: string, passwo
return await _requestToCouchDB(baseUri, username, password, origin, uri, body, method); return await _requestToCouchDB(baseUri, username, password, origin, uri, body, method);
}; };
export async function performRebuildDB(plugin: ObsidianLiveSyncPlugin, method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice") { export async function performRebuildDB(plugin: ObsidianLiveSyncPlugin, method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks") {
if (method == "localOnly") { if (method == "localOnly") {
await plugin.addOnSetup.fetchLocal(); await plugin.addOnSetup.fetchLocal();
} }
if (method == "localOnlyWithChunks") {
await plugin.addOnSetup.fetchLocal(true);
}
if (method == "remoteOnly") { if (method == "remoteOnly") {
await plugin.addOnSetup.rebuildRemote(); await plugin.addOnSetup.rebuildRemote();
} }