mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-04-21 08:28:34 +00:00
11th March, 2026
Now, Self-hosted LiveSync has finally begun to be split into the Self-hosted LiveSync plugin for Obsidian, and a properly abstracted version of it. This may not offer much benefit to Obsidian plugin users, or might even cause a slight inconvenience, but I believe it will certainly help improve testability and make the ecosystem better. However, I do not see the point in putting something with little benefit into beta, so I am handling this on the alpha branch. I would actually preferred to create an R&D branch, but I was not keen on the ampersand, and I feel it will eventually become a proper beta anyway. ### Refactored - Separated `ObsidianLiveSyncPlugin` into `ObsidianLiveSyncPlugin` and `LiveSyncBaseCore`. - Now `LiveSyncCore` indicates the type specified version of `LiveSyncBaseCore`. - Referencing `plugin.xxx` has been rewritten to referencing the corresponding service or `core.xxx`. ### Internal API changes - Storage Access APIs are now yielding Promises. This is to allow more limited storage platforms to be supported. ### R&D - Browser-version of Self-hosted LiveSync is now in development. This is not intended for public use now, but I will eventually make it available for testing. - We can see the code in `src/apps/webapp` for the browser version.
This commit is contained in:
@@ -15,6 +15,7 @@ import { isErrorOfMissingDoc } from "../../../lib/src/pouchdb/utils_couchdb.ts";
|
||||
import { fireAndForget, getDocData, readContent } from "../../../lib/src/common/utils.ts";
|
||||
import { isPlainText, stripPrefix } from "../../../lib/src/string_and_binary/path.ts";
|
||||
import { scheduleOnceIfDuplicated } from "octagonal-wheels/concurrency/lock";
|
||||
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
|
||||
|
||||
function isImage(path: string) {
|
||||
const ext = path.split(".").splice(-1)[0].toLowerCase();
|
||||
@@ -46,8 +47,9 @@ function readDocument(w: LoadedEntry) {
|
||||
}
|
||||
export class DocumentHistoryModal extends Modal {
|
||||
plugin: ObsidianLiveSyncPlugin;
|
||||
core: LiveSyncBaseCore;
|
||||
get services() {
|
||||
return this.plugin.services;
|
||||
return this.core.services;
|
||||
}
|
||||
range!: HTMLInputElement;
|
||||
contentView!: HTMLDivElement;
|
||||
@@ -66,6 +68,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
|
||||
constructor(
|
||||
app: App,
|
||||
core: LiveSyncBaseCore,
|
||||
plugin: ObsidianLiveSyncPlugin,
|
||||
file: TFile | FilePathWithPrefix,
|
||||
id?: DocumentID,
|
||||
@@ -73,6 +76,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.core = core;
|
||||
this.file = file instanceof TFile ? getPathFromTFile(file) : file;
|
||||
this.id = id;
|
||||
this.initialRev = revision;
|
||||
@@ -88,7 +92,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
if (!this.id) {
|
||||
this.id = await this.services.path.path2id(this.file);
|
||||
}
|
||||
const db = this.plugin.localDatabase;
|
||||
const db = this.core.localDatabase;
|
||||
try {
|
||||
const w = await db.getRaw(this.id, { revs_info: true });
|
||||
this.revs_info = w._revs_info?.filter((e) => e?.status == "available") ?? [];
|
||||
@@ -137,7 +141,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
}
|
||||
|
||||
async showExactRev(rev: string) {
|
||||
const db = this.plugin.localDatabase;
|
||||
const db = this.core.localDatabase;
|
||||
const w = await db.getDBEntry(this.file, { rev: rev }, false, false, true);
|
||||
this.currentText = "";
|
||||
this.currentDeleted = false;
|
||||
@@ -292,7 +296,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
return;
|
||||
}
|
||||
const d = readContent(this.currentDoc);
|
||||
await this.plugin.storageAccess.writeHiddenFileAuto(pathToWrite, d);
|
||||
await this.core.storageAccess.writeHiddenFileAuto(pathToWrite, d);
|
||||
await focusFile(pathToWrite);
|
||||
this.close();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import { diff_match_patch } from "../../../deps.ts";
|
||||
import { DocumentHistoryModal } from "../DocumentHistory/DocumentHistoryModal.ts";
|
||||
import { isPlainText, stripAllPrefixes } from "../../../lib/src/string_and_binary/path.ts";
|
||||
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
|
||||
export let plugin: ObsidianLiveSyncPlugin;
|
||||
export let core: LiveSyncBaseCore;
|
||||
|
||||
let showDiffInfo = false;
|
||||
let showChunkCorrected = false;
|
||||
@@ -44,12 +46,12 @@
|
||||
let history = [] as HistoryData[];
|
||||
let loading = false;
|
||||
function getPath(entry: AnyEntry): FilePathWithPrefix {
|
||||
return plugin.services.path.getPath(entry);
|
||||
return core.services.path.getPath(entry);
|
||||
}
|
||||
|
||||
async function fetchChanges(): Promise<HistoryData[]> {
|
||||
try {
|
||||
const db = plugin.localDatabase;
|
||||
const db = core.localDatabase;
|
||||
let result = [] as typeof history;
|
||||
for await (const docA of db.findAllNormalDocs()) {
|
||||
if (docA.mtime < range_from_epoch) {
|
||||
@@ -112,11 +114,11 @@
|
||||
}
|
||||
if (rev == docA._rev) {
|
||||
if (checkStorageDiff) {
|
||||
const isExist = await plugin.storageAccess.isExistsIncludeHidden(
|
||||
const isExist = await core.storageAccess.isExistsIncludeHidden(
|
||||
stripAllPrefixes(getPath(docA))
|
||||
);
|
||||
if (isExist) {
|
||||
const data = await plugin.storageAccess.readHiddenFileBinary(
|
||||
const data = await core.storageAccess.readHiddenFileBinary(
|
||||
stripAllPrefixes(getPath(docA))
|
||||
);
|
||||
const d = readAsBlob(doc);
|
||||
@@ -189,7 +191,7 @@
|
||||
onDestroy(() => {});
|
||||
|
||||
function showHistory(file: string, rev: string) {
|
||||
new DocumentHistoryModal(plugin.app, plugin, file as unknown as FilePathWithPrefix, undefined, rev).open();
|
||||
new DocumentHistoryModal(plugin.app, plugin.core, plugin, file as unknown as FilePathWithPrefix, undefined, rev).open();
|
||||
}
|
||||
function openFile(file: string) {
|
||||
plugin.app.workspace.openLinkText(file, file);
|
||||
|
||||
@@ -11,6 +11,7 @@ export class GlobalHistoryView extends SvelteItemView {
|
||||
target: target,
|
||||
props: {
|
||||
plugin: this.plugin,
|
||||
core: this.plugin.core,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -254,8 +254,7 @@ export class ModuleLog extends AbstractObsidianModule {
|
||||
}
|
||||
// Case Sensitivity
|
||||
if (this.services.vault.shouldCheckCaseInsensitively()) {
|
||||
const f = this.core.storageAccess
|
||||
.getFiles()
|
||||
const f = (await this.core.storageAccess.getFiles())
|
||||
.map((e) => e.path)
|
||||
.filter((e) => e.toLowerCase() == thisFile.path.toLowerCase());
|
||||
if (f.length > 1) {
|
||||
@@ -405,8 +404,8 @@ export class ModuleLog extends AbstractObsidianModule {
|
||||
this.logHistory = this.statusDiv.createDiv({ cls: "livesync-status-loghistory" });
|
||||
eventHub.onEvent(EVENT_LAYOUT_READY, () => this.adjustStatusDivPosition());
|
||||
if (this.settings?.showStatusOnStatusbar) {
|
||||
this.statusBar = this.core.addStatusBarItem();
|
||||
this.statusBar.addClass("syncstatusbar");
|
||||
this.statusBar = this.services.API.addStatusBarItem();
|
||||
this.statusBar?.addClass("syncstatusbar");
|
||||
}
|
||||
this.adjustStatusDivPosition();
|
||||
return Promise.resolve(true);
|
||||
|
||||
@@ -34,7 +34,7 @@ export class ModuleObsidianDocumentHistory extends AbstractObsidianModule {
|
||||
}
|
||||
|
||||
showHistory(file: TFile | FilePathWithPrefix, id?: DocumentID) {
|
||||
new DocumentHistoryModal(this.app, this.plugin, file, id).open();
|
||||
new DocumentHistoryModal(this.app, this.core, this.plugin, file, id).open();
|
||||
}
|
||||
|
||||
async fileHistory() {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSe
|
||||
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "../../common/events.ts";
|
||||
import type { LiveSyncCore } from "@/main.ts";
|
||||
|
||||
export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
|
||||
settingTab!: ObsidianLiveSyncSettingTab;
|
||||
@@ -29,7 +30,7 @@ export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
|
||||
get appId() {
|
||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||
}
|
||||
override onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
||||
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,11 @@ export function createStub(name: string, key: string, value: string, panel: stri
|
||||
|
||||
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
plugin: ObsidianLiveSyncPlugin;
|
||||
get core() {
|
||||
return this.plugin.core;
|
||||
}
|
||||
get services() {
|
||||
return this.plugin.services;
|
||||
return this.core.services;
|
||||
}
|
||||
selectedScreen = "";
|
||||
|
||||
@@ -122,9 +125,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
continue;
|
||||
}
|
||||
//@ts-ignore
|
||||
this.plugin.settings[k] = this.editingSettings[k];
|
||||
this.core.settings[k] = this.editingSettings[k];
|
||||
//@ts-ignore
|
||||
this.initialSettings[k] = this.plugin.settings[k];
|
||||
this.initialSettings[k] = this.core.settings[k];
|
||||
}
|
||||
keys.forEach((e) => this.refreshSetting(e));
|
||||
}
|
||||
@@ -164,14 +167,14 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
continue;
|
||||
}
|
||||
//@ts-ignore
|
||||
this.plugin.settings[k] = this.editingSettings[k];
|
||||
this.core.settings[k] = this.editingSettings[k];
|
||||
//@ts-ignore
|
||||
this.initialSettings[k] = this.plugin.settings[k];
|
||||
this.initialSettings[k] = this.core.settings[k];
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
await this.plugin.saveSettings();
|
||||
await this.services.setting.saveSettingData();
|
||||
}
|
||||
|
||||
// if (runOnSaved) {
|
||||
@@ -231,7 +234,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
*/
|
||||
reloadAllSettings(skipUpdate: boolean = false) {
|
||||
const localSetting = this.reloadAllLocalSettings();
|
||||
this._editingSettings = { ...this.plugin.settings, ...localSetting };
|
||||
this._editingSettings = { ...this.core.settings, ...localSetting };
|
||||
this._editingSettings = { ...this.editingSettings, ...this.computeAllLocalSettings() };
|
||||
this.initialSettings = { ...this.editingSettings };
|
||||
if (!skipUpdate) this.requestUpdate();
|
||||
@@ -242,7 +245,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
*/
|
||||
refreshSetting(key: AllSettingItemKey) {
|
||||
const localSetting = this.reloadAllLocalSettings();
|
||||
if (key in this.plugin.settings) {
|
||||
if (key in this.core.settings) {
|
||||
if (key in localSetting) {
|
||||
//@ts-ignore
|
||||
this.initialSettings[key] = localSetting[key];
|
||||
@@ -250,7 +253,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
this.editingSettings[key] = localSetting[key];
|
||||
} else {
|
||||
//@ts-ignore
|
||||
this.initialSettings[key] = this.plugin.settings[key];
|
||||
this.initialSettings[key] = this.core.settings[key];
|
||||
//@ts-ignore
|
||||
this.editingSettings[key] = this.initialSettings[key];
|
||||
}
|
||||
@@ -319,7 +322,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
|
||||
closeSetting() {
|
||||
// @ts-ignore
|
||||
this.plugin.app.setting.close();
|
||||
this.core.app.setting.close();
|
||||
}
|
||||
|
||||
handleElement(element: HTMLElement, func: OnUpdateFunc) {
|
||||
@@ -381,7 +384,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
|
||||
requestReload() {
|
||||
if (this.isShown) {
|
||||
const newConf = this.plugin.settings;
|
||||
const newConf = this.core.settings;
|
||||
const keys = Object.keys(newConf) as (keyof ObsidianLiveSyncSettings)[];
|
||||
let hasLoaded = false;
|
||||
for (const k of keys) {
|
||||
@@ -389,7 +392,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
// Something has changed
|
||||
if (this.isDirty(k as AllSettingItemKey)) {
|
||||
// And modified.
|
||||
this.plugin.confirm.askInPopup(
|
||||
this.core.confirm.askInPopup(
|
||||
`config-reloaded-${k}`,
|
||||
$msg("obsidianLiveSyncSettingTab.msgSettingModified", {
|
||||
setting: getConfName(k as AllSettingItemKey),
|
||||
@@ -457,7 +460,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
this.editingSettings.syncOnStart = false;
|
||||
this.editingSettings.syncOnFileOpen = false;
|
||||
this.editingSettings.syncAfterMerge = false;
|
||||
this.plugin.replicator.closeReplication();
|
||||
this.core.replicator.closeReplication();
|
||||
await this.saveAllDirtySettings();
|
||||
this.containerEl.addClass("isWizard");
|
||||
this.inWizard = true;
|
||||
@@ -514,8 +517,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
if (this.isConfiguredAs("syncOnStart", true)) return true;
|
||||
if (this.isConfiguredAs("syncAfterMerge", true)) return true;
|
||||
if (this.isConfiguredAs("syncOnFileOpen", true)) return true;
|
||||
if (this.plugin?.replicator?.syncStatus == "CONNECTED") return true;
|
||||
if (this.plugin?.replicator?.syncStatus == "PAUSED") return true;
|
||||
if (this.core?.replicator?.syncStatus == "CONNECTED") return true;
|
||||
if (this.core?.replicator?.syncStatus == "PAUSED") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -605,7 +608,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
await this.saveAllDirtySettings();
|
||||
this.closeSetting();
|
||||
await delay(2000);
|
||||
await this.plugin.rebuilder.$performRebuildDB(method);
|
||||
await this.core.rebuilder.$performRebuildDB(method);
|
||||
};
|
||||
async confirmRebuild() {
|
||||
if (!(await this.isPassphraseValid())) {
|
||||
@@ -633,7 +636,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
if (result == OPTION_FETCH) {
|
||||
if (!(await this.checkWorkingPassphrase())) {
|
||||
if (
|
||||
(await this.plugin.confirm.askYesNoDialog($msg("obsidianLiveSyncSettingTab.msgAreYouSureProceed"), {
|
||||
(await this.core.confirm.askYesNoDialog($msg("obsidianLiveSyncSettingTab.msgAreYouSureProceed"), {
|
||||
defaultOption: "No",
|
||||
})) != "yes"
|
||||
)
|
||||
@@ -646,16 +649,16 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
await this.saveAllDirtySettings();
|
||||
await this.applyAllSettings();
|
||||
if (result == OPTION_FETCH) {
|
||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
||||
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
||||
this.services.appLifecycle.scheduleRestart();
|
||||
this.closeSetting();
|
||||
// await rebuildDB("localOnly");
|
||||
} else if (result == OPTION_REBUILD_BOTH) {
|
||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
||||
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
||||
this.services.appLifecycle.scheduleRestart();
|
||||
this.closeSetting();
|
||||
} else if (result == OPTION_ONLY_SETTING) {
|
||||
await this.plugin.saveSettings();
|
||||
await this.services.setting.saveSettingData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,7 +871,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
}
|
||||
|
||||
getMinioJournalSyncClient() {
|
||||
return new JournalSyncMinio(this.plugin.settings, this.plugin.simpleStore, this.plugin);
|
||||
return new JournalSyncMinio(this.core.settings, this.core.simpleStore, this.core);
|
||||
}
|
||||
async resetRemoteBucket() {
|
||||
const minioJournal = this.getMinioJournalSyncClient();
|
||||
|
||||
@@ -165,7 +165,7 @@ export function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement,
|
||||
}
|
||||
const obsidianInfo = {
|
||||
navigator: navigator.userAgent,
|
||||
fileSystem: this.plugin.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
|
||||
fileSystem: this.core.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
|
||||
};
|
||||
const msgConfig = `# ---- Obsidian info ----
|
||||
${stringifyYaml(obsidianInfo)}
|
||||
@@ -221,7 +221,7 @@ ${stringifyYaml({
|
||||
|
||||
void addPanel(paneEl, "Recovery and Repair").then((paneEl) => {
|
||||
const addResult = async (path: string, file: FilePathWithPrefix | false, fileOnDB: LoadedEntry | false) => {
|
||||
const storageFileStat = file ? await this.plugin.storageAccess.statHidden(file) : null;
|
||||
const storageFileStat = file ? await this.core.storageAccess.statHidden(file) : null;
|
||||
resultArea.appendChild(
|
||||
this.createEl(resultArea, "div", {}, (el) => {
|
||||
el.appendChild(this.createEl(el, "h6", { text: path }));
|
||||
@@ -256,7 +256,7 @@ ${stringifyYaml({
|
||||
this.createEl(el, "button", { text: "Storage -> Database" }, (buttonEl) => {
|
||||
buttonEl.onClickEvent(async () => {
|
||||
if (file.startsWith(".")) {
|
||||
const addOn = this.plugin.getAddOn<HiddenFileSync>(HiddenFileSync.name);
|
||||
const addOn = this.core.getAddOn<HiddenFileSync>(HiddenFileSync.name);
|
||||
if (addOn) {
|
||||
const file = (await addOn.scanInternalFiles()).find((e) => e.path == path);
|
||||
if (!file) {
|
||||
@@ -275,7 +275,7 @@ ${stringifyYaml({
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(await this.plugin.fileHandler.storeFileToDB(file as FilePath, true))) {
|
||||
if (!(await this.core.fileHandler.storeFileToDB(file as FilePath, true))) {
|
||||
Logger(
|
||||
`Failed to store the file to the database: ${file}`,
|
||||
LOG_LEVEL_NOTICE
|
||||
@@ -293,7 +293,7 @@ ${stringifyYaml({
|
||||
this.createEl(el, "button", { text: "Database -> Storage" }, (buttonEl) => {
|
||||
buttonEl.onClickEvent(async () => {
|
||||
if (fileOnDB.path.startsWith(ICHeader)) {
|
||||
const addOn = this.plugin.getAddOn<HiddenFileSync>(HiddenFileSync.name);
|
||||
const addOn = this.core.getAddOn<HiddenFileSync>(HiddenFileSync.name);
|
||||
if (addOn) {
|
||||
if (
|
||||
!(await addOn.extractInternalFileFromDatabase(path as FilePath, true))
|
||||
@@ -307,7 +307,7 @@ ${stringifyYaml({
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
!(await this.plugin.fileHandler.dbToStorage(
|
||||
!(await this.core.fileHandler.dbToStorage(
|
||||
fileOnDB as MetaEntry,
|
||||
null,
|
||||
true
|
||||
@@ -332,7 +332,7 @@ ${stringifyYaml({
|
||||
|
||||
const checkBetweenStorageAndDatabase = async (file: FilePathWithPrefix, fileOnDB: LoadedEntry) => {
|
||||
const dataContent = readAsBlob(fileOnDB);
|
||||
const content = createBlob(await this.plugin.storageAccess.readHiddenFileBinary(file));
|
||||
const content = createBlob(await this.core.storageAccess.readHiddenFileBinary(file));
|
||||
if (await isDocContentSame(content, dataContent)) {
|
||||
Logger(`Compare: SAME: ${file}`);
|
||||
} else {
|
||||
@@ -348,7 +348,7 @@ ${stringifyYaml({
|
||||
.setButtonText("Recreate all")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
await this.plugin.fileHandler.createAllChunks(true);
|
||||
await this.core.fileHandler.createAllChunks(true);
|
||||
})
|
||||
);
|
||||
new Setting(paneEl)
|
||||
@@ -377,21 +377,21 @@ ${stringifyYaml({
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
Logger("Start verifying all files", LOG_LEVEL_NOTICE, "verify");
|
||||
const ignorePatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesIgnorePatterns");
|
||||
const targetPatterns = getFileRegExp(this.plugin.settings, "syncInternalFilesTargetPatterns");
|
||||
this.plugin.localDatabase.clearCaches();
|
||||
const ignorePatterns = getFileRegExp(this.core.settings, "syncInternalFilesIgnorePatterns");
|
||||
const targetPatterns = getFileRegExp(this.core.settings, "syncInternalFilesTargetPatterns");
|
||||
this.core.localDatabase.clearCaches();
|
||||
Logger("Start verifying all files", LOG_LEVEL_NOTICE, "verify");
|
||||
const files = this.plugin.settings.syncInternalFiles
|
||||
? await this.plugin.storageAccess.getFilesIncludeHidden("/", targetPatterns, ignorePatterns)
|
||||
: await this.plugin.storageAccess.getFileNames();
|
||||
const files = this.core.settings.syncInternalFiles
|
||||
? await this.core.storageAccess.getFilesIncludeHidden("/", targetPatterns, ignorePatterns)
|
||||
: await this.core.storageAccess.getFileNames();
|
||||
const documents = [] as FilePath[];
|
||||
|
||||
const adn = this.plugin.localDatabase.findAllDocs();
|
||||
const adn = this.core.localDatabase.findAllDocs();
|
||||
for await (const i of adn) {
|
||||
const path = this.services.path.getPath(i);
|
||||
if (path.startsWith(ICXHeader)) continue;
|
||||
if (path.startsWith(PSCHeader)) continue;
|
||||
if (!this.plugin.settings.syncInternalFiles && path.startsWith(ICHeader)) continue;
|
||||
if (!this.core.settings.syncInternalFiles && path.startsWith(ICHeader)) continue;
|
||||
documents.push(stripAllPrefixes(path));
|
||||
}
|
||||
const allPaths = [...new Set([...documents, ...files])];
|
||||
@@ -411,8 +411,8 @@ ${stringifyYaml({
|
||||
if (shouldBeIgnored(path)) {
|
||||
return incProc();
|
||||
}
|
||||
const stat = (await this.plugin.storageAccess.isExistsIncludeHidden(path))
|
||||
? await this.plugin.storageAccess.statHidden(path)
|
||||
const stat = (await this.core.storageAccess.isExistsIncludeHidden(path))
|
||||
? await this.core.storageAccess.statHidden(path)
|
||||
: false;
|
||||
const fileOnStorage = stat != null ? stat : false;
|
||||
if (!(await this.services.vault.isTargetFile(path))) return incProc();
|
||||
@@ -422,7 +422,7 @@ ${stringifyYaml({
|
||||
try {
|
||||
const isHiddenFile = path.startsWith(".");
|
||||
const dbPath = isHiddenFile ? addPrefix(path, ICHeader) : path;
|
||||
const fileOnDB = await this.plugin.localDatabase.getDBEntry(dbPath);
|
||||
const fileOnDB = await this.core.localDatabase.getDBEntry(dbPath);
|
||||
if (fileOnDB && this.services.vault.isFileSizeTooLarge(fileOnDB.size))
|
||||
return incProc();
|
||||
|
||||
@@ -466,10 +466,10 @@ ${stringifyYaml({
|
||||
.setDisabled(false)
|
||||
.setWarning()
|
||||
.onClick(async () => {
|
||||
for await (const docName of this.plugin.localDatabase.findAllDocNames()) {
|
||||
for await (const docName of this.core.localDatabase.findAllDocNames()) {
|
||||
if (!docName.startsWith("f:")) {
|
||||
const idEncoded = await this.services.path.path2id(docName as FilePathWithPrefix);
|
||||
const doc = await this.plugin.localDatabase.getRaw(docName as DocumentID);
|
||||
const doc = await this.core.localDatabase.getRaw(docName as DocumentID);
|
||||
if (!doc) continue;
|
||||
if (doc.type != "newnote" && doc.type != "plain") {
|
||||
continue;
|
||||
@@ -482,7 +482,7 @@ ${stringifyYaml({
|
||||
// @ts-ignore
|
||||
delete newDoc._rev;
|
||||
try {
|
||||
const obfuscatedDoc = await this.plugin.localDatabase.getRaw(idEncoded, {
|
||||
const obfuscatedDoc = await this.core.localDatabase.getRaw(idEncoded, {
|
||||
revs_info: true,
|
||||
});
|
||||
// Unfortunately we have to delete one of them.
|
||||
@@ -499,14 +499,14 @@ ${stringifyYaml({
|
||||
-32
|
||||
);
|
||||
}
|
||||
const ret = await this.plugin.localDatabase.putRaw(newDoc, { force: true });
|
||||
const ret = await this.core.localDatabase.putRaw(newDoc, { force: true });
|
||||
if (ret.ok) {
|
||||
Logger(
|
||||
`${docName} has been converted as conflicted document`,
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
doc._deleted = true;
|
||||
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
||||
if ((await this.core.localDatabase.putRaw(doc)).ok) {
|
||||
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
|
||||
}
|
||||
await this.services.conflict.queueCheckForIfOpen(docName as FilePathWithPrefix);
|
||||
@@ -517,10 +517,10 @@ ${stringifyYaml({
|
||||
} catch (ex: any) {
|
||||
if (ex?.status == 404) {
|
||||
// We can perform this safely
|
||||
if ((await this.plugin.localDatabase.putRaw(newDoc)).ok) {
|
||||
if ((await this.core.localDatabase.putRaw(newDoc)).ok) {
|
||||
Logger(`${docName} has been converted`, LOG_LEVEL_NOTICE);
|
||||
doc._deleted = true;
|
||||
if ((await this.plugin.localDatabase.putRaw(doc)).ok) {
|
||||
if ((await this.core.localDatabase.putRaw(doc)).ok) {
|
||||
Logger(`Old ${docName} has been deleted`, LOG_LEVEL_NOTICE);
|
||||
}
|
||||
}
|
||||
@@ -555,7 +555,7 @@ ${stringifyYaml({
|
||||
.setWarning()
|
||||
.onClick(async () => {
|
||||
Logger(`Deleting customization sync data`, LOG_LEVEL_NOTICE);
|
||||
const entriesToDelete = await this.plugin.localDatabase.allDocsRaw({
|
||||
const entriesToDelete = await this.core.localDatabase.allDocsRaw({
|
||||
startkey: "ix:",
|
||||
endkey: "ix:\u{10ffff}",
|
||||
include_docs: true,
|
||||
@@ -564,7 +564,7 @@ ${stringifyYaml({
|
||||
...e.doc,
|
||||
_deleted: true,
|
||||
}));
|
||||
const r = await this.plugin.localDatabase.bulkDocsRaw(newData as any[]);
|
||||
const r = await this.core.localDatabase.bulkDocsRaw(newData as any[]);
|
||||
// Do not care about the result.
|
||||
Logger(
|
||||
`${r.length} items have been removed, to confirm how many items are left, please perform it again.`,
|
||||
|
||||
@@ -11,8 +11,8 @@ export function paneMaintenance(
|
||||
paneEl: HTMLElement,
|
||||
{ addPanel }: PageFunctions
|
||||
): void {
|
||||
const isRemoteLockedAndDeviceNotAccepted = () => this.plugin?.replicator?.remoteLockedAndDeviceNotAccepted;
|
||||
const isRemoteLocked = () => this.plugin?.replicator?.remoteLocked;
|
||||
const isRemoteLockedAndDeviceNotAccepted = () => this.core?.replicator?.remoteLockedAndDeviceNotAccepted;
|
||||
const isRemoteLocked = () => this.core?.replicator?.remoteLocked;
|
||||
// if (this.plugin?.replicator?.remoteLockedAndDeviceNotAccepted) {
|
||||
this.createEl(
|
||||
paneEl,
|
||||
@@ -92,7 +92,7 @@ export function paneMaintenance(
|
||||
.setDisabled(false)
|
||||
.setWarning()
|
||||
.onClick(async () => {
|
||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
|
||||
await this.core.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
|
||||
this.services.appLifecycle.performRestart();
|
||||
})
|
||||
);
|
||||
@@ -108,7 +108,7 @@ export function paneMaintenance(
|
||||
.setCta()
|
||||
.setDisabled(false)
|
||||
.onClick(async () => {
|
||||
await this.plugin.storageAccess.writeFileAuto(FlagFilesHumanReadable.FETCH_ALL, "");
|
||||
await this.core.storageAccess.writeFileAuto(FlagFilesHumanReadable.FETCH_ALL, "");
|
||||
this.services.appLifecycle.performRestart();
|
||||
})
|
||||
);
|
||||
@@ -121,7 +121,7 @@ export function paneMaintenance(
|
||||
.setCta()
|
||||
.setDisabled(false)
|
||||
.onClick(async () => {
|
||||
await this.plugin.storageAccess.writeFileAuto(FlagFilesHumanReadable.REBUILD_ALL, "");
|
||||
await this.core.storageAccess.writeFileAuto(FlagFilesHumanReadable.REBUILD_ALL, "");
|
||||
this.services.appLifecycle.performRestart();
|
||||
})
|
||||
);
|
||||
@@ -137,8 +137,8 @@ export function paneMaintenance(
|
||||
.setWarning()
|
||||
.setDisabled(false)
|
||||
.onClick(async () => {
|
||||
if (this.plugin.replicator instanceof LiveSyncCouchDBReplicator) {
|
||||
await this.plugin.replicator.sendChunks(this.plugin.settings, undefined, true, 0);
|
||||
if (this.core.replicator instanceof LiveSyncCouchDBReplicator) {
|
||||
await this.core.replicator.sendChunks(this.core.settings, undefined, true, 0);
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -299,7 +299,7 @@ export function paneMaintenance(
|
||||
.setButtonText("Perform")
|
||||
.setDisabled(false)
|
||||
.onClick(async () => {
|
||||
const replicator = this.plugin.replicator as LiveSyncCouchDBReplicator;
|
||||
const replicator = this.core.replicator as LiveSyncCouchDBReplicator;
|
||||
Logger(`Cleanup has been began`, LOG_LEVEL_NOTICE, "compaction");
|
||||
if (await replicator.compactRemote(this.editingSettings)) {
|
||||
Logger(`Cleanup has been completed!`, LOG_LEVEL_NOTICE, "compaction");
|
||||
|
||||
@@ -31,7 +31,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
|
||||
void addPanel(paneEl, "Compatibility (Database structure)").then((paneEl) => {
|
||||
const migrateAllToIndexedDB = async () => {
|
||||
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName + ExtraSuffixIndexedDB;
|
||||
const dbToName = this.core.localDatabase.dbname + SuffixDatabaseName + ExtraSuffixIndexedDB;
|
||||
const options = {
|
||||
adapter: "indexeddb",
|
||||
//@ts-ignore :missing def
|
||||
@@ -42,18 +42,19 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
const openTo = () => {
|
||||
return new PouchDB(dbToName, options);
|
||||
};
|
||||
if (await migrateDatabases("to IndexedDB", this.plugin.localDatabase.localDatabase, openTo)) {
|
||||
if (await migrateDatabases("to IndexedDB", this.core.localDatabase.localDatabase, openTo)) {
|
||||
Logger(
|
||||
"Migration to IndexedDB completed. Obsidian will be restarted with new configuration immediately.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
this.plugin.settings.useIndexedDBAdapter = true;
|
||||
await this.services.setting.saveSettingData();
|
||||
// this.plugin.settings.useIndexedDBAdapter = true;
|
||||
// await this.services.setting.saveSettingData();
|
||||
await this.core.services.setting.applyPartial({ useIndexedDBAdapter: true }, true);
|
||||
this.services.appLifecycle.performRestart();
|
||||
}
|
||||
};
|
||||
const migrateAllToIDB = async () => {
|
||||
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName;
|
||||
const dbToName = this.core.localDatabase.dbname + SuffixDatabaseName;
|
||||
const options = {
|
||||
adapter: "idb",
|
||||
auto_compaction: false,
|
||||
@@ -62,13 +63,14 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
const openTo = () => {
|
||||
return new PouchDB(dbToName, options);
|
||||
};
|
||||
if (await migrateDatabases("to IDB", this.plugin.localDatabase.localDatabase, openTo)) {
|
||||
if (await migrateDatabases("to IDB", this.core.localDatabase.localDatabase, openTo)) {
|
||||
Logger(
|
||||
"Migration to IDB completed. Obsidian will be restarted with new configuration immediately.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
this.plugin.settings.useIndexedDBAdapter = false;
|
||||
await this.services.setting.saveSettingData();
|
||||
await this.core.services.setting.applyPartial({ useIndexedDBAdapter: false }, true);
|
||||
// this.core.settings.useIndexedDBAdapter = false;
|
||||
// await this.services.setting.saveSettingData();
|
||||
this.services.appLifecycle.performRestart();
|
||||
}
|
||||
};
|
||||
@@ -151,7 +153,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
} as Record<HashAlgorithm, string>,
|
||||
});
|
||||
this.addOnSaved("hashAlg", async () => {
|
||||
await this.plugin.localDatabase._prepareHashFunctions();
|
||||
await this.core.localDatabase._prepareHashFunctions();
|
||||
});
|
||||
});
|
||||
void addPanel(paneEl, "Edge case addressing (Behaviour)").then((paneEl) => {
|
||||
@@ -215,7 +217,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
|
||||
this.addOnSaved("maxMTimeForReflectEvents", async (key) => {
|
||||
const buttons = ["Restart Now", "Later"] as const;
|
||||
const reboot = await this.plugin.confirm.askSelectStringDialogue(
|
||||
const reboot = await this.core.confirm.askSelectStringDialogue(
|
||||
"Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?",
|
||||
buttons,
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ export function paneRemoteConfig(
|
||||
.addButton((button) =>
|
||||
button
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onlyE2EEConfiguration(UserMode.Update, originalSettings);
|
||||
updateE2EESummary();
|
||||
@@ -79,7 +79,7 @@ export function paneRemoteConfig(
|
||||
.addButton((button) =>
|
||||
button
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onConfigureManually(originalSettings, UserMode.Update);
|
||||
updateE2EESummary();
|
||||
@@ -101,7 +101,7 @@ export function paneRemoteConfig(
|
||||
.setButtonText("Change Remote and Setup")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onSelectServer(originalSettings, UserMode.Update);
|
||||
})
|
||||
@@ -127,7 +127,7 @@ export function paneRemoteConfig(
|
||||
.setButtonText("Configure")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onCouchDBManualSetup(
|
||||
UserMode.Update,
|
||||
@@ -162,7 +162,7 @@ export function paneRemoteConfig(
|
||||
.setButtonText("Configure")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onBucketManualSetup(
|
||||
UserMode.Update,
|
||||
@@ -202,7 +202,7 @@ export function paneRemoteConfig(
|
||||
.setButtonText("Configure")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
const originalSettings = getSettingsFromEditingSettings(this.editingSettings);
|
||||
await setupManager.onP2PManualSetup(
|
||||
UserMode.Update,
|
||||
|
||||
@@ -35,7 +35,7 @@ export function paneSetup(
|
||||
.setDesc($msg("Rerun the onboarding wizard to set up Self-hosted LiveSync again."))
|
||||
.addButton((text) => {
|
||||
text.setButtonText($msg("Rerun Wizard")).onClick(async () => {
|
||||
const setupManager = this.plugin.getModule(SetupManager);
|
||||
const setupManager = this.core.getModule(SetupManager);
|
||||
await setupManager.onOnboard(UserMode.ExistingUser);
|
||||
// await this.plugin.moduleSetupObsidian.onBoardingWizard(true);
|
||||
});
|
||||
@@ -86,14 +86,14 @@ export function paneSetup(
|
||||
text.setButtonText($msg("obsidianLiveSyncSettingTab.btnDiscard"))
|
||||
.onClick(async () => {
|
||||
if (
|
||||
(await this.plugin.confirm.askYesNoDialog(
|
||||
(await this.core.confirm.askYesNoDialog(
|
||||
$msg("obsidianLiveSyncSettingTab.msgDiscardConfirmation"),
|
||||
{ defaultOption: "No" }
|
||||
)) == "yes"
|
||||
) {
|
||||
this.editingSettings = { ...this.editingSettings, ...DEFAULT_SETTINGS };
|
||||
await this.saveAllDirtySettings();
|
||||
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
||||
this.core.settings = { ...DEFAULT_SETTINGS };
|
||||
await this.services.setting.saveSettingData();
|
||||
await this.services.database.resetDatabase();
|
||||
// await this.plugin.initializeDatabase();
|
||||
|
||||
@@ -109,7 +109,7 @@ export function paneSyncSettings(
|
||||
await this.rebuildDB("localOnly");
|
||||
// this.resetEditingSettings();
|
||||
if (
|
||||
(await this.plugin.confirm.askYesNoDialog(
|
||||
(await this.core.confirm.askYesNoDialog(
|
||||
$msg("obsidianLiveSyncSettingTab.msgGenerateSetupURI"),
|
||||
{
|
||||
defaultOption: "Yes",
|
||||
|
||||
Reference in New Issue
Block a user