mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-13 09:45:56 +00:00
disenchanting and dispelling from the nightmarish implicit something
Indeed, even though if this changeset is mostly another nightmare. It might be in beta for a while.
This commit is contained in:
@@ -1,11 +1,6 @@
|
|||||||
import { type PluginManifest, TFile } from "../deps.ts";
|
import { type PluginManifest, TFile } from "../deps.ts";
|
||||||
import {
|
import { type DatabaseEntry, type EntryBody, type FilePath } from "../lib/src/common/types.ts";
|
||||||
type DatabaseEntry,
|
export type { CacheData, FileEventItem } from "../lib/src/common/types.ts";
|
||||||
type EntryBody,
|
|
||||||
type FilePath,
|
|
||||||
type UXFileInfoStub,
|
|
||||||
type UXInternalFileInfoStub,
|
|
||||||
} from "../lib/src/common/types.ts";
|
|
||||||
|
|
||||||
export interface PluginDataEntry extends DatabaseEntry {
|
export interface PluginDataEntry extends DatabaseEntry {
|
||||||
deviceVaultName: string;
|
deviceVaultName: string;
|
||||||
@@ -54,23 +49,6 @@ export type queueItem = {
|
|||||||
warned?: boolean;
|
warned?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CacheData = string | ArrayBuffer;
|
|
||||||
export type FileEventType = "CREATE" | "DELETE" | "CHANGED" | "INTERNAL";
|
|
||||||
export type FileEventArgs = {
|
|
||||||
file: UXFileInfoStub | UXInternalFileInfoStub;
|
|
||||||
cache?: CacheData;
|
|
||||||
oldPath?: string;
|
|
||||||
ctx?: any;
|
|
||||||
};
|
|
||||||
export type FileEventItem = {
|
|
||||||
type: FileEventType;
|
|
||||||
args: FileEventArgs;
|
|
||||||
key: string;
|
|
||||||
skipBatchWait?: boolean;
|
|
||||||
cancelled?: boolean;
|
|
||||||
batched?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hidden items (Now means `chunk`)
|
// Hidden items (Now means `chunk`)
|
||||||
export const CHeader = "h:";
|
export const CHeader = "h:";
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export class PeriodicProcessor {
|
|||||||
() =>
|
() =>
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
await this.process();
|
await this.process();
|
||||||
if (this._plugin.$$isUnloaded()) {
|
if (this._plugin.services?.appLifecycle?.hasUnloaded()) {
|
||||||
this.disable();
|
this.disable();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -68,14 +68,23 @@ import type ObsidianLiveSyncPlugin from "../../main.ts";
|
|||||||
import { base64ToArrayBuffer, base64ToString } from "octagonal-wheels/binary/base64";
|
import { base64ToArrayBuffer, base64ToString } from "octagonal-wheels/binary/base64";
|
||||||
import { ConflictResolveModal } from "../../modules/features/InteractiveConflictResolving/ConflictResolveModal.ts";
|
import { ConflictResolveModal } from "../../modules/features/InteractiveConflictResolving/ConflictResolveModal.ts";
|
||||||
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
||||||
import type { IObsidianModule } from "../../modules/AbstractObsidianModule.ts";
|
|
||||||
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "../../common/events.ts";
|
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "../../common/events.ts";
|
||||||
import { PluginDialogModal } from "./PluginDialogModal.ts";
|
import { PluginDialogModal } from "./PluginDialogModal.ts";
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
const d = "\u200b";
|
const d = "\u200b";
|
||||||
const d2 = "\n";
|
const d2 = "\n";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface OPTIONAL_SYNC_FEATURES {
|
||||||
|
DISABLE: "DISABLE";
|
||||||
|
CUSTOMIZE: "CUSTOMIZE";
|
||||||
|
DISABLE_CUSTOM: "DISABLE_CUSTOM";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function serialize(data: PluginDataEx): string {
|
function serialize(data: PluginDataEx): string {
|
||||||
// For higher performance, create custom plug-in data strings.
|
// For higher performance, create custom plug-in data strings.
|
||||||
// Self-hosted LiveSync uses `\n` to split chunks. Therefore, grouping together those with similar entropy would work nicely.
|
// Self-hosted LiveSync uses `\n` to split chunks. Therefore, grouping together those with similar entropy would work nicely.
|
||||||
@@ -384,7 +393,7 @@ export type PluginDataEx = {
|
|||||||
mtime: number;
|
mtime: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
export class ConfigSync extends LiveSyncCommands {
|
||||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
pluginScanningCount.onChanged((e) => {
|
pluginScanningCount.onChanged((e) => {
|
||||||
@@ -482,7 +491,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
// Idea non-filter option?
|
// Idea non-filter option?
|
||||||
return this.getFileCategory(filePath) != "";
|
return this.getFileCategory(filePath) != "";
|
||||||
}
|
}
|
||||||
async $everyOnDatabaseInitialized(showNotice: boolean) {
|
private async _everyOnDatabaseInitialized(showNotice: boolean) {
|
||||||
if (!this._isThisModuleEnabled()) return true;
|
if (!this._isThisModuleEnabled()) return true;
|
||||||
try {
|
try {
|
||||||
this._log("Scanning customizations...");
|
this._log("Scanning customizations...");
|
||||||
@@ -494,7 +503,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async $everyBeforeReplicate(showNotice: boolean) {
|
async _everyBeforeReplicate(showNotice: boolean) {
|
||||||
if (!this._isThisModuleEnabled()) return true;
|
if (!this._isThisModuleEnabled()) return true;
|
||||||
if (this.settings.autoSweepPlugins) {
|
if (this.settings.autoSweepPlugins) {
|
||||||
await this.scanAllConfigFiles(showNotice);
|
await this.scanAllConfigFiles(showNotice);
|
||||||
@@ -502,7 +511,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async $everyOnResumeProcess(): Promise<boolean> {
|
async _everyOnResumeProcess(): Promise<boolean> {
|
||||||
if (!this._isThisModuleEnabled()) return true;
|
if (!this._isThisModuleEnabled()) return true;
|
||||||
if (this._isMainSuspended()) {
|
if (this._isMainSuspended()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -517,7 +526,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
_everyAfterResumeProcess(): Promise<boolean> {
|
||||||
const q = activeDocument.querySelector(`.livesync-ribbon-showcustom`);
|
const q = activeDocument.querySelector(`.livesync-ribbon-showcustom`);
|
||||||
q?.toggleClass("sls-hidden", !this._isThisModuleEnabled());
|
q?.toggleClass("sls-hidden", !this._isThisModuleEnabled());
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
@@ -633,7 +642,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
).startPipeline();
|
).startPipeline();
|
||||||
|
|
||||||
filenameToUnifiedKey(path: string, termOverRide?: string) {
|
filenameToUnifiedKey(path: string, termOverRide?: string) {
|
||||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
const term = termOverRide || this.services.setting.getDeviceAndVaultName();
|
||||||
const category = this.getFileCategory(path);
|
const category = this.getFileCategory(path);
|
||||||
const name =
|
const name =
|
||||||
category == "CONFIG" || category == "SNIPPET"
|
category == "CONFIG" || category == "SNIPPET"
|
||||||
@@ -645,7 +654,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filenameWithUnifiedKey(path: string, termOverRide?: string) {
|
filenameWithUnifiedKey(path: string, termOverRide?: string) {
|
||||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
const term = termOverRide || this.services.setting.getDeviceAndVaultName();
|
||||||
const category = this.getFileCategory(path);
|
const category = this.getFileCategory(path);
|
||||||
const name =
|
const name =
|
||||||
category == "CONFIG" || category == "SNIPPET" ? path.split("/").slice(-1)[0] : path.split("/").slice(-2)[0];
|
category == "CONFIG" || category == "SNIPPET" ? path.split("/").slice(-1)[0] : path.split("/").slice(-2)[0];
|
||||||
@@ -654,7 +663,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unifiedKeyPrefixOfTerminal(termOverRide?: string) {
|
unifiedKeyPrefixOfTerminal(termOverRide?: string) {
|
||||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
const term = termOverRide || this.services.setting.getDeviceAndVaultName();
|
||||||
return `${ICXHeader}${term}/` as FilePathWithPrefix;
|
return `${ICXHeader}${term}/` as FilePathWithPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,7 +840,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
const v2Path = (prefixPath + relativeFilename) as FilePathWithPrefix;
|
const v2Path = (prefixPath + relativeFilename) as FilePathWithPrefix;
|
||||||
// console.warn(`Migrating ${v1Path} / ${relativeFilename} to ${v2Path}`);
|
// console.warn(`Migrating ${v1Path} / ${relativeFilename} to ${v2Path}`);
|
||||||
this._log(`Migrating ${v1Path} / ${relativeFilename} to ${v2Path}`, LOG_LEVEL_VERBOSE);
|
this._log(`Migrating ${v1Path} / ${relativeFilename} to ${v2Path}`, LOG_LEVEL_VERBOSE);
|
||||||
const newId = await this.plugin.$$path2id(v2Path);
|
const newId = await this.services.path.path2id(v2Path);
|
||||||
// const buf =
|
// const buf =
|
||||||
|
|
||||||
const data = createBlob([DUMMY_HEAD, DUMMY_END, ...getDocDataAsArray(f.data)]);
|
const data = createBlob([DUMMY_HEAD, DUMMY_END, ...getDocDataAsArray(f.data)]);
|
||||||
@@ -999,7 +1008,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
await this.plugin.storageAccess.ensureDir(path);
|
await this.plugin.storageAccess.ensureDir(path);
|
||||||
// If the content has applied, modified time will be updated to the current time.
|
// If the content has applied, modified time will be updated to the current time.
|
||||||
await this.plugin.storageAccess.writeHiddenFileAuto(path, content);
|
await this.plugin.storageAccess.writeHiddenFileAuto(path, content);
|
||||||
await this.storeCustomisationFileV2(path, this.plugin.$$getDeviceAndVaultName());
|
await this.storeCustomisationFileV2(path, this.services.setting.getDeviceAndVaultName());
|
||||||
} else {
|
} else {
|
||||||
const files = data.files;
|
const files = data.files;
|
||||||
for (const f of files) {
|
for (const f of files) {
|
||||||
@@ -1042,7 +1051,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
await this.plugin.storageAccess.writeHiddenFileAuto(path, content, stat);
|
await this.plugin.storageAccess.writeHiddenFileAuto(path, content, stat);
|
||||||
}
|
}
|
||||||
this._log(`Applied ${f.filename} of ${data.displayName || data.name}..`);
|
this._log(`Applied ${f.filename} of ${data.displayName || data.name}..`);
|
||||||
await this.storeCustomisationFileV2(path, this.plugin.$$getDeviceAndVaultName());
|
await this.storeCustomisationFileV2(path, this.services.setting.getDeviceAndVaultName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -1114,7 +1123,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (data.category == "CONFIG") {
|
} else if (data.category == "CONFIG") {
|
||||||
this.plugin.$$askReload();
|
this.services.appLifecycle.askRestart();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -1157,8 +1166,8 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async $anyModuleParsedReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
async _anyModuleParsedReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
||||||
if (!docs._id.startsWith(ICXHeader)) return undefined;
|
if (!docs._id.startsWith(ICXHeader)) return false;
|
||||||
if (this._isThisModuleEnabled()) {
|
if (this._isThisModuleEnabled()) {
|
||||||
await this.updatePluginList(
|
await this.updatePluginList(
|
||||||
false,
|
false,
|
||||||
@@ -1205,7 +1214,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async $everyRealizeSettingSyncMode(): Promise<boolean> {
|
async _everyRealizeSettingSyncMode(): Promise<boolean> {
|
||||||
this.periodicPluginSweepProcessor?.disable();
|
this.periodicPluginSweepProcessor?.disable();
|
||||||
if (!this._isMainReady) return true;
|
if (!this._isMainReady) return true;
|
||||||
if (!this._isMainSuspended()) return true;
|
if (!this._isMainSuspended()) return true;
|
||||||
@@ -1345,7 +1354,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
||||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
const term = termOverRide || this.services.setting.getDeviceAndVaultName();
|
||||||
if (term == "") {
|
if (term == "") {
|
||||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
@@ -1488,7 +1497,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async $anyProcessOptionalFileEvent(path: FilePath): Promise<boolean | undefined> {
|
async _anyProcessOptionalFileEvent(path: FilePath): Promise<boolean> {
|
||||||
return await this.watchVaultRawEventsAsync(path);
|
return await this.watchVaultRawEventsAsync(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1535,7 +1544,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
await shareRunningResult("scanAllConfigFiles", async () => {
|
await shareRunningResult("scanAllConfigFiles", async () => {
|
||||||
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||||
this._log("Scanning customizing files.", logLevel, "scan-all-config");
|
this._log("Scanning customizing files.", logLevel, "scan-all-config");
|
||||||
const term = this.plugin.$$getDeviceAndVaultName();
|
const term = this.services.setting.getDeviceAndVaultName();
|
||||||
if (term == "") {
|
if (term == "") {
|
||||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
@@ -1673,7 +1682,10 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
return filenames as FilePath[];
|
return filenames as FilePath[];
|
||||||
}
|
}
|
||||||
|
|
||||||
async $allAskUsingOptionalSyncFeature(opt: { enableFetch?: boolean; enableOverwrite?: boolean }): Promise<boolean> {
|
private async _allAskUsingOptionalSyncFeature(opt: {
|
||||||
|
enableFetch?: boolean;
|
||||||
|
enableOverwrite?: boolean;
|
||||||
|
}): Promise<boolean> {
|
||||||
await this._askHiddenFileConfiguration(opt);
|
await this._askHiddenFileConfiguration(opt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1707,7 +1719,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | "newer"> {
|
_anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | "newer"> {
|
||||||
if (isPluginMetadata(path)) {
|
if (isPluginMetadata(path)) {
|
||||||
return Promise.resolve("newer");
|
return Promise.resolve("newer");
|
||||||
}
|
}
|
||||||
@@ -1717,7 +1729,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$allSuspendExtraSync(): Promise<boolean> {
|
private _allSuspendExtraSync(): Promise<boolean> {
|
||||||
if (this.plugin.settings.usePluginSync || this.plugin.settings.autoSweepPlugins) {
|
if (this.plugin.settings.usePluginSync || this.plugin.settings.autoSweepPlugins) {
|
||||||
this._log(
|
this._log(
|
||||||
"Customisation sync have been temporarily disabled. Please enable them after the fetching, if you need them.",
|
"Customisation sync have been temporarily disabled. Please enable them after the fetching, if you need them.",
|
||||||
@@ -1729,10 +1741,11 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyConfigureOptionalSyncFeature(mode: "CUSTOMIZE" | "DISABLE" | "DISABLE_CUSTOM") {
|
private async _anyConfigureOptionalSyncFeature(mode: keyof OPTIONAL_SYNC_FEATURES) {
|
||||||
await this.configureHiddenFileSync(mode);
|
await this.configureHiddenFileSync(mode);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
async configureHiddenFileSync(mode: "CUSTOMIZE" | "DISABLE" | "DISABLE_CUSTOM") {
|
async configureHiddenFileSync(mode: keyof OPTIONAL_SYNC_FEATURES) {
|
||||||
if (mode == "DISABLE") {
|
if (mode == "DISABLE") {
|
||||||
this.plugin.settings.usePluginSync = false;
|
this.plugin.settings.usePluginSync = false;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
@@ -1740,7 +1753,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == "CUSTOMIZE") {
|
if (mode == "CUSTOMIZE") {
|
||||||
if (!this.plugin.$$getDeviceAndVaultName()) {
|
if (!this.services.setting.getDeviceAndVaultName()) {
|
||||||
let name = await this.plugin.confirm.askString("Device name", "Please set this device name", `desktop`);
|
let name = await this.plugin.confirm.askString("Device name", "Please set this device name", `desktop`);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
if (Platform.isAndroidApp) {
|
if (Platform.isAndroidApp) {
|
||||||
@@ -1764,7 +1777,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
name = name + Math.random().toString(36).slice(-4);
|
name = name + Math.random().toString(36).slice(-4);
|
||||||
}
|
}
|
||||||
this.plugin.$$setDeviceAndVaultName(name);
|
this.services.setting.setDeviceAndVaultName(name);
|
||||||
}
|
}
|
||||||
this.plugin.settings.usePluginSync = true;
|
this.plugin.settings.usePluginSync = true;
|
||||||
this.plugin.settings.useAdvancedMode = true;
|
this.plugin.settings.useAdvancedMode = true;
|
||||||
@@ -1789,4 +1802,17 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
|||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.fileProcessing.handleOptionalFileEvent(this._anyProcessOptionalFileEvent.bind(this));
|
||||||
|
services.conflict.handleGetOptionalConflictCheckMethod(this._anyGetOptionalConflictCheckMethod.bind(this));
|
||||||
|
services.replication.handleProcessVirtualDocuments(this._anyModuleParsedReplicationResultItem.bind(this));
|
||||||
|
services.setting.handleOnRealiseSetting(this._everyRealizeSettingSyncMode.bind(this));
|
||||||
|
services.appLifecycle.handleOnResuming(this._everyOnResumeProcess.bind(this));
|
||||||
|
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
||||||
|
services.databaseEvents.handleDatabaseInitialised(this._everyOnDatabaseInitialized.bind(this));
|
||||||
|
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
||||||
|
services.setting.handleSuggestOptionalFeatures(this._allAskUsingOptionalSyncFeature.bind(this));
|
||||||
|
services.setting.handleEnableOptionalFeature(this._anyConfigureOptionalSyncFeature.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
export let plugin: ObsidianLiveSyncPlugin;
|
export let plugin: ObsidianLiveSyncPlugin;
|
||||||
|
|
||||||
$: hideNotApplicable = false;
|
$: hideNotApplicable = false;
|
||||||
$: thisTerm = plugin.$$getDeviceAndVaultName();
|
$: thisTerm = plugin.services.setting.getDeviceAndVaultName();
|
||||||
|
|
||||||
const addOn = plugin.getAddOn(ConfigSync.name) as ConfigSync;
|
const addOn = plugin.getAddOn(ConfigSync.name) as ConfigSync;
|
||||||
if (!addOn) {
|
if (!addOn) {
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
await requestUpdate();
|
await requestUpdate();
|
||||||
}
|
}
|
||||||
async function replicate() {
|
async function replicate() {
|
||||||
await plugin.$$replicate(true);
|
await plugin.services.replication.replicate(true);
|
||||||
}
|
}
|
||||||
function selectAllNewest(selectMode: boolean) {
|
function selectAllNewest(selectMode: boolean) {
|
||||||
selectNewestPulse++;
|
selectNewestPulse++;
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
plugin.settings.pluginSyncExtendedSetting[key].files = files;
|
plugin.settings.pluginSyncExtendedSetting[key].files = files;
|
||||||
plugin.settings.pluginSyncExtendedSetting[key].mode = mode;
|
plugin.settings.pluginSyncExtendedSetting[key].mode = mode;
|
||||||
}
|
}
|
||||||
plugin.$$saveSettingData();
|
plugin.services.setting.saveSettingData();
|
||||||
}
|
}
|
||||||
function getIcon(mode: SYNC_MODE) {
|
function getIcon(mode: SYNC_MODE) {
|
||||||
if (mode in ICONS) {
|
if (mode in ICONS) {
|
||||||
|
|||||||
@@ -51,12 +51,20 @@ import { LiveSyncCommands } from "../LiveSyncCommands.ts";
|
|||||||
import { addPrefix, stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
import { addPrefix, stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
||||||
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
||||||
import { hiddenFilesEventCount, hiddenFilesProcessingCount } from "../../lib/src/mock_and_interop/stores.ts";
|
import { hiddenFilesEventCount, hiddenFilesProcessingCount } from "../../lib/src/mock_and_interop/stores.ts";
|
||||||
import type { IObsidianModule } from "../../modules/AbstractObsidianModule.ts";
|
|
||||||
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
|
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
|
||||||
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
|
||||||
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
type SyncDirection = "push" | "pull" | "safe" | "pullForce" | "pushForce";
|
type SyncDirection = "push" | "pull" | "safe" | "pullForce" | "pushForce";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface OPTIONAL_SYNC_FEATURES {
|
||||||
|
FETCH: "FETCH";
|
||||||
|
OVERWRITE: "OVERWRITE";
|
||||||
|
MERGE: "MERGE";
|
||||||
|
DISABLE: "DISABLE";
|
||||||
|
DISABLE_HIDDEN: "DISABLE_HIDDEN";
|
||||||
|
}
|
||||||
|
}
|
||||||
function getComparingMTime(
|
function getComparingMTime(
|
||||||
doc: (MetaEntry | LoadedEntry | false) | UXFileInfo | UXStat | null | undefined,
|
doc: (MetaEntry | LoadedEntry | false) | UXFileInfo | UXStat | null | undefined,
|
||||||
includeDeleted = false
|
includeDeleted = false
|
||||||
@@ -72,7 +80,7 @@ function getComparingMTime(
|
|||||||
return doc.mtime ?? 0;
|
return doc.mtime ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule {
|
export class HiddenFileSync extends LiveSyncCommands {
|
||||||
_isThisModuleEnabled() {
|
_isThisModuleEnabled() {
|
||||||
return this.plugin.settings.syncInternalFiles;
|
return this.plugin.settings.syncInternalFiles;
|
||||||
}
|
}
|
||||||
@@ -132,13 +140,17 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
this.updateSettingCache();
|
this.updateSettingCache();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async $everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
// We cannot initialise autosaveCache because kvDB is not ready yet
|
||||||
|
// async _everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
|
// this._fileInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed");
|
||||||
|
// this._databaseInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed-database");
|
||||||
|
// this._fileInfoLastKnown = await autosaveCache(this.kvDB, "hidden-file-lastKnown");
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
private async _everyOnDatabaseInitialized(showNotice: boolean) {
|
||||||
this._fileInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed");
|
this._fileInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed");
|
||||||
this._databaseInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed-database");
|
this._databaseInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed-database");
|
||||||
this._fileInfoLastKnown = await autosaveCache(this.kvDB, "hidden-file-lastKnown");
|
this._fileInfoLastKnown = await autosaveCache(this.kvDB, "hidden-file-lastKnown");
|
||||||
return true;
|
|
||||||
}
|
|
||||||
async $everyOnDatabaseInitialized(showNotice: boolean) {
|
|
||||||
if (this._isThisModuleEnabled()) {
|
if (this._isThisModuleEnabled()) {
|
||||||
if (this._fileInfoLastProcessed.size == 0 && this._fileInfoLastProcessed.size == 0) {
|
if (this._fileInfoLastProcessed.size == 0 && this._fileInfoLastProcessed.size == 0) {
|
||||||
this._log(`No cache found. Performing startup scan.`, LOG_LEVEL_VERBOSE);
|
this._log(`No cache found. Performing startup scan.`, LOG_LEVEL_VERBOSE);
|
||||||
@@ -149,7 +161,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async $everyBeforeReplicate(showNotice: boolean) {
|
async _everyBeforeReplicate(showNotice: boolean) {
|
||||||
if (
|
if (
|
||||||
this._isThisModuleEnabled() &&
|
this._isThisModuleEnabled() &&
|
||||||
this._isDatabaseReady() &&
|
this._isDatabaseReady() &&
|
||||||
@@ -161,7 +173,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
this.updateSettingCache();
|
this.updateSettingCache();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
@@ -197,7 +209,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
await this.applyOfflineChanges(showNotice);
|
await this.applyOfflineChanges(showNotice);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnResumeProcess(): Promise<boolean> {
|
async _everyOnResumeProcess(): Promise<boolean> {
|
||||||
this.periodicInternalFileScanProcessor?.disable();
|
this.periodicInternalFileScanProcessor?.disable();
|
||||||
if (this._isMainSuspended()) return true;
|
if (this._isMainSuspended()) return true;
|
||||||
if (this._isThisModuleEnabled()) {
|
if (this._isThisModuleEnabled()) {
|
||||||
@@ -211,10 +223,10 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyRealizeSettingSyncMode(): Promise<boolean> {
|
_everyRealizeSettingSyncMode(): Promise<boolean> {
|
||||||
this.periodicInternalFileScanProcessor?.disable();
|
this.periodicInternalFileScanProcessor?.disable();
|
||||||
if (this._isMainSuspended()) return Promise.resolve(true);
|
if (this._isMainSuspended()) return Promise.resolve(true);
|
||||||
if (!this.plugin.$$isReady()) return Promise.resolve(true);
|
if (!this.services.appLifecycle.isReady()) return Promise.resolve(true);
|
||||||
this.periodicInternalFileScanProcessor.enable(
|
this.periodicInternalFileScanProcessor.enable(
|
||||||
this._isThisModuleEnabled() && this.settings.syncInternalFilesInterval
|
this._isThisModuleEnabled() && this.settings.syncInternalFilesInterval
|
||||||
? this.settings.syncInternalFilesInterval * 1000
|
? this.settings.syncInternalFilesInterval * 1000
|
||||||
@@ -227,13 +239,14 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyProcessOptionalFileEvent(path: FilePath): Promise<boolean | undefined> {
|
async _anyProcessOptionalFileEvent(path: FilePath): Promise<boolean> {
|
||||||
if (this.isReady()) {
|
if (this.isReady()) {
|
||||||
return await this.trackStorageFileModification(path);
|
return (await this.trackStorageFileModification(path)) || false;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | "newer"> {
|
_anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | "newer"> {
|
||||||
if (isInternalMetadata(path)) {
|
if (isInternalMetadata(path)) {
|
||||||
this.queueConflictCheck(path);
|
this.queueConflictCheck(path);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
@@ -241,12 +254,12 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyProcessOptionalSyncFiles(doc: LoadedEntry): Promise<boolean | undefined> {
|
async _anyProcessOptionalSyncFiles(doc: LoadedEntry): Promise<boolean> {
|
||||||
if (isInternalMetadata(doc._id)) {
|
if (isInternalMetadata(doc._id)) {
|
||||||
if (this._isThisModuleEnabled()) {
|
if (this._isThisModuleEnabled()) {
|
||||||
//system file
|
//system file
|
||||||
const filename = getPath(doc);
|
const filename = getPath(doc);
|
||||||
if (await this.plugin.$$isTargetFile(filename)) {
|
if (await this.services.vault.isTargetFile(filename)) {
|
||||||
// this.procInternalFile(filename);
|
// this.procInternalFile(filename);
|
||||||
await this.processReplicationResult(doc);
|
await this.processReplicationResult(doc);
|
||||||
return true;
|
return true;
|
||||||
@@ -1091,14 +1104,14 @@ Offline Changed files: ${files.length}`;
|
|||||||
|
|
||||||
// If something changes left, notify for reloading Obsidian.
|
// If something changes left, notify for reloading Obsidian.
|
||||||
if (updatedFolders.indexOf(this.plugin.app.vault.configDir) >= 0) {
|
if (updatedFolders.indexOf(this.plugin.app.vault.configDir) >= 0) {
|
||||||
if (!this.plugin.$$isReloadingScheduled()) {
|
if (!this.services.appLifecycle.isReloadingScheduled()) {
|
||||||
this.plugin.confirm.askInPopup(
|
this.plugin.confirm.askInPopup(
|
||||||
`updated-any-hidden`,
|
`updated-any-hidden`,
|
||||||
`Some setting files have been modified\nPress {HERE} to schedule a reload of Obsidian, or press elsewhere to dismiss this message.`,
|
`Some setting files have been modified\nPress {HERE} to schedule a reload of Obsidian, or press elsewhere to dismiss this message.`,
|
||||||
(anchor) => {
|
(anchor) => {
|
||||||
anchor.text = "HERE";
|
anchor.text = "HERE";
|
||||||
anchor.addEventListener("click", () => {
|
anchor.addEventListener("click", () => {
|
||||||
this.plugin.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1318,7 +1331,7 @@ Offline Changed files: ${files.length}`;
|
|||||||
async storeInternalFileToDatabase(file: InternalFileInfo | UXFileInfo, forceWrite = false) {
|
async storeInternalFileToDatabase(file: InternalFileInfo | UXFileInfo, forceWrite = false) {
|
||||||
const storeFilePath = stripAllPrefixes(file.path as FilePath);
|
const storeFilePath = stripAllPrefixes(file.path as FilePath);
|
||||||
const storageFilePath = file.path;
|
const storageFilePath = file.path;
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(storageFilePath)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(storageFilePath)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const prefixedFileName = addPrefix(storeFilePath, ICHeader);
|
const prefixedFileName = addPrefix(storeFilePath, ICHeader);
|
||||||
@@ -1372,7 +1385,7 @@ Offline Changed files: ${files.length}`;
|
|||||||
const displayFileName = filenameSrc;
|
const displayFileName = filenameSrc;
|
||||||
const prefixedFileName = addPrefix(storeFilePath, ICHeader);
|
const prefixedFileName = addPrefix(storeFilePath, ICHeader);
|
||||||
const mtime = new Date().getTime();
|
const mtime = new Date().getTime();
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(storageFilePath)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(storageFilePath)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return await serialized("file-" + prefixedFileName, async () => {
|
return await serialized("file-" + prefixedFileName, async () => {
|
||||||
@@ -1432,7 +1445,7 @@ Offline Changed files: ${files.length}`;
|
|||||||
includeDeletion = true
|
includeDeletion = true
|
||||||
) {
|
) {
|
||||||
const prefixedFileName = addPrefix(storageFilePath, ICHeader);
|
const prefixedFileName = addPrefix(storageFilePath, ICHeader);
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(storageFilePath)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(storageFilePath)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return await serialized("file-" + prefixedFileName, async () => {
|
return await serialized("file-" + prefixedFileName, async () => {
|
||||||
@@ -1582,7 +1595,7 @@ Offline Changed files: ${files.length}`;
|
|||||||
|
|
||||||
// <-- Database To Storage Functions
|
// <-- Database To Storage Functions
|
||||||
|
|
||||||
async $allAskUsingOptionalSyncFeature(opt: { enableFetch?: boolean; enableOverwrite?: boolean }) {
|
private async _allAskUsingOptionalSyncFeature(opt: { enableFetch?: boolean; enableOverwrite?: boolean }) {
|
||||||
await this._askHiddenFileConfiguration(opt);
|
await this._askHiddenFileConfiguration(opt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1632,7 +1645,7 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$allSuspendExtraSync(): Promise<boolean> {
|
private _allSuspendExtraSync(): Promise<boolean> {
|
||||||
if (this.plugin.settings.syncInternalFiles) {
|
if (this.plugin.settings.syncInternalFiles) {
|
||||||
this._log(
|
this._log(
|
||||||
"Hidden file synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.",
|
"Hidden file synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.",
|
||||||
@@ -1644,11 +1657,12 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --> Configuration handling
|
// --> Configuration handling
|
||||||
async $anyConfigureOptionalSyncFeature(mode: "FETCH" | "OVERWRITE" | "MERGE" | "DISABLE" | "DISABLE_HIDDEN") {
|
private async _anyConfigureOptionalSyncFeature(mode: keyof OPTIONAL_SYNC_FEATURES) {
|
||||||
await this.configureHiddenFileSync(mode);
|
await this.configureHiddenFileSync(mode);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async configureHiddenFileSync(mode: "FETCH" | "OVERWRITE" | "MERGE" | "DISABLE" | "DISABLE_HIDDEN") {
|
async configureHiddenFileSync(mode: keyof OPTIONAL_SYNC_FEATURES) {
|
||||||
if (
|
if (
|
||||||
mode != "FETCH" &&
|
mode != "FETCH" &&
|
||||||
mode != "OVERWRITE" &&
|
mode != "OVERWRITE" &&
|
||||||
@@ -1718,7 +1732,7 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
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)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(w.path)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const mtime = w.stat?.mtime ?? 0;
|
const mtime = w.stat?.mtime ?? 0;
|
||||||
@@ -1756,7 +1770,7 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
if (ignoreFilter && ignoreFilter.some((ee) => ee.test(file))) {
|
if (ignoreFilter && ignoreFilter.some((ee) => ee.test(file))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(file)) continue;
|
if (await this.services.vault.isIgnoredByIgnoreFile(file)) continue;
|
||||||
files.push(file);
|
files.push(file);
|
||||||
}
|
}
|
||||||
L1: for (const v of w.folders) {
|
L1: for (const v of w.folders) {
|
||||||
@@ -1768,7 +1782,7 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
if (ignoreFilter && ignoreFilter.some((e) => e.test(v))) {
|
if (ignoreFilter && ignoreFilter.some((e) => e.test(v))) {
|
||||||
continue L1;
|
continue L1;
|
||||||
}
|
}
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(v)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(v)) {
|
||||||
continue L1;
|
continue L1;
|
||||||
}
|
}
|
||||||
files = files.concat(await this.getFiles(v, ignoreList, filter, ignoreFilter));
|
files = files.concat(await this.getFiles(v, ignoreList, filter, ignoreFilter));
|
||||||
@@ -1777,4 +1791,20 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <-- Local Storage SubFunctions
|
// <-- Local Storage SubFunctions
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
|
// No longer needed on initialisation
|
||||||
|
// services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
services.fileProcessing.handleOptionalFileEvent(this._anyProcessOptionalFileEvent.bind(this));
|
||||||
|
services.conflict.handleGetOptionalConflictCheckMethod(this._anyGetOptionalConflictCheckMethod.bind(this));
|
||||||
|
services.replication.handleProcessOptionalSynchroniseResult(this._anyProcessOptionalSyncFiles.bind(this));
|
||||||
|
services.setting.handleOnRealiseSetting(this._everyRealizeSettingSyncMode.bind(this));
|
||||||
|
services.appLifecycle.handleOnResuming(this._everyOnResumeProcess.bind(this));
|
||||||
|
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
||||||
|
services.databaseEvents.handleDatabaseInitialised(this._everyOnDatabaseInitialized.bind(this));
|
||||||
|
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
||||||
|
services.setting.handleSuggestOptionalFeatures(this._allAskUsingOptionalSyncFeature.bind(this));
|
||||||
|
services.setting.handleEnableOptionalFeature(this._anyConfigureOptionalSyncFeature.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import {
|
|||||||
LOG_LEVEL_NOTICE,
|
LOG_LEVEL_NOTICE,
|
||||||
type AnyEntry,
|
type AnyEntry,
|
||||||
type DocumentID,
|
type DocumentID,
|
||||||
type EntryHasPath,
|
|
||||||
type FilePath,
|
type FilePath,
|
||||||
type FilePathWithPrefix,
|
type FilePathWithPrefix,
|
||||||
type LOG_LEVEL,
|
type LOG_LEVEL,
|
||||||
} from "../lib/src/common/types.ts";
|
} from "../lib/src/common/types.ts";
|
||||||
import type ObsidianLiveSyncPlugin from "../main.ts";
|
import type ObsidianLiveSyncPlugin from "../main.ts";
|
||||||
import { MARK_DONE } from "../modules/features/ModuleLog.ts";
|
import { MARK_DONE } from "../modules/features/ModuleLog.ts";
|
||||||
|
import type { LiveSyncCore } from "../main.ts";
|
||||||
|
|
||||||
let noticeIndex = 0;
|
let noticeIndex = 0;
|
||||||
export abstract class LiveSyncCommands {
|
export abstract class LiveSyncCommands {
|
||||||
@@ -25,12 +25,15 @@ export abstract class LiveSyncCommands {
|
|||||||
get localDatabase() {
|
get localDatabase() {
|
||||||
return this.plugin.localDatabase;
|
return this.plugin.localDatabase;
|
||||||
}
|
}
|
||||||
|
get services() {
|
||||||
id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix {
|
return this.plugin.services;
|
||||||
return this.plugin.$$id2path(id, entry, stripPrefix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix {
|
||||||
|
// return this.plugin.$$id2path(id, entry, stripPrefix);
|
||||||
|
// }
|
||||||
async path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise<DocumentID> {
|
async path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise<DocumentID> {
|
||||||
return await this.plugin.$$path2id(filename, prefix);
|
return await this.services.path.path2id(filename, prefix);
|
||||||
}
|
}
|
||||||
getPath(entry: AnyEntry): FilePathWithPrefix {
|
getPath(entry: AnyEntry): FilePathWithPrefix {
|
||||||
return getPath(entry);
|
return getPath(entry);
|
||||||
@@ -38,18 +41,19 @@ export abstract class LiveSyncCommands {
|
|||||||
|
|
||||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.onBindFunction(plugin, plugin.services);
|
||||||
}
|
}
|
||||||
abstract onunload(): void;
|
abstract onunload(): void;
|
||||||
abstract onload(): void | Promise<void>;
|
abstract onload(): void | Promise<void>;
|
||||||
|
|
||||||
_isMainReady() {
|
_isMainReady() {
|
||||||
return this.plugin.$$isReady();
|
return this.plugin.services.appLifecycle.isReady();
|
||||||
}
|
}
|
||||||
_isMainSuspended() {
|
_isMainSuspended() {
|
||||||
return this.plugin.$$isSuspended();
|
return this.services.appLifecycle.isSuspended();
|
||||||
}
|
}
|
||||||
_isDatabaseReady() {
|
_isDatabaseReady() {
|
||||||
return this.plugin.$$isDatabaseReady();
|
return this.services.database.isDatabaseReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
||||||
@@ -89,4 +93,8 @@ export abstract class LiveSyncCommands {
|
|||||||
_debug = (msg: any, key?: string) => {
|
_debug = (msg: any, key?: string) => {
|
||||||
this._log(msg, LOG_LEVEL_VERBOSE, key);
|
this._log(msg, LOG_LEVEL_VERBOSE, key);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
|
// Override if needed.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
type MetaEntry,
|
type MetaEntry,
|
||||||
} from "../../lib/src/common/types";
|
} from "../../lib/src/common/types";
|
||||||
import { getNoFromRev } from "../../lib/src/pouchdb/LiveSyncLocalDB";
|
import { getNoFromRev } from "../../lib/src/pouchdb/LiveSyncLocalDB";
|
||||||
import type { IObsidianModule } from "../../modules/AbstractObsidianModule";
|
|
||||||
import { LiveSyncCommands } from "../LiveSyncCommands";
|
import { LiveSyncCommands } from "../LiveSyncCommands";
|
||||||
import { serialized } from "octagonal-wheels/concurrency/lock_v2";
|
import { serialized } from "octagonal-wheels/concurrency/lock_v2";
|
||||||
import { arrayToChunkedArray } from "octagonal-wheels/collection";
|
import { arrayToChunkedArray } from "octagonal-wheels/collection";
|
||||||
@@ -22,10 +21,7 @@ type NoteDocumentID = DocumentID;
|
|||||||
type Rev = string;
|
type Rev = string;
|
||||||
|
|
||||||
type ChunkUsageMap = Map<NoteDocumentID, Map<Rev, Set<ChunkID>>>;
|
type ChunkUsageMap = Map<NoteDocumentID, Map<Rev, Set<ChunkID>>>;
|
||||||
export class LocalDatabaseMaintenance extends LiveSyncCommands implements IObsidianModule {
|
export class LocalDatabaseMaintenance extends LiveSyncCommands {
|
||||||
$everyOnload(): Promise<boolean> {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
onunload(): void {
|
onunload(): void {
|
||||||
// NO OP.
|
// NO OP.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
import type { IObsidianModule } from "../../modules/AbstractObsidianModule";
|
|
||||||
import { P2PReplicatorPaneView, VIEW_TYPE_P2P } from "./P2PReplicator/P2PReplicatorPaneView.ts";
|
import { P2PReplicatorPaneView, VIEW_TYPE_P2P } from "./P2PReplicator/P2PReplicatorPaneView.ts";
|
||||||
import {
|
import {
|
||||||
AutoAccepting,
|
AutoAccepting,
|
||||||
LOG_LEVEL_NOTICE,
|
LOG_LEVEL_NOTICE,
|
||||||
|
P2P_DEFAULT_SETTINGS,
|
||||||
REMOTE_P2P,
|
REMOTE_P2P,
|
||||||
type EntryDoc,
|
type EntryDoc,
|
||||||
type P2PSyncSetting,
|
type P2PSyncSetting,
|
||||||
type RemoteDBSettings,
|
type RemoteDBSettings,
|
||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { LiveSyncCommands } from "../LiveSyncCommands.ts";
|
import { LiveSyncCommands } from "../LiveSyncCommands.ts";
|
||||||
import { LiveSyncTrysteroReplicator } from "../../lib/src/replication/trystero/LiveSyncTrysteroReplicator.ts";
|
import {
|
||||||
|
LiveSyncTrysteroReplicator,
|
||||||
|
setReplicatorFunc,
|
||||||
|
} from "../../lib/src/replication/trystero/LiveSyncTrysteroReplicator.ts";
|
||||||
import { EVENT_REQUEST_OPEN_P2P, eventHub } from "../../common/events.ts";
|
import { EVENT_REQUEST_OPEN_P2P, eventHub } from "../../common/events.ts";
|
||||||
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator.ts";
|
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator.ts";
|
||||||
import { Logger } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
|
||||||
import type { CommandShim } from "../../lib/src/replication/trystero/P2PReplicatorPaneCommon.ts";
|
import type { CommandShim } from "../../lib/src/replication/trystero/P2PReplicatorPaneCommon.ts";
|
||||||
import {
|
import {
|
||||||
P2PReplicatorMixIn,
|
addP2PEventHandlers,
|
||||||
|
closeP2PReplicator,
|
||||||
|
openP2PReplicator,
|
||||||
|
P2PLogCollector,
|
||||||
removeP2PReplicatorInstance,
|
removeP2PReplicatorInstance,
|
||||||
type P2PReplicatorBase,
|
type P2PReplicatorBase,
|
||||||
} from "../../lib/src/replication/trystero/P2PReplicatorCore.ts";
|
} from "../../lib/src/replication/trystero/P2PReplicatorCore.ts";
|
||||||
@@ -24,8 +30,180 @@ import type { Confirm } from "../../lib/src/interfaces/Confirm.ts";
|
|||||||
import type ObsidianLiveSyncPlugin from "../../main.ts";
|
import type ObsidianLiveSyncPlugin from "../../main.ts";
|
||||||
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
||||||
import { getPlatformName } from "../../lib/src/PlatformAPIs/obsidian/Environment.ts";
|
import { getPlatformName } from "../../lib/src/PlatformAPIs/obsidian/Environment.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
import { TrysteroReplicator } from "../../lib/src/replication/trystero/TrysteroReplicator.ts";
|
||||||
|
|
||||||
class P2PReplicatorCommandBase extends LiveSyncCommands implements P2PReplicatorBase {
|
// class P2PReplicatorCommandBase extends LiveSyncCommands implements P2PReplicatorBase {
|
||||||
|
// storeP2PStatusLine = reactiveSource("");
|
||||||
|
|
||||||
|
// getSettings(): P2PSyncSetting {
|
||||||
|
// return this.plugin.settings;
|
||||||
|
// }
|
||||||
|
// get settings() {
|
||||||
|
// return this.plugin.settings;
|
||||||
|
// }
|
||||||
|
// getDB() {
|
||||||
|
// return this.plugin.localDatabase.localDatabase;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get confirm(): Confirm {
|
||||||
|
// return this.plugin.confirm;
|
||||||
|
// }
|
||||||
|
// _simpleStore!: SimpleStore<any>;
|
||||||
|
|
||||||
|
// simpleStore(): SimpleStore<any> {
|
||||||
|
// return this._simpleStore;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// this.onBindFunction(plugin, plugin.services);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async handleReplicatedDocuments(docs: EntryDoc[]): Promise<void> {
|
||||||
|
// // console.log("Processing Replicated Docs", docs);
|
||||||
|
// return await this.services.replication.parseSynchroniseResult(
|
||||||
|
// docs as PouchDB.Core.ExistingDocument<EntryDoc>[]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// onunload(): void {
|
||||||
|
// throw new Error("Method not implemented.");
|
||||||
|
// }
|
||||||
|
// onload(): void | Promise<void> {
|
||||||
|
// throw new Error("Method not implemented.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// init() {
|
||||||
|
// this._simpleStore = this.services.database.openSimpleStore("p2p-sync");
|
||||||
|
// return Promise.resolve(this);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export class P2PReplicator extends P2PReplicatorMixIn(P2PReplicatorCommandBase) implements CommandShim {
|
||||||
|
// storeP2PStatusLine = reactiveSource("");
|
||||||
|
// _anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
||||||
|
// const settings = { ...this.settings, ...settingOverride };
|
||||||
|
// if (settings.remoteType == REMOTE_P2P) {
|
||||||
|
// return Promise.resolve(new LiveSyncTrysteroReplicator(this.plugin));
|
||||||
|
// }
|
||||||
|
// return undefined!;
|
||||||
|
// }
|
||||||
|
// override getPlatform(): string {
|
||||||
|
// return getPlatformName();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// override onunload(): void {
|
||||||
|
// removeP2PReplicatorInstance();
|
||||||
|
// void this.close();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// override onload(): void | Promise<void> {
|
||||||
|
// eventHub.onEvent(EVENT_REQUEST_OPEN_P2P, () => {
|
||||||
|
// void this.openPane();
|
||||||
|
// });
|
||||||
|
// this.p2pLogCollector.p2pReplicationLine.onChanged((line) => {
|
||||||
|
// this.storeP2PStatusLine.value = line.value;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// async _everyOnInitializeDatabase(): Promise<boolean> {
|
||||||
|
// await this.initialiseP2PReplicator();
|
||||||
|
// return Promise.resolve(true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private async _allSuspendExtraSync() {
|
||||||
|
// this.plugin.settings.P2P_Enabled = false;
|
||||||
|
// this.plugin.settings.P2P_AutoAccepting = AutoAccepting.NONE;
|
||||||
|
// this.plugin.settings.P2P_AutoBroadcast = false;
|
||||||
|
// this.plugin.settings.P2P_AutoStart = false;
|
||||||
|
// this.plugin.settings.P2P_AutoSyncPeers = "";
|
||||||
|
// this.plugin.settings.P2P_AutoWatchPeers = "";
|
||||||
|
// return await Promise.resolve(true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // async $everyOnLoadStart() {
|
||||||
|
// // return await Promise.resolve();
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// async openPane() {
|
||||||
|
// await this.services.API.showWindow(VIEW_TYPE_P2P);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async _everyOnloadStart(): Promise<boolean> {
|
||||||
|
// // this.plugin.registerView(VIEW_TYPE_P2P, (leaf) => new P2PReplicatorPaneView(leaf, this.plugin));
|
||||||
|
// this.plugin.addCommand({
|
||||||
|
// id: "open-p2p-replicator",
|
||||||
|
// name: "P2P Sync : Open P2P Replicator",
|
||||||
|
// callback: async () => {
|
||||||
|
// await this.openPane();
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// this.plugin.addCommand({
|
||||||
|
// id: "p2p-establish-connection",
|
||||||
|
// name: "P2P Sync : Connect to the Signalling Server",
|
||||||
|
// checkCallback: (isChecking) => {
|
||||||
|
// if (isChecking) {
|
||||||
|
// return !(this._replicatorInstance?.server?.isServing ?? false);
|
||||||
|
// }
|
||||||
|
// void this.open();
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// this.plugin.addCommand({
|
||||||
|
// id: "p2p-close-connection",
|
||||||
|
// name: "P2P Sync : Disconnect from the Signalling Server",
|
||||||
|
// checkCallback: (isChecking) => {
|
||||||
|
// if (isChecking) {
|
||||||
|
// return this._replicatorInstance?.server?.isServing ?? false;
|
||||||
|
// }
|
||||||
|
// Logger(`Closing P2P Connection`, LOG_LEVEL_NOTICE);
|
||||||
|
// void this.close();
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// this.plugin.addCommand({
|
||||||
|
// id: "replicate-now-by-p2p",
|
||||||
|
// name: "Replicate now by P2P",
|
||||||
|
// checkCallback: (isChecking) => {
|
||||||
|
// if (isChecking) {
|
||||||
|
// if (this.settings.remoteType == REMOTE_P2P) return false;
|
||||||
|
// if (!this._replicatorInstance?.server?.isServing) return false;
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// void this._replicatorInstance?.replicateFromCommand(false);
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// this.plugin
|
||||||
|
// .addRibbonIcon("waypoints", "P2P Replicator", async () => {
|
||||||
|
// await this.openPane();
|
||||||
|
// })
|
||||||
|
// .addClass("livesync-ribbon-replicate-p2p");
|
||||||
|
|
||||||
|
// return await Promise.resolve(true);
|
||||||
|
// }
|
||||||
|
// _everyAfterResumeProcess(): Promise<boolean> {
|
||||||
|
// if (this.settings.P2P_Enabled && this.settings.P2P_AutoStart) {
|
||||||
|
// setTimeout(() => void this.open(), 100);
|
||||||
|
// }
|
||||||
|
// const rep = this._replicatorInstance;
|
||||||
|
// rep?.allowReconnection();
|
||||||
|
// return Promise.resolve(true);
|
||||||
|
// }
|
||||||
|
// _everyBeforeSuspendProcess(): Promise<boolean> {
|
||||||
|
// const rep = this._replicatorInstance;
|
||||||
|
// rep?.disconnectFromServer();
|
||||||
|
// return Promise.resolve(true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
// services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
||||||
|
// services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
|
// services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
// services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
||||||
|
// services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
// services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
export class P2PReplicator extends LiveSyncCommands implements P2PReplicatorBase, CommandShim {
|
||||||
storeP2PStatusLine = reactiveSource("");
|
storeP2PStatusLine = reactiveSource("");
|
||||||
|
|
||||||
getSettings(): P2PSyncSetting {
|
getSettings(): P2PSyncSetting {
|
||||||
@@ -49,47 +227,126 @@ class P2PReplicatorCommandBase extends LiveSyncCommands implements P2PReplicator
|
|||||||
|
|
||||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
|
setReplicatorFunc(() => this._replicatorInstance);
|
||||||
|
addP2PEventHandlers(this);
|
||||||
|
this.afterConstructor();
|
||||||
|
this.onBindFunction(plugin, plugin.services);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleReplicatedDocuments(docs: EntryDoc[]): Promise<void> {
|
async handleReplicatedDocuments(docs: EntryDoc[]): Promise<void> {
|
||||||
// console.log("Processing Replicated Docs", docs);
|
// console.log("Processing Replicated Docs", docs);
|
||||||
return await this.plugin.$$parseReplicationResult(docs as PouchDB.Core.ExistingDocument<EntryDoc>[]);
|
return await this.services.replication.parseSynchroniseResult(
|
||||||
}
|
docs as PouchDB.Core.ExistingDocument<EntryDoc>[]
|
||||||
onunload(): void {
|
);
|
||||||
throw new Error("Method not implemented.");
|
|
||||||
}
|
|
||||||
onload(): void | Promise<void> {
|
|
||||||
throw new Error("Method not implemented.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
||||||
this._simpleStore = this.plugin.$$getSimpleStore("p2p-sync");
|
|
||||||
return Promise.resolve(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class P2PReplicator
|
|
||||||
extends P2PReplicatorMixIn(P2PReplicatorCommandBase)
|
|
||||||
implements IObsidianModule, CommandShim
|
|
||||||
{
|
|
||||||
storeP2PStatusLine = reactiveSource("");
|
|
||||||
$anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
|
||||||
const settings = { ...this.settings, ...settingOverride };
|
const settings = { ...this.settings, ...settingOverride };
|
||||||
if (settings.remoteType == REMOTE_P2P) {
|
if (settings.remoteType == REMOTE_P2P) {
|
||||||
return Promise.resolve(new LiveSyncTrysteroReplicator(this.plugin));
|
return Promise.resolve(new LiveSyncTrysteroReplicator(this.plugin));
|
||||||
}
|
}
|
||||||
return undefined!;
|
return undefined!;
|
||||||
}
|
}
|
||||||
override getPlatform(): string {
|
_replicatorInstance?: TrysteroReplicator;
|
||||||
|
p2pLogCollector = new P2PLogCollector();
|
||||||
|
|
||||||
|
afterConstructor() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await openP2PReplicator(this);
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
await closeP2PReplicator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig(key: string) {
|
||||||
|
const vaultName = this.services.vault.getVaultName();
|
||||||
|
const dbKey = `${vaultName}-${key}`;
|
||||||
|
return localStorage.getItem(dbKey);
|
||||||
|
}
|
||||||
|
setConfig(key: string, value: string) {
|
||||||
|
const vaultName = this.services.vault.getVaultName();
|
||||||
|
const dbKey = `${vaultName}-${key}`;
|
||||||
|
localStorage.setItem(dbKey, value);
|
||||||
|
}
|
||||||
|
enableBroadcastCastings() {
|
||||||
|
return this?._replicatorInstance?.enableBroadcastChanges();
|
||||||
|
}
|
||||||
|
disableBroadcastCastings() {
|
||||||
|
return this?._replicatorInstance?.disableBroadcastChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._simpleStore = this.services.database.openSimpleStore("p2p-sync");
|
||||||
|
return Promise.resolve(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialiseP2PReplicator(): Promise<TrysteroReplicator> {
|
||||||
|
await this.init();
|
||||||
|
try {
|
||||||
|
if (this._replicatorInstance) {
|
||||||
|
await this._replicatorInstance.close();
|
||||||
|
this._replicatorInstance = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settings.P2P_AppID) {
|
||||||
|
this.settings.P2P_AppID = P2P_DEFAULT_SETTINGS.P2P_AppID;
|
||||||
|
}
|
||||||
|
const getInitialDeviceName = () => this.getConfig("p2p_device_name") || this.services.vault.getVaultName();
|
||||||
|
|
||||||
|
const getSettings = () => this.settings;
|
||||||
|
const store = () => this.simpleStore();
|
||||||
|
const getDB = () => this.getDB();
|
||||||
|
|
||||||
|
const getConfirm = () => this.confirm;
|
||||||
|
const getPlatform = () => this.getPlatform();
|
||||||
|
const env = {
|
||||||
|
get db() {
|
||||||
|
return getDB();
|
||||||
|
},
|
||||||
|
get confirm() {
|
||||||
|
return getConfirm();
|
||||||
|
},
|
||||||
|
get deviceName() {
|
||||||
|
return getInitialDeviceName();
|
||||||
|
},
|
||||||
|
get platform() {
|
||||||
|
return getPlatform();
|
||||||
|
},
|
||||||
|
get settings() {
|
||||||
|
return getSettings();
|
||||||
|
},
|
||||||
|
processReplicatedDocs: async (docs: EntryDoc[]): Promise<void> => {
|
||||||
|
await this.handleReplicatedDocuments(docs);
|
||||||
|
// No op. This is a client and does not need to process the docs
|
||||||
|
},
|
||||||
|
get simpleStore() {
|
||||||
|
return store();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this._replicatorInstance = new TrysteroReplicator(env);
|
||||||
|
return this._replicatorInstance;
|
||||||
|
} catch (e) {
|
||||||
|
this._log(
|
||||||
|
e instanceof Error ? e.message : "Something occurred on Initialising P2P Replicator",
|
||||||
|
LOG_LEVEL_INFO
|
||||||
|
);
|
||||||
|
this._log(e, LOG_LEVEL_VERBOSE);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getPlatform(): string {
|
||||||
return getPlatformName();
|
return getPlatformName();
|
||||||
}
|
}
|
||||||
|
|
||||||
override onunload(): void {
|
onunload(): void {
|
||||||
removeP2PReplicatorInstance();
|
removeP2PReplicatorInstance();
|
||||||
void this.close();
|
void this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
override onload(): void | Promise<void> {
|
onload(): void | Promise<void> {
|
||||||
eventHub.onEvent(EVENT_REQUEST_OPEN_P2P, () => {
|
eventHub.onEvent(EVENT_REQUEST_OPEN_P2P, () => {
|
||||||
void this.openPane();
|
void this.openPane();
|
||||||
});
|
});
|
||||||
@@ -97,12 +354,12 @@ export class P2PReplicator
|
|||||||
this.storeP2PStatusLine.value = line.value;
|
this.storeP2PStatusLine.value = line.value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async $everyOnInitializeDatabase(): Promise<boolean> {
|
async _everyOnInitializeDatabase(): Promise<boolean> {
|
||||||
await this.initialiseP2PReplicator();
|
await this.initialiseP2PReplicator();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $allSuspendExtraSync() {
|
private async _allSuspendExtraSync() {
|
||||||
this.plugin.settings.P2P_Enabled = false;
|
this.plugin.settings.P2P_Enabled = false;
|
||||||
this.plugin.settings.P2P_AutoAccepting = AutoAccepting.NONE;
|
this.plugin.settings.P2P_AutoAccepting = AutoAccepting.NONE;
|
||||||
this.plugin.settings.P2P_AutoBroadcast = false;
|
this.plugin.settings.P2P_AutoBroadcast = false;
|
||||||
@@ -112,15 +369,15 @@ export class P2PReplicator
|
|||||||
return await Promise.resolve(true);
|
return await Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnLoadStart() {
|
// async $everyOnLoadStart() {
|
||||||
return await Promise.resolve();
|
// return await Promise.resolve();
|
||||||
}
|
// }
|
||||||
|
|
||||||
async openPane() {
|
async openPane() {
|
||||||
await this.plugin.$$showView(VIEW_TYPE_P2P);
|
await this.services.API.showWindow(VIEW_TYPE_P2P);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnloadStart(): Promise<boolean> {
|
async _everyOnloadStart(): Promise<boolean> {
|
||||||
this.plugin.registerView(VIEW_TYPE_P2P, (leaf) => new P2PReplicatorPaneView(leaf, this.plugin));
|
this.plugin.registerView(VIEW_TYPE_P2P, (leaf) => new P2PReplicatorPaneView(leaf, this.plugin));
|
||||||
this.plugin.addCommand({
|
this.plugin.addCommand({
|
||||||
id: "open-p2p-replicator",
|
id: "open-p2p-replicator",
|
||||||
@@ -170,7 +427,7 @@ export class P2PReplicator
|
|||||||
|
|
||||||
return await Promise.resolve(true);
|
return await Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
_everyAfterResumeProcess(): Promise<boolean> {
|
||||||
if (this.settings.P2P_Enabled && this.settings.P2P_AutoStart) {
|
if (this.settings.P2P_Enabled && this.settings.P2P_AutoStart) {
|
||||||
setTimeout(() => void this.open(), 100);
|
setTimeout(() => void this.open(), 100);
|
||||||
}
|
}
|
||||||
@@ -178,9 +435,18 @@ export class P2PReplicator
|
|||||||
rep?.allowReconnection();
|
rep?.allowReconnection();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyBeforeSuspendProcess(): Promise<boolean> {
|
_everyBeforeSuspendProcess(): Promise<boolean> {
|
||||||
const rep = this._replicatorInstance;
|
const rep = this._replicatorInstance;
|
||||||
rep?.disconnectFromServer();
|
rep?.disconnectFromServer();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
||||||
|
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
||||||
|
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,10 @@
|
|||||||
const initialSettings = { ...plugin.settings };
|
const initialSettings = { ...plugin.settings };
|
||||||
|
|
||||||
let settings = $state<P2PSyncSetting>(initialSettings);
|
let settings = $state<P2PSyncSetting>(initialSettings);
|
||||||
// const vaultName = plugin.$$getVaultName();
|
// const vaultName = service.vault.getVaultName();
|
||||||
// const dbKey = `${vaultName}-p2p-device-name`;
|
// const dbKey = `${vaultName}-p2p-device-name`;
|
||||||
|
|
||||||
const initialDeviceName = cmdSync.getConfig("p2p_device_name") ?? plugin.$$getVaultName();
|
const initialDeviceName = cmdSync.getConfig("p2p_device_name") ?? plugin.services.vault.getVaultName();
|
||||||
let deviceName = $state<string>(initialDeviceName);
|
let deviceName = $state<string>(initialDeviceName);
|
||||||
|
|
||||||
let eP2PEnabled = $state<boolean>(initialSettings.P2P_Enabled);
|
let eP2PEnabled = $state<boolean>(initialSettings.P2P_Enabled);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ And you can also drop the local database to rebuild from the remote device.`,
|
|||||||
if (yn === DROP) {
|
if (yn === DROP) {
|
||||||
await this.plugin.rebuilder.scheduleFetch();
|
await this.plugin.rebuilder.scheduleFetch();
|
||||||
} else {
|
} else {
|
||||||
await this.plugin.$$scheduleAppReload();
|
this.plugin.services.appLifecycle.scheduleRestart();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger(`Cancelled\nRemote config for ${peer.name} is not applied`, LOG_LEVEL_NOTICE);
|
Logger(`Cancelled\nRemote config for ${peer.name} is not applied`, LOG_LEVEL_NOTICE);
|
||||||
|
|||||||
2
src/lib
2
src/lib
Submodule src/lib updated: 21ca077163...868590e814
792
src/main.ts
792
src/main.ts
@@ -1,26 +1,10 @@
|
|||||||
import { Plugin } from "./deps";
|
import { Plugin } from "./deps";
|
||||||
import {
|
import {
|
||||||
type EntryDoc,
|
type EntryDoc,
|
||||||
type LoadedEntry,
|
|
||||||
type ObsidianLiveSyncSettings,
|
type ObsidianLiveSyncSettings,
|
||||||
type LOG_LEVEL,
|
|
||||||
type diff_result,
|
|
||||||
type DatabaseConnectingStatus,
|
type DatabaseConnectingStatus,
|
||||||
type EntryHasPath,
|
|
||||||
type DocumentID,
|
|
||||||
type FilePathWithPrefix,
|
|
||||||
type FilePath,
|
|
||||||
LOG_LEVEL_INFO,
|
|
||||||
type HasSettings,
|
type HasSettings,
|
||||||
type MetaEntry,
|
|
||||||
type UXFileInfoStub,
|
|
||||||
type MISSING_OR_ERROR,
|
|
||||||
type AUTO_MERGED,
|
|
||||||
type RemoteDBSettings,
|
|
||||||
type TweakValues,
|
|
||||||
type CouchDBCredentials,
|
|
||||||
} from "./lib/src/common/types.ts";
|
} from "./lib/src/common/types.ts";
|
||||||
import { type FileEventItem } from "./common/types.ts";
|
|
||||||
import { type SimpleStore } from "./lib/src/common/utils.ts";
|
import { type SimpleStore } from "./lib/src/common/utils.ts";
|
||||||
import { LiveSyncLocalDB, type LiveSyncLocalDBEnv } from "./lib/src/pouchdb/LiveSyncLocalDB.ts";
|
import { LiveSyncLocalDB, type LiveSyncLocalDBEnv } from "./lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||||
import {
|
import {
|
||||||
@@ -35,7 +19,6 @@ import { reactiveSource, type ReactiveValue } from "octagonal-wheels/dataobject/
|
|||||||
import { type LiveSyncJournalReplicatorEnv } from "./lib/src/replication/journal/LiveSyncJournalReplicator.js";
|
import { type LiveSyncJournalReplicatorEnv } from "./lib/src/replication/journal/LiveSyncJournalReplicator.js";
|
||||||
import { type LiveSyncCouchDBReplicatorEnv } from "./lib/src/replication/couchdb/LiveSyncReplicator.js";
|
import { type LiveSyncCouchDBReplicatorEnv } from "./lib/src/replication/couchdb/LiveSyncReplicator.js";
|
||||||
import type { CheckPointInfo } from "./lib/src/replication/journal/JournalSyncTypes.js";
|
import type { CheckPointInfo } from "./lib/src/replication/journal/JournalSyncTypes.js";
|
||||||
import { ObsHttpHandler } from "./modules/essentialObsidian/APILib/ObsHttpHandler.js";
|
|
||||||
import type { IObsidianModule } from "./modules/AbstractObsidianModule.ts";
|
import type { IObsidianModule } from "./modules/AbstractObsidianModule.ts";
|
||||||
|
|
||||||
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
|
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
|
||||||
@@ -59,8 +42,7 @@ import { ModuleDatabaseFileAccess } from "./modules/core/ModuleDatabaseFileAcces
|
|||||||
import { ModuleFileHandler } from "./modules/core/ModuleFileHandler.ts";
|
import { ModuleFileHandler } from "./modules/core/ModuleFileHandler.ts";
|
||||||
import { ModuleObsidianAPI } from "./modules/essentialObsidian/ModuleObsidianAPI.ts";
|
import { ModuleObsidianAPI } from "./modules/essentialObsidian/ModuleObsidianAPI.ts";
|
||||||
import { ModuleObsidianEvents } from "./modules/essentialObsidian/ModuleObsidianEvents.ts";
|
import { ModuleObsidianEvents } from "./modules/essentialObsidian/ModuleObsidianEvents.ts";
|
||||||
import { injectModules, type AbstractModule } from "./modules/AbstractModule.ts";
|
import { type AbstractModule } from "./modules/AbstractModule.ts";
|
||||||
import type { ICoreModule } from "./modules/ModuleTypes.ts";
|
|
||||||
import { ModuleObsidianSettingDialogue } from "./modules/features/ModuleObsidianSettingTab.ts";
|
import { ModuleObsidianSettingDialogue } from "./modules/features/ModuleObsidianSettingTab.ts";
|
||||||
import { ModuleObsidianDocumentHistory } from "./modules/features/ModuleObsidianDocumentHistory.ts";
|
import { ModuleObsidianDocumentHistory } from "./modules/features/ModuleObsidianDocumentHistory.ts";
|
||||||
import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHistory.ts";
|
import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHistory.ts";
|
||||||
@@ -85,13 +67,16 @@ import { ModuleExtraSyncObsidian } from "./modules/extraFeaturesObsidian/ModuleE
|
|||||||
import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts";
|
import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts";
|
||||||
import { P2PReplicator } from "./features/P2PSync/CmdP2PReplicator.ts";
|
import { P2PReplicator } from "./features/P2PSync/CmdP2PReplicator.ts";
|
||||||
import type { LiveSyncManagers } from "./lib/src/managers/LiveSyncManagers.ts";
|
import type { LiveSyncManagers } from "./lib/src/managers/LiveSyncManagers.ts";
|
||||||
|
import { ObsidianServiceHub } from "./modules/services/ObsidianServices.ts";
|
||||||
|
import type { InjectableServiceHub } from "./lib/src/services/InjectableServices.ts";
|
||||||
|
|
||||||
|
// function throwShouldBeOverridden(): never {
|
||||||
|
// throw new Error("This function should be overridden by the module.");
|
||||||
|
// }
|
||||||
|
// const InterceptiveAll = Promise.resolve(true);
|
||||||
|
// const InterceptiveEvery = Promise.resolve(true);
|
||||||
|
// const InterceptiveAny = Promise.resolve(undefined);
|
||||||
|
|
||||||
function throwShouldBeOverridden(): never {
|
|
||||||
throw new Error("This function should be overridden by the module.");
|
|
||||||
}
|
|
||||||
const InterceptiveAll = Promise.resolve(true);
|
|
||||||
const InterceptiveEvery = Promise.resolve(true);
|
|
||||||
const InterceptiveAny = Promise.resolve(undefined);
|
|
||||||
/**
|
/**
|
||||||
* All $prefixed functions are hooked by the modules. Be careful to call them directly.
|
* All $prefixed functions are hooked by the modules. Be careful to call them directly.
|
||||||
* Please refer to the module's source code to understand the function.
|
* Please refer to the module's source code to understand the function.
|
||||||
@@ -101,6 +86,13 @@ const InterceptiveAny = Promise.resolve(undefined);
|
|||||||
* $any : Process all modules until the first success.
|
* $any : Process all modules until the first success.
|
||||||
* $ : Other interceptive points. You should manually assign the module
|
* $ : Other interceptive points. You should manually assign the module
|
||||||
* All of above performed on injectModules function.
|
* All of above performed on injectModules function.
|
||||||
|
*
|
||||||
|
* No longer used! See AppLifecycleService in Services.ts.
|
||||||
|
* For a while, just commented out some previously used code. (sorry, some are deleted...)
|
||||||
|
* 'Convention over configuration' was a lie for me. At least, very lack of refactor-ability.
|
||||||
|
*
|
||||||
|
* Still some modules are separated, and connected by `ThroughHole` class.
|
||||||
|
* However, it is not a good design. I am going to manage the modules in a more explicit way.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class ObsidianLiveSyncPlugin
|
export default class ObsidianLiveSyncPlugin
|
||||||
@@ -112,6 +104,18 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
LiveSyncCouchDBReplicatorEnv,
|
LiveSyncCouchDBReplicatorEnv,
|
||||||
HasSettings<ObsidianLiveSyncSettings>
|
HasSettings<ObsidianLiveSyncSettings>
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The service hub for managing all services.
|
||||||
|
*/
|
||||||
|
_services: InjectableServiceHub = new ObsidianServiceHub();
|
||||||
|
get services() {
|
||||||
|
return this._services;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Bind functions to the service hub (for migration purpose).
|
||||||
|
*/
|
||||||
|
// bindFunctions = (this.serviceHub as ObsidianServiceHub).bindFunctions.bind(this.serviceHub);
|
||||||
|
|
||||||
// --> Module System
|
// --> Module System
|
||||||
getAddOn<T extends LiveSyncCommands>(cls: string) {
|
getAddOn<T extends LiveSyncCommands>(cls: string) {
|
||||||
for (const addon of this.addOns) {
|
for (const addon of this.addOns) {
|
||||||
@@ -173,41 +177,9 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
new ModuleReplicateTest(this, this),
|
new ModuleReplicateTest(this, this),
|
||||||
new ModuleIntegratedTest(this, this),
|
new ModuleIntegratedTest(this, this),
|
||||||
] as (IObsidianModule | AbstractModule)[];
|
] as (IObsidianModule | AbstractModule)[];
|
||||||
injected = injectModules(this, [...this.modules, ...this.addOns] as ICoreModule[]);
|
// injected = injectModules(this, [...this.modules, ...this.addOns] as ICoreModule[]);
|
||||||
// <-- Module System
|
// <-- Module System
|
||||||
|
|
||||||
$$isSuspended(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$setSuspended(value: boolean): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$isDatabaseReady(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$getDeviceAndVaultName(): string {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$setDeviceAndVaultName(name: string): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$isReady(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$markIsReady(): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$resetIsReady(): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Following are plugged by the modules.
|
// Following are plugged by the modules.
|
||||||
|
|
||||||
settings!: ObsidianLiveSyncSettings;
|
settings!: ObsidianLiveSyncSettings;
|
||||||
@@ -229,30 +201,6 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
return this.settings;
|
return this.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$markFileListPossiblyChanged(): void {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$customFetchHandler(): ObsHttpHandler {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$getLastPostFailedBySize(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$isStorageInsensitive(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$shouldCheckCaseInsensitive(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$isUnloaded(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
requestCount = reactiveSource(0);
|
requestCount = reactiveSource(0);
|
||||||
responseCount = reactiveSource(0);
|
responseCount = reactiveSource(0);
|
||||||
totalQueued = reactiveSource(0);
|
totalQueued = reactiveSource(0);
|
||||||
@@ -277,101 +225,6 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
syncStatus: "CLOSED" as DatabaseConnectingStatus,
|
syncStatus: "CLOSED" as DatabaseConnectingStatus,
|
||||||
});
|
});
|
||||||
|
|
||||||
$$isReloadingScheduled(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$getReplicator(): LiveSyncAbstractReplicator {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$connectRemoteCouchDB(
|
|
||||||
uri: string,
|
|
||||||
auth: CouchDBCredentials,
|
|
||||||
disableRequestURI: boolean,
|
|
||||||
passphrase: string | false,
|
|
||||||
useDynamicIterationCount: boolean,
|
|
||||||
performSetup: boolean,
|
|
||||||
skipInfo: boolean,
|
|
||||||
compression: boolean,
|
|
||||||
customHeaders: Record<string, string>,
|
|
||||||
useRequestAPI: boolean,
|
|
||||||
getPBKDF2Salt: () => Promise<Uint8Array>
|
|
||||||
): Promise<
|
|
||||||
| string
|
|
||||||
| {
|
|
||||||
db: PouchDB.Database<EntryDoc>;
|
|
||||||
info: PouchDB.Core.DatabaseInfo;
|
|
||||||
}
|
|
||||||
> {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$isMobile(): boolean {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
$$vaultName(): string {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --> Path
|
|
||||||
|
|
||||||
$$getActiveFilePath(): FilePathWithPrefix | undefined {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
// <-- Path
|
|
||||||
|
|
||||||
// --> Path conversion
|
|
||||||
$$id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise<DocumentID> {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
// <!-- Path conversion
|
|
||||||
|
|
||||||
// --> Database
|
|
||||||
$$createPouchDBInstance<T extends object>(
|
|
||||||
name?: string,
|
|
||||||
options?: PouchDB.Configuration.DatabaseConfiguration
|
|
||||||
): PouchDB.Database<T> {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$allOnDBUnload(db: LiveSyncLocalDB): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$allOnDBClose(db: LiveSyncLocalDB): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <!-- Database
|
|
||||||
|
|
||||||
$anyNewReplicator(settingOverride: Partial<ObsidianLiveSyncSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
|
||||||
return InterceptiveEvery;
|
|
||||||
}
|
|
||||||
|
|
||||||
$everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
|
||||||
return InterceptiveEvery;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end interfaces
|
|
||||||
|
|
||||||
$$getVaultName(): string {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$$getSimpleStore<T>(kind: string): SimpleStore<T> {
|
|
||||||
throwShouldBeOverridden();
|
|
||||||
}
|
|
||||||
// trench!: Trench;
|
|
||||||
|
|
||||||
// --> Events
|
// --> Events
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -412,331 +265,404 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$everyOnLayoutReady(): Promise<boolean> {
|
// $everyOnLayoutReady(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// //TODO: AppLifecycleService.onLayoutReady
|
||||||
}
|
// return InterceptiveEvery;
|
||||||
$everyOnFirstInitialize(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveEvery;
|
// $everyOnFirstInitialize(): Promise<boolean> {
|
||||||
}
|
// //TODO: AppLifecycleService.onFirstInitialize
|
||||||
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
// Some Module should call this function to start the plugin.
|
// Some Module should call this function to start the plugin.
|
||||||
$$onLiveSyncReady(): Promise<false | undefined> {
|
// $$onLiveSyncReady(): Promise<false | undefined> {
|
||||||
throwShouldBeOverridden();
|
// //TODO: AppLifecycleService.onLiveSyncReady
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$wireUpEvents(): void {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$wireUpEvents(): void {
|
||||||
}
|
// //TODO: AppLifecycleService.wireUpEvents
|
||||||
$$onLiveSyncLoad(): Promise<void> {
|
// throwShouldBeOverridden();
|
||||||
throwShouldBeOverridden();
|
// }
|
||||||
}
|
// $$onLiveSyncLoad(): Promise<void> {
|
||||||
|
// //TODO: AppLifecycleService.onLoad
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$onLiveSyncUnload(): Promise<void> {
|
// $$onLiveSyncUnload(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// //TODO: AppLifecycleService.onAppUnload
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$allScanStat(): Promise<boolean> {
|
// $allScanStat(): Promise<boolean> {
|
||||||
return InterceptiveAll;
|
// //TODO: AppLifecycleService.scanStartupIssues
|
||||||
}
|
// return InterceptiveAll;
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveEvery;
|
// $everyOnloadStart(): Promise<boolean> {
|
||||||
}
|
// //TODO: AppLifecycleService.onInitialise
|
||||||
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
// $everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// //TODO: AppLifecycleService.onApplyStartupLoaded
|
||||||
}
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$everyOnload(): Promise<boolean> {
|
// $everyOnload(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// //TODO: AppLifecycleService.onLoaded
|
||||||
}
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$anyHandlerProcessesFileEvent(item: FileEventItem): Promise<boolean | undefined> {
|
// $anyHandlerProcessesFileEvent(item: FileEventItem): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// //TODO: FileProcessingService.processFileEvent
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
$allStartOnUnload(): Promise<boolean> {
|
// $allStartOnUnload(): Promise<boolean> {
|
||||||
return InterceptiveAll;
|
// //TODO: AppLifecycleService.onBeforeUnload
|
||||||
}
|
// return InterceptiveAll;
|
||||||
$allOnUnload(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveAll;
|
// $allOnUnload(): Promise<boolean> {
|
||||||
}
|
// //TODO: AppLifecycleService.onUnload
|
||||||
|
// return InterceptiveAll;
|
||||||
|
// }
|
||||||
|
|
||||||
$$openDatabase(): Promise<boolean> {
|
// $$openDatabase(): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // DatabaseService.openDatabase
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$realizeSettingSyncMode(): Promise<void> {
|
// $$realizeSettingSyncMode(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.realiseSetting
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$performRestart() {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$performRestart() {
|
||||||
}
|
// // AppLifecycleService.performRestart
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$clearUsedPassphrase(): void {
|
// $$clearUsedPassphrase(): void {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.clearUsedPassphrase
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$decryptSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
// $$decryptSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.decryptSettings
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$adjustSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$adjustSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
||||||
}
|
// // SettingService.adjustSettings
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$loadSettings(): Promise<void> {
|
// $$loadSettings(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.loadSettings
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$saveDeviceAndVaultName(): void {
|
// $$saveDeviceAndVaultName(): void {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.saveDeviceAndVaultName
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$saveSettingData(): Promise<void> {
|
// $$saveSettingData(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // SettingService.saveSettingData
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$anyProcessOptionalFileEvent(path: FilePath): Promise<boolean | undefined> {
|
// $anyProcessOptionalFileEvent(path: FilePath): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// // FileProcessingService.processOptionalFileEvent
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
$everyCommitPendingFileEvent(): Promise<boolean> {
|
// $everyCommitPendingFileEvent(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// // FileProcessingService.commitPendingFileEvent
|
||||||
}
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
// ->
|
// ->
|
||||||
$anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | undefined | "newer"> {
|
// $anyGetOptionalConflictCheckMethod(path: FilePathWithPrefix): Promise<boolean | undefined | "newer"> {
|
||||||
return InterceptiveAny;
|
// return InterceptiveAny;
|
||||||
}
|
// }
|
||||||
|
|
||||||
$$queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise<void> {
|
// $$queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // ConflictEventManager.queueCheckForConflictIfOpen
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$queueConflictCheck(file: FilePathWithPrefix): Promise<void> {
|
// $$queueConflictCheck(file: FilePathWithPrefix): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // ConflictEventManager.queueCheckForConflict
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$waitForAllConflictProcessed(): Promise<boolean> {
|
// $$waitForAllConflictProcessed(): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // ConflictEventManager.ensureAllConflictProcessed
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
//<-- Conflict Check
|
//<-- Conflict Check
|
||||||
|
|
||||||
$anyProcessOptionalSyncFiles(doc: LoadedEntry): Promise<boolean | undefined> {
|
// $anyProcessOptionalSyncFiles(doc: LoadedEntry): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// // ReplicationService.processOptionalSyncFile
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
$anyProcessReplicatedDoc(doc: MetaEntry): Promise<boolean | undefined> {
|
// $anyProcessReplicatedDoc(doc: MetaEntry): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// // ReplicationService.processReplicatedDocument
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
//---> Sync
|
//---> Sync
|
||||||
$$parseReplicationResult(docs: Array<PouchDB.Core.ExistingDocument<EntryDoc>>): void {
|
// $$parseReplicationResult(docs: Array<PouchDB.Core.ExistingDocument<EntryDoc>>): void {
|
||||||
throwShouldBeOverridden();
|
// // ReplicationService.parseSynchroniseResult
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$anyModuleParsedReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>): Promise<boolean | undefined> {
|
// $anyModuleParsedReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// // ReplicationService.processVirtualDocument
|
||||||
}
|
// return InterceptiveAny;
|
||||||
$everyBeforeRealizeSetting(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveEvery;
|
// $everyBeforeRealizeSetting(): Promise<boolean> {
|
||||||
}
|
// // SettingEventManager.beforeRealiseSetting
|
||||||
$everyAfterRealizeSetting(): Promise<boolean> {
|
// return InterceptiveEvery;
|
||||||
return InterceptiveEvery;
|
// }
|
||||||
}
|
// $everyAfterRealizeSetting(): Promise<boolean> {
|
||||||
$everyRealizeSettingSyncMode(): Promise<boolean> {
|
// // SettingEventManager.onSettingRealised
|
||||||
return InterceptiveEvery;
|
// return InterceptiveEvery;
|
||||||
}
|
// }
|
||||||
|
// $everyRealizeSettingSyncMode(): Promise<boolean> {
|
||||||
|
// // SettingEventManager.onRealiseSetting
|
||||||
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$everyBeforeSuspendProcess(): Promise<boolean> {
|
// $everyBeforeSuspendProcess(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// // AppLifecycleService.onSuspending
|
||||||
}
|
// return InterceptiveEvery;
|
||||||
$everyOnResumeProcess(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveEvery;
|
// $everyOnResumeProcess(): Promise<boolean> {
|
||||||
}
|
// // AppLifecycleService.onResuming
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
// return InterceptiveEvery;
|
||||||
return InterceptiveEvery;
|
// }
|
||||||
}
|
// $everyAfterResumeProcess(): Promise<boolean> {
|
||||||
|
// // AppLifecycleService.onResumed
|
||||||
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$$fetchRemotePreferredTweakValues(trialSetting: RemoteDBSettings): Promise<TweakValues | false> {
|
// $$fetchRemotePreferredTweakValues(trialSetting: RemoteDBSettings): Promise<TweakValues | false> {
|
||||||
throwShouldBeOverridden();
|
// //TODO:TweakValueService.fetchRemotePreferred
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$checkAndAskResolvingMismatchedTweaks(preferred: Partial<TweakValues>): Promise<[TweakValues | boolean, boolean]> {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$checkAndAskResolvingMismatchedTweaks(preferred: Partial<TweakValues>): Promise<[TweakValues | boolean, boolean]> {
|
||||||
}
|
// //TODO:TweakValueService.checkAndAskResolvingMismatched
|
||||||
$$askResolvingMismatchedTweaks(preferredSource: TweakValues): Promise<"OK" | "CHECKAGAIN" | "IGNORE"> {
|
// throwShouldBeOverridden();
|
||||||
throwShouldBeOverridden();
|
// }
|
||||||
}
|
// $$askResolvingMismatchedTweaks(preferredSource: TweakValues): Promise<"OK" | "CHECKAGAIN" | "IGNORE"> {
|
||||||
|
// //TODO:TweakValueService.askResolvingMismatched
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$checkAndAskUseRemoteConfiguration(
|
// $$checkAndAskUseRemoteConfiguration(
|
||||||
settings: RemoteDBSettings
|
// settings: RemoteDBSettings
|
||||||
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
// ): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
||||||
throwShouldBeOverridden();
|
// // TweakValueService.checkAndAskUseRemoteConfiguration
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$askUseRemoteConfiguration(
|
// $$askUseRemoteConfiguration(
|
||||||
trialSetting: RemoteDBSettings,
|
// trialSetting: RemoteDBSettings,
|
||||||
preferred: TweakValues
|
// preferred: TweakValues
|
||||||
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
// ): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
||||||
throwShouldBeOverridden();
|
// // TweakValueService.askUseRemoteConfiguration
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
// }
|
||||||
return InterceptiveEvery;
|
// $everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
||||||
}
|
// // ReplicationService.beforeReplicate
|
||||||
|
// return InterceptiveEvery;
|
||||||
|
// }
|
||||||
|
|
||||||
$$canReplicate(showMessage: boolean = false): Promise<boolean> {
|
// $$canReplicate(showMessage: boolean = false): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // ReplicationService.isReplicationReady
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$replicate(showMessage: boolean = false): Promise<boolean | void> {
|
// $$replicate(showMessage: boolean = false): Promise<boolean | void> {
|
||||||
throwShouldBeOverridden();
|
// // ReplicationService.replicate
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$replicateByEvent(showMessage: boolean = false): Promise<boolean | void> {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$replicateByEvent(showMessage: boolean = false): Promise<boolean | void> {
|
||||||
}
|
// // ReplicationService.replicateByEvent
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$everyOnDatabaseInitialized(showingNotice: boolean): Promise<boolean> {
|
// $everyOnDatabaseInitialized(showingNotice: boolean): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // DatabaseEventService.onDatabaseInitialised
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$initializeDatabase(
|
// $$initializeDatabase(
|
||||||
showingNotice: boolean = false,
|
// showingNotice: boolean = false,
|
||||||
reopenDatabase = true,
|
// reopenDatabase = true,
|
||||||
ignoreSuspending: boolean = false
|
// ignoreSuspending: boolean = false
|
||||||
): Promise<boolean> {
|
// ): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // DatabaseEventService.initializeDatabase
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$anyAfterConnectCheckFailed(): Promise<boolean | "CHECKAGAIN" | undefined> {
|
// $anyAfterConnectCheckFailed(): Promise<boolean | "CHECKAGAIN" | undefined> {
|
||||||
return InterceptiveAny;
|
// // ReplicationService.checkConnectionFailure
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
$$replicateAllToServer(
|
// $$replicateAllToServer(
|
||||||
showingNotice: boolean = false,
|
// showingNotice: boolean = false,
|
||||||
sendChunksInBulkDisabled: boolean = false
|
// sendChunksInBulkDisabled: boolean = false
|
||||||
): Promise<boolean> {
|
// ): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.replicateAllToRemote
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$replicateAllFromServer(showingNotice: boolean = false): Promise<boolean> {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$replicateAllFromServer(showingNotice: boolean = false): Promise<boolean> {
|
||||||
}
|
// // RemoteService.replicateAllFromRemote
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
// Remote Governing
|
// Remote Governing
|
||||||
$$markRemoteLocked(lockByClean: boolean = false): Promise<void> {
|
// $$markRemoteLocked(lockByClean: boolean = false): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.markLocked;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$markRemoteUnlocked(): Promise<void> {
|
// $$markRemoteUnlocked(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.markUnlocked;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$markRemoteResolved(): Promise<void> {
|
// $$markRemoteResolved(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.markResolved;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
// <-- Remote Governing
|
// <-- Remote Governing
|
||||||
|
|
||||||
$$isFileSizeExceeded(size: number): boolean {
|
// $$isFileSizeExceeded(size: number): boolean {
|
||||||
throwShouldBeOverridden();
|
// // VaultService.isFileSizeTooLarge
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$performFullScan(showingNotice?: boolean, ignoreSuspending?: boolean): Promise<void> {
|
// $$performFullScan(showingNotice?: boolean, ignoreSuspending?: boolean): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // VaultService.scanVault
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$anyResolveConflictByUI(
|
// $anyResolveConflictByUI(
|
||||||
filename: FilePathWithPrefix,
|
// filename: FilePathWithPrefix,
|
||||||
conflictCheckResult: diff_result
|
// conflictCheckResult: diff_result
|
||||||
): Promise<boolean | undefined> {
|
// ): Promise<boolean | undefined> {
|
||||||
return InterceptiveAny;
|
// // ConflictService.resolveConflictByUserInteraction
|
||||||
}
|
// return InterceptiveAny;
|
||||||
$$resolveConflictByDeletingRev(
|
// }
|
||||||
path: FilePathWithPrefix,
|
// $$resolveConflictByDeletingRev(
|
||||||
deleteRevision: string,
|
// path: FilePathWithPrefix,
|
||||||
subTitle = ""
|
// deleteRevision: string,
|
||||||
): Promise<typeof MISSING_OR_ERROR | typeof AUTO_MERGED> {
|
// subTitle = ""
|
||||||
throwShouldBeOverridden();
|
// ): Promise<typeof MISSING_OR_ERROR | typeof AUTO_MERGED> {
|
||||||
}
|
// // ConflictService.resolveByDeletingRevision
|
||||||
$$resolveConflict(filename: FilePathWithPrefix): Promise<void> {
|
// throwShouldBeOverridden();
|
||||||
throwShouldBeOverridden();
|
// }
|
||||||
}
|
// $$resolveConflict(filename: FilePathWithPrefix): Promise<void> {
|
||||||
$anyResolveConflictByNewest(filename: FilePathWithPrefix): Promise<boolean> {
|
// // ConflictService.resolveConflict
|
||||||
throwShouldBeOverridden();
|
// throwShouldBeOverridden();
|
||||||
}
|
// }
|
||||||
|
// $anyResolveConflictByNewest(filename: FilePathWithPrefix): Promise<boolean> {
|
||||||
|
// // ConflictService.resolveByNewest
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$resetLocalDatabase(): Promise<void> {
|
// $$resetLocalDatabase(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // DatabaseService.resetDatabase;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$tryResetRemoteDatabase(): Promise<void> {
|
// $$tryResetRemoteDatabase(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.tryResetDatabase;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$tryCreateRemoteDatabase(): Promise<void> {
|
// $$tryCreateRemoteDatabase(): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // RemoteService.tryCreateDatabase;
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$isIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
|
// $$isIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // VaultService.isIgnoredByIgnoreFiles
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$isTargetFile(file: string | UXFileInfoStub, keepFileCheckList = false): Promise<boolean> {
|
// $$isTargetFile(file: string | UXFileInfoStub, keepFileCheckList = false): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // VaultService.isTargetFile
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$askReload(message?: string) {
|
// $$askReload(message?: string) {
|
||||||
throwShouldBeOverridden();
|
// // AppLifecycleService.askRestart
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$$scheduleAppReload() {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $$scheduleAppReload() {
|
||||||
}
|
// // AppLifecycleService.scheduleRestart
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
//--- Setup
|
//--- Setup
|
||||||
$allSuspendAllSync(): Promise<boolean> {
|
// $allSuspendAllSync(): Promise<boolean> {
|
||||||
return InterceptiveAll;
|
// // SettingEventManager.suspendAllSync
|
||||||
}
|
// return InterceptiveAll;
|
||||||
$allSuspendExtraSync(): Promise<boolean> {
|
// }
|
||||||
return InterceptiveAll;
|
// $allSuspendExtraSync(): Promise<boolean> {
|
||||||
}
|
// // SettingEventManager.suspendExtraSync
|
||||||
|
// return InterceptiveAll;
|
||||||
|
// }
|
||||||
|
|
||||||
$allAskUsingOptionalSyncFeature(opt: { enableFetch?: boolean; enableOverwrite?: boolean }): Promise<boolean> {
|
// $allAskUsingOptionalSyncFeature(opt: { enableFetch?: boolean; enableOverwrite?: boolean }): Promise<boolean> {
|
||||||
throwShouldBeOverridden();
|
// // SettingEventManager.suggestOptionalFeatures
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
$anyConfigureOptionalSyncFeature(mode: string): Promise<void> {
|
// }
|
||||||
throwShouldBeOverridden();
|
// $anyConfigureOptionalSyncFeature(mode: string): Promise<void> {
|
||||||
}
|
// // SettingEventManager.enableOptionalFeature
|
||||||
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
$$showView(viewType: string): Promise<void> {
|
// $$showView(viewType: string): Promise<void> {
|
||||||
throwShouldBeOverridden();
|
// // UIManager.showWindow //
|
||||||
}
|
// throwShouldBeOverridden();
|
||||||
|
// }
|
||||||
|
|
||||||
// For Development: Ensure reliability MORE AND MORE. May the this plug-in helps all of us.
|
// For Development: Ensure reliability MORE AND MORE. May the this plug-in helps all of us.
|
||||||
$everyModuleTest(): Promise<boolean> {
|
// $everyModuleTest(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// return InterceptiveEvery;
|
||||||
}
|
// }
|
||||||
$everyModuleTestMultiDevice(): Promise<boolean> {
|
// $everyModuleTestMultiDevice(): Promise<boolean> {
|
||||||
return InterceptiveEvery;
|
// return InterceptiveEvery;
|
||||||
}
|
// }
|
||||||
$$addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void {
|
// $$addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void {
|
||||||
throwShouldBeOverridden();
|
// throwShouldBeOverridden();
|
||||||
}
|
// }
|
||||||
|
|
||||||
_isThisModuleEnabled(): boolean {
|
// _isThisModuleEnabled(): boolean {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
$anyGetAppId(): Promise<string | undefined> {
|
// $anyGetAppId(): Promise<string | undefined> {
|
||||||
return InterceptiveAny;
|
// // APIService.getAppId
|
||||||
}
|
// return InterceptiveAny;
|
||||||
|
// }
|
||||||
|
|
||||||
// Plug-in's overrideable functions
|
// Plug-in's overrideable functions
|
||||||
onload() {
|
onload() {
|
||||||
void this.$$onLiveSyncLoad();
|
void this.services.appLifecycle.onLoad();
|
||||||
}
|
}
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
await this.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
}
|
}
|
||||||
onunload() {
|
onunload() {
|
||||||
return void this.$$onLiveSyncUnload();
|
return void this.services.appLifecycle.onAppUnload();
|
||||||
}
|
}
|
||||||
// <-- Plug-in's overrideable functions
|
// <-- Plug-in's overrideable functions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
|
||||||
import type { LOG_LEVEL } from "../lib/src/common/types";
|
import type { LOG_LEVEL } from "../lib/src/common/types";
|
||||||
import type { LiveSyncCore } from "../main";
|
import type { LiveSyncCore } from "../main";
|
||||||
import { unique } from "octagonal-wheels/collection";
|
// import { unique } from "octagonal-wheels/collection";
|
||||||
import type { IObsidianModule } from "./AbstractObsidianModule.ts";
|
// import type { IObsidianModule } from "./AbstractObsidianModule.ts";
|
||||||
import type {
|
// import type {
|
||||||
ICoreModuleBase,
|
// ICoreModuleBase,
|
||||||
AllInjectableProps,
|
// AllInjectableProps,
|
||||||
AllExecuteProps,
|
// AllExecuteProps,
|
||||||
EveryExecuteProps,
|
// EveryExecuteProps,
|
||||||
AnyExecuteProps,
|
// AnyExecuteProps,
|
||||||
ICoreModule,
|
// ICoreModule,
|
||||||
} from "./ModuleTypes";
|
// } from "./ModuleTypes";
|
||||||
|
|
||||||
function isOverridableKey(key: string): key is keyof ICoreModuleBase {
|
// function isOverridableKey(key: string): key is keyof ICoreModuleBase {
|
||||||
return key.startsWith("$");
|
// return key.startsWith("$");
|
||||||
}
|
// }
|
||||||
|
|
||||||
function isInjectableKey(key: string): key is keyof AllInjectableProps {
|
// function isInjectableKey(key: string): key is keyof AllInjectableProps {
|
||||||
return key.startsWith("$$");
|
// return key.startsWith("$$");
|
||||||
}
|
// }
|
||||||
|
|
||||||
function isAllExecuteKey(key: string): key is keyof AllExecuteProps {
|
// function isAllExecuteKey(key: string): key is keyof AllExecuteProps {
|
||||||
return key.startsWith("$all");
|
// return key.startsWith("$all");
|
||||||
}
|
// }
|
||||||
function isEveryExecuteKey(key: string): key is keyof EveryExecuteProps {
|
// function isEveryExecuteKey(key: string): key is keyof EveryExecuteProps {
|
||||||
return key.startsWith("$every");
|
// return key.startsWith("$every");
|
||||||
}
|
// }
|
||||||
function isAnyExecuteKey(key: string): key is keyof AnyExecuteProps {
|
// function isAnyExecuteKey(key: string): key is keyof AnyExecuteProps {
|
||||||
return key.startsWith("$any");
|
// return key.startsWith("$any");
|
||||||
}
|
// }
|
||||||
/**
|
/**
|
||||||
* All $prefixed functions are hooked by the modules. Be careful to call them directly.
|
* All $prefixed functions are hooked by the modules. Be careful to call them directly.
|
||||||
* Please refer to the module's source code to understand the function.
|
* Please refer to the module's source code to understand the function.
|
||||||
@@ -39,100 +39,100 @@ function isAnyExecuteKey(key: string): key is keyof AnyExecuteProps {
|
|||||||
* $ : Other interceptive points. You should manually assign the module
|
* $ : Other interceptive points. You should manually assign the module
|
||||||
* All of above performed on injectModules function.
|
* All of above performed on injectModules function.
|
||||||
*/
|
*/
|
||||||
export function injectModules<T extends ICoreModule>(target: T, modules: ICoreModule[]) {
|
// export function injectModules<T extends ICoreModule>(target: T, modules: ICoreModule[]) {
|
||||||
const allKeys = unique([
|
// const allKeys = unique([
|
||||||
...Object.keys(Object.getOwnPropertyDescriptors(target)),
|
// ...Object.keys(Object.getOwnPropertyDescriptors(target)),
|
||||||
...Object.keys(Object.getOwnPropertyDescriptors(Object.getPrototypeOf(target))),
|
// ...Object.keys(Object.getOwnPropertyDescriptors(Object.getPrototypeOf(target))),
|
||||||
]).filter((e) => e.startsWith("$")) as (keyof ICoreModule)[];
|
// ]).filter((e) => e.startsWith("$")) as (keyof ICoreModule)[];
|
||||||
const moduleMap = new Map<string, IObsidianModule[]>();
|
// const moduleMap = new Map<string, IObsidianModule[]>();
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
for (const key of allKeys) {
|
// for (const key of allKeys) {
|
||||||
if (isOverridableKey(key)) {
|
// if (isOverridableKey(key)) {
|
||||||
if (key in module) {
|
// if (key in module) {
|
||||||
const list = moduleMap.get(key) || [];
|
// const list = moduleMap.get(key) || [];
|
||||||
if (typeof module[key] === "function") {
|
// if (typeof module[key] === "function") {
|
||||||
module[key] = module[key].bind(module) as any;
|
// module[key] = module[key].bind(module) as any;
|
||||||
}
|
// }
|
||||||
list.push(module);
|
// list.push(module);
|
||||||
moduleMap.set(key, list);
|
// moduleMap.set(key, list);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Logger(`Injecting modules for ${target.constructor.name}`, LOG_LEVEL_VERBOSE);
|
// Logger(`Injecting modules for ${target.constructor.name}`, LOG_LEVEL_VERBOSE);
|
||||||
for (const key of allKeys) {
|
// for (const key of allKeys) {
|
||||||
const modules = moduleMap.get(key) || [];
|
// const modules = moduleMap.get(key) || [];
|
||||||
if (isInjectableKey(key)) {
|
// if (isInjectableKey(key)) {
|
||||||
if (modules.length == 0) {
|
// if (modules.length == 0) {
|
||||||
throw new Error(`No module injected for ${key}. This is a fatal error.`);
|
// throw new Error(`No module injected for ${key}. This is a fatal error.`);
|
||||||
}
|
// }
|
||||||
target[key] = modules[0][key]! as any;
|
// target[key] = modules[0][key]! as any;
|
||||||
Logger(`[${modules[0].constructor.name}]: Injected ${key} `, LOG_LEVEL_VERBOSE);
|
// Logger(`[${modules[0].constructor.name}]: Injected ${key} `, LOG_LEVEL_VERBOSE);
|
||||||
} else if (isAllExecuteKey(key)) {
|
// } else if (isAllExecuteKey(key)) {
|
||||||
const modules = moduleMap.get(key) || [];
|
// const modules = moduleMap.get(key) || [];
|
||||||
target[key] = async (...args: any) => {
|
// target[key] = async (...args: any) => {
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
try {
|
// try {
|
||||||
//@ts-ignore
|
// //@ts-ignore
|
||||||
await module[key]!(...args);
|
// await module[key]!(...args);
|
||||||
} catch (ex) {
|
// } catch (ex) {
|
||||||
Logger(`[${module.constructor.name}]: All handler for ${key} failed`, LOG_LEVEL_VERBOSE);
|
// Logger(`[${module.constructor.name}]: All handler for ${key} failed`, LOG_LEVEL_VERBOSE);
|
||||||
Logger(ex, LOG_LEVEL_VERBOSE);
|
// Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return true;
|
// return true;
|
||||||
};
|
// };
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
Logger(`[${module.constructor.name}]: Injected (All) ${key} `, LOG_LEVEL_VERBOSE);
|
// Logger(`[${module.constructor.name}]: Injected (All) ${key} `, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
} else if (isEveryExecuteKey(key)) {
|
// } else if (isEveryExecuteKey(key)) {
|
||||||
target[key] = async (...args: any) => {
|
// target[key] = async (...args: any) => {
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
try {
|
// try {
|
||||||
//@ts-ignore:2556
|
// //@ts-ignore:2556
|
||||||
const ret = await module[key]!(...args);
|
// const ret = await module[key]!(...args);
|
||||||
if (ret !== undefined && !ret) {
|
// if (ret !== undefined && !ret) {
|
||||||
// Failed then return that falsy value.
|
// // Failed then return that falsy value.
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
// }
|
||||||
} catch (ex) {
|
// } catch (ex) {
|
||||||
Logger(`[${module.constructor.name}]: Every handler for ${key} failed`);
|
// Logger(`[${module.constructor.name}]: Every handler for ${key} failed`);
|
||||||
Logger(ex, LOG_LEVEL_VERBOSE);
|
// Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return true;
|
// return true;
|
||||||
};
|
// };
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
Logger(`[${module.constructor.name}]: Injected (Every) ${key} `, LOG_LEVEL_VERBOSE);
|
// Logger(`[${module.constructor.name}]: Injected (Every) ${key} `, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
} else if (isAnyExecuteKey(key)) {
|
// } else if (isAnyExecuteKey(key)) {
|
||||||
//@ts-ignore
|
// //@ts-ignore
|
||||||
target[key] = async (...args: any[]) => {
|
// target[key] = async (...args: any[]) => {
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
try {
|
// try {
|
||||||
//@ts-ignore:2556
|
// //@ts-ignore:2556
|
||||||
const ret = await module[key](...args);
|
// const ret = await module[key](...args);
|
||||||
// If truly value returned, then return that value.
|
// // If truly value returned, then return that value.
|
||||||
if (ret) {
|
// if (ret) {
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
// }
|
||||||
} catch (ex) {
|
// } catch (ex) {
|
||||||
Logger(`[${module.constructor.name}]: Any handler for ${key} failed`);
|
// Logger(`[${module.constructor.name}]: Any handler for ${key} failed`);
|
||||||
Logger(ex, LOG_LEVEL_VERBOSE);
|
// Logger(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return false;
|
// return false;
|
||||||
};
|
// };
|
||||||
for (const module of modules) {
|
// for (const module of modules) {
|
||||||
Logger(`[${module.constructor.name}]: Injected (Any) ${key} `, LOG_LEVEL_VERBOSE);
|
// Logger(`[${module.constructor.name}]: Injected (Any) ${key} `, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
Logger(`No injected handler for ${key} `, LOG_LEVEL_VERBOSE);
|
// Logger(`No injected handler for ${key} `, LOG_LEVEL_VERBOSE);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Logger(`Injected modules for ${target.constructor.name}`, LOG_LEVEL_VERBOSE);
|
// Logger(`Injected modules for ${target.constructor.name}`, LOG_LEVEL_VERBOSE);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export abstract class AbstractModule {
|
export abstract class AbstractModule {
|
||||||
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
||||||
@@ -153,14 +153,17 @@ export abstract class AbstractModule {
|
|||||||
this.core.settings = value;
|
this.core.settings = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
|
// Override if needed.
|
||||||
|
}
|
||||||
constructor(public core: LiveSyncCore) {
|
constructor(public core: LiveSyncCore) {
|
||||||
|
this.onBindFunction(core, core.services);
|
||||||
Logger(`[${this.constructor.name}] Loaded`, LOG_LEVEL_VERBOSE);
|
Logger(`[${this.constructor.name}] Loaded`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
saveSettings = this.core.saveSettings.bind(this.core);
|
saveSettings = this.core.saveSettings.bind(this.core);
|
||||||
|
|
||||||
// abstract $everyTest(): Promise<boolean>;
|
|
||||||
addTestResult(key: string, value: boolean, summary?: string, message?: string) {
|
addTestResult(key: string, value: boolean, summary?: string, message?: string) {
|
||||||
this.core.$$addTestResult(`${this.constructor.name}`, key, value, summary, message);
|
this.services.test.addTestResult(`${this.constructor.name}`, key, value, summary, message);
|
||||||
}
|
}
|
||||||
testDone(result: boolean = true) {
|
testDone(result: boolean = true) {
|
||||||
return Promise.resolve(result);
|
return Promise.resolve(result);
|
||||||
@@ -185,4 +188,8 @@ export abstract class AbstractModule {
|
|||||||
}
|
}
|
||||||
return this.testDone();
|
return this.testDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get services() {
|
||||||
|
return this.core._services;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ export abstract class AbstractObsidianModule extends AbstractModule {
|
|||||||
saveSettings = this.plugin.saveSettings.bind(this.plugin);
|
saveSettings = this.plugin.saveSettings.bind(this.plugin);
|
||||||
|
|
||||||
_isMainReady() {
|
_isMainReady() {
|
||||||
return this.core.$$isReady();
|
return this.services.appLifecycle.isReady();
|
||||||
}
|
}
|
||||||
_isMainSuspended() {
|
_isMainSuspended() {
|
||||||
return this.core.$$isSuspended();
|
return this.services.appLifecycle.isSuspended();
|
||||||
}
|
}
|
||||||
_isDatabaseReady() {
|
_isDatabaseReady() {
|
||||||
return this.core.$$isDatabaseReady();
|
return this.services.database.isDatabaseReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
//should be overridden
|
//should be overridden
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import type {
|
|||||||
DocumentID,
|
DocumentID,
|
||||||
} from "../../lib/src/common/types";
|
} from "../../lib/src/common/types";
|
||||||
import type { DatabaseFileAccess } from "../interfaces/DatabaseFileAccess";
|
import type { DatabaseFileAccess } from "../interfaces/DatabaseFileAccess";
|
||||||
import { type IObsidianModule } from "../AbstractObsidianModule.ts";
|
|
||||||
import { isPlainText, shouldBeIgnored, stripAllPrefixes } from "../../lib/src/string_and_binary/path";
|
import { isPlainText, shouldBeIgnored, stripAllPrefixes } from "../../lib/src/string_and_binary/path";
|
||||||
import {
|
import {
|
||||||
createBlob,
|
createBlob,
|
||||||
@@ -30,14 +29,15 @@ import {
|
|||||||
import { serialized } from "octagonal-wheels/concurrency/lock";
|
import { serialized } from "octagonal-wheels/concurrency/lock";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import { ICHeader } from "../../common/types.ts";
|
import { ICHeader } from "../../common/types.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidianModule, DatabaseFileAccess {
|
export class ModuleDatabaseFileAccess extends AbstractModule implements DatabaseFileAccess {
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
this.core.databaseFileAccess = this;
|
this.core.databaseFileAccess = this;
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyModuleTest(): Promise<boolean> {
|
private async _everyModuleTest(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
const testString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec purus nec nunc";
|
const testString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec purus nec nunc";
|
||||||
// Before test, we need to delete completely.
|
// Before test, we need to delete completely.
|
||||||
@@ -75,7 +75,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
|
|||||||
|
|
||||||
async checkIsTargetFile(file: UXFileInfoStub | FilePathWithPrefix): Promise<boolean> {
|
async checkIsTargetFile(file: UXFileInfoStub | FilePathWithPrefix): Promise<boolean> {
|
||||||
const path = getStoragePathFromUXFileInfo(file);
|
const path = getStoragePathFromUXFileInfo(file);
|
||||||
if (!(await this.core.$$isTargetFile(path))) {
|
if (!(await this.services.vault.isTargetFile(path))) {
|
||||||
this._log(`File is not target`, LOG_LEVEL_VERBOSE);
|
this._log(`File is not target`, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const idMain = await this.core.$$path2id(fullPath);
|
const idMain = await this.services.path.path2id(fullPath);
|
||||||
|
|
||||||
const id = (idPrefix + idMain) as DocumentID;
|
const id = (idPrefix + idMain) as DocumentID;
|
||||||
const d: SavingEntry = {
|
const d: SavingEntry = {
|
||||||
@@ -345,4 +345,8 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
|
|||||||
eventHub.emitEvent(EVENT_FILE_SAVED);
|
eventHub.emitEvent(EVENT_FILE_SAVED);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.test.handleTest(this._everyModuleTest.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ import {
|
|||||||
} from "../../common/utils";
|
} from "../../common/utils";
|
||||||
import { getDocDataAsArray, isDocContentSame, readAsBlob, readContent } from "../../lib/src/common/utils";
|
import { getDocDataAsArray, isDocContentSame, readAsBlob, readContent } from "../../lib/src/common/utils";
|
||||||
import { shouldBeIgnored } from "../../lib/src/string_and_binary/path";
|
import { shouldBeIgnored } from "../../lib/src/string_and_binary/path";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
||||||
import { eventHub } from "../../common/events.ts";
|
import { eventHub } from "../../common/events.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
export class ModuleFileHandler extends AbstractModule {
|
||||||
get db() {
|
get db() {
|
||||||
return this.core.databaseFileAccess;
|
return this.core.databaseFileAccess;
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
return this.core.storageAccess;
|
return this.core.storageAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.core.fileHandler = this;
|
this.core.fileHandler = this;
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
info: UXFileInfoStub | UXFileInfo | UXInternalFileInfoStub | FilePathWithPrefix,
|
info: UXFileInfoStub | UXFileInfo | UXInternalFileInfoStub | FilePathWithPrefix,
|
||||||
force: boolean = false,
|
force: boolean = false,
|
||||||
onlyChunks: boolean = false
|
onlyChunks: boolean = false
|
||||||
): Promise<boolean | undefined> {
|
): Promise<boolean> {
|
||||||
const file = typeof info === "string" ? this.storage.getFileStub(info) : info;
|
const file = typeof info === "string" ? this.storage.getFileStub(info) : info;
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
this._log(`File ${info} is not exist on the storage`, LOG_LEVEL_VERBOSE);
|
this._log(`File ${info} is not exist on the storage`, LOG_LEVEL_VERBOSE);
|
||||||
@@ -125,7 +125,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFileFromDB(info: UXFileInfoStub | UXInternalFileInfoStub | FilePath): Promise<boolean | undefined> {
|
async deleteFileFromDB(info: UXFileInfoStub | UXInternalFileInfoStub | FilePath): Promise<boolean> {
|
||||||
const file = typeof info === "string" ? this.storage.getFileStub(info) : info;
|
const file = typeof info === "string" ? this.storage.getFileStub(info) : info;
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
this._log(`File ${info} is not exist on the storage`, LOG_LEVEL_VERBOSE);
|
this._log(`File ${info} is not exist on the storage`, LOG_LEVEL_VERBOSE);
|
||||||
@@ -222,7 +222,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
// NO OP
|
// NO OP
|
||||||
} else {
|
} else {
|
||||||
// If not, then it should be checked. and will be processed later (i.e., after the conflict is resolved).
|
// If not, then it should be checked. and will be processed later (i.e., after the conflict is resolved).
|
||||||
await this.core.$$queueConflictCheckIfOpen(path);
|
await this.services.conflict.queueCheckForIfOpen(path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,11 +313,11 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyHandlerProcessesFileEvent(item: FileEventItem): Promise<boolean | undefined> {
|
private async _anyHandlerProcessesFileEvent(item: FileEventItem): Promise<boolean> {
|
||||||
const eventItem = item.args;
|
const eventItem = item.args;
|
||||||
const type = item.type;
|
const type = item.type;
|
||||||
const path = eventItem.file.path;
|
const path = eventItem.file.path;
|
||||||
if (!(await this.core.$$isTargetFile(path))) {
|
if (!(await this.services.vault.isTargetFile(path))) {
|
||||||
this._log(`File ${path} is not the target file`, LOG_LEVEL_VERBOSE);
|
this._log(`File ${path} is not the target file`, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -343,9 +343,9 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyProcessReplicatedDoc(entry: MetaEntry): Promise<boolean | undefined> {
|
async _anyProcessReplicatedDoc(entry: MetaEntry): Promise<boolean> {
|
||||||
return await serialized(entry.path, async () => {
|
return await serialized(entry.path, async () => {
|
||||||
if (!(await this.core.$$isTargetFile(entry.path))) {
|
if (!(await this.services.vault.isTargetFile(entry.path))) {
|
||||||
this._log(`File ${entry.path} is not the target file`, LOG_LEVEL_VERBOSE);
|
this._log(`File ${entry.path} is not the target file`, LOG_LEVEL_VERBOSE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -362,7 +362,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
this._log(
|
this._log(
|
||||||
`Processing ${path} (${entry._id.substring(0, 8)}: ${entry._rev?.substring(0, 5)}) :Started...`,
|
`Processing ${path} (${entry._id.substring(0, 8)} :${entry._rev?.substring(0, 5)}) : Started...`,
|
||||||
LOG_LEVEL_VERBOSE
|
LOG_LEVEL_VERBOSE
|
||||||
);
|
);
|
||||||
// Before writing (or skipped ), merging dialogue should be cancelled.
|
// Before writing (or skipped ), merging dialogue should be cancelled.
|
||||||
@@ -391,7 +391,7 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
};
|
};
|
||||||
const total = filesStorageSrc.length;
|
const total = filesStorageSrc.length;
|
||||||
const procAllChunks = filesStorageSrc.map(async (file) => {
|
const procAllChunks = filesStorageSrc.map(async (file) => {
|
||||||
if (!(await this.core.$$isTargetFile(file))) {
|
if (!(await this.services.vault.isTargetFile(file))) {
|
||||||
incProcessed();
|
incProcessed();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -416,4 +416,9 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
|
|||||||
"chunkCreation"
|
"chunkCreation"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.fileProcessing.handleProcessFileEvent(this._anyHandlerProcessesFileEvent.bind(this));
|
||||||
|
services.replication.handleProcessSynchroniseResult(this._anyProcessReplicatedDoc.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ import { $msg } from "../../lib/src/common/i18n";
|
|||||||
import { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
import { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||||
import { initializeStores } from "../../common/stores.ts";
|
import { initializeStores } from "../../common/stores.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { LiveSyncManagers } from "../../lib/src/managers/LiveSyncManagers.ts";
|
import { LiveSyncManagers } from "../../lib/src/managers/LiveSyncManagers.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleLocalDatabaseObsidian extends AbstractModule implements ICoreModule {
|
export class ModuleLocalDatabaseObsidian extends AbstractModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
async $$openDatabase(): Promise<boolean> {
|
private async _openDatabase(): Promise<boolean> {
|
||||||
if (this.localDatabase != null) {
|
if (this.localDatabase != null) {
|
||||||
await this.localDatabase.close();
|
await this.localDatabase.close();
|
||||||
}
|
}
|
||||||
const vaultName = this.core.$$getVaultName();
|
const vaultName = this.services.vault.getVaultName();
|
||||||
this._log($msg("moduleLocalDatabase.logWaitingForReady"));
|
this._log($msg("moduleLocalDatabase.logWaitingForReady"));
|
||||||
const getDB = () => this.core.localDatabase.localDatabase;
|
const getDB = () => this.core.localDatabase.localDatabase;
|
||||||
const getSettings = () => this.core.settings;
|
const getSettings = () => this.core.settings;
|
||||||
@@ -22,8 +22,9 @@ export class ModuleLocalDatabaseObsidian extends AbstractModule implements ICore
|
|||||||
return getDB();
|
return getDB();
|
||||||
},
|
},
|
||||||
getActiveReplicator: () => this.core.replicator,
|
getActiveReplicator: () => this.core.replicator,
|
||||||
id2path: this.core.$$id2path.bind(this.core),
|
id2path: this.services.path.id2path,
|
||||||
path2id: this.core.$$path2id.bind(this.core),
|
// path2id: this.core.$$path2id.bind(this.core),
|
||||||
|
path2id: this.services.path.path2id,
|
||||||
get settings() {
|
get settings() {
|
||||||
return getSettings();
|
return getSettings();
|
||||||
},
|
},
|
||||||
@@ -34,7 +35,12 @@ export class ModuleLocalDatabaseObsidian extends AbstractModule implements ICore
|
|||||||
return await this.localDatabase.initializeDatabase();
|
return await this.localDatabase.initializeDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
$$isDatabaseReady(): boolean {
|
_isDatabaseReady(): boolean {
|
||||||
return this.localDatabase != null && this.localDatabase.isReady;
|
return this.localDatabase != null && this.localDatabase.isReady;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.database.handleIsDatabaseReady(this._isDatabaseReady.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.database.handleOpenDatabase(this._openDatabase.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { PeriodicProcessor } from "../../common/utils";
|
import { PeriodicProcessor } from "../../common/utils";
|
||||||
|
import type { LiveSyncCore } from "../../main";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
|
|
||||||
export class ModulePeriodicProcess extends AbstractModule implements ICoreModule {
|
export class ModulePeriodicProcess extends AbstractModule {
|
||||||
periodicSyncProcessor = new PeriodicProcessor(this.core, async () => await this.core.$$replicate());
|
periodicSyncProcessor = new PeriodicProcessor(this.core, async () => await this.services.replication.replicate());
|
||||||
|
|
||||||
_disablePeriodic() {
|
_disablePeriodic() {
|
||||||
this.periodicSyncProcessor?.disable();
|
this.periodicSyncProcessor?.disable();
|
||||||
@@ -15,19 +15,27 @@ export class ModulePeriodicProcess extends AbstractModule implements ICoreModule
|
|||||||
);
|
);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$allOnUnload() {
|
private _allOnUnload() {
|
||||||
return this._disablePeriodic();
|
return this._disablePeriodic();
|
||||||
}
|
}
|
||||||
$everyBeforeRealizeSetting(): Promise<boolean> {
|
_everyBeforeRealizeSetting(): Promise<boolean> {
|
||||||
return this._disablePeriodic();
|
return this._disablePeriodic();
|
||||||
}
|
}
|
||||||
$everyBeforeSuspendProcess(): Promise<boolean> {
|
_everyBeforeSuspendProcess(): Promise<boolean> {
|
||||||
return this._disablePeriodic();
|
return this._disablePeriodic();
|
||||||
}
|
}
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
_everyAfterResumeProcess(): Promise<boolean> {
|
||||||
return this._resumePeriodic();
|
return this._resumePeriodic();
|
||||||
}
|
}
|
||||||
$everyAfterRealizeSetting(): Promise<boolean> {
|
_everyAfterRealizeSetting(): Promise<boolean> {
|
||||||
return this._resumePeriodic();
|
return this._resumePeriodic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnUnload(this._allOnUnload.bind(this));
|
||||||
|
services.setting.handleBeforeRealiseSetting(this._everyBeforeRealizeSetting.bind(this));
|
||||||
|
services.setting.handleSettingRealised(this._everyAfterRealizeSetting.bind(this));
|
||||||
|
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
||||||
|
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||||
|
import type { LiveSyncCore } from "../../main";
|
||||||
|
|
||||||
export class ModulePouchDB extends AbstractModule implements ICoreModule {
|
export class ModulePouchDB extends AbstractModule {
|
||||||
$$createPouchDBInstance<T extends object>(
|
_createPouchDBInstance<T extends object>(
|
||||||
name?: string,
|
name?: string,
|
||||||
options?: PouchDB.Configuration.DatabaseConfiguration
|
options?: PouchDB.Configuration.DatabaseConfiguration
|
||||||
): PouchDB.Database<T> {
|
): PouchDB.Database<T> {
|
||||||
@@ -16,4 +16,7 @@ export class ModulePouchDB extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return new PouchDB(name, optionPass);
|
return new PouchDB(name, optionPass);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.database.handleCreatePouchDBInstance(this._createPouchDBInstance.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import {
|
|||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { Rebuilder } from "../interfaces/DatabaseRebuilder.ts";
|
import type { Rebuilder } from "../interfaces/DatabaseRebuilder.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import type { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator.ts";
|
import type { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator.ts";
|
||||||
import { fetchAllUsedChunks } from "@/lib/src/pouchdb/chunks.ts";
|
import { fetchAllUsedChunks } from "@/lib/src/pouchdb/chunks.ts";
|
||||||
import { EVENT_DATABASE_REBUILT, eventHub } from "src/common/events.ts";
|
import { EVENT_DATABASE_REBUILT, eventHub } from "src/common/events.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebuilder {
|
export class ModuleRebuilder extends AbstractModule implements Rebuilder {
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
this.core.rebuilder = this;
|
this.core.rebuilder = this;
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
@@ -43,47 +43,47 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
{ title: "Enable extra features", defaultOption: "No", timeout: 15 }
|
{ title: "Enable extra features", defaultOption: "No", timeout: 15 }
|
||||||
)) == "yes"
|
)) == "yes"
|
||||||
) {
|
) {
|
||||||
await this.core.$allAskUsingOptionalSyncFeature(opt);
|
await this.services.setting.suggestOptionalFeatures(opt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async rebuildRemote() {
|
async rebuildRemote() {
|
||||||
await this.core.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
this.core.settings.isConfigured = true;
|
this.core.settings.isConfigured = true;
|
||||||
|
|
||||||
await this.core.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.core.$$markRemoteLocked();
|
await this.services.remote.markLocked();
|
||||||
await this.core.$$tryResetRemoteDatabase();
|
await this.services.remote.tryResetDatabase();
|
||||||
await this.core.$$markRemoteLocked();
|
await this.services.remote.markLocked();
|
||||||
await delay(500);
|
await delay(500);
|
||||||
await this.askUsingOptionalFeature({ enableOverwrite: true });
|
await this.askUsingOptionalFeature({ enableOverwrite: true });
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$replicateAllToServer(true);
|
await this.services.remote.replicateAllToRemote(true);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$replicateAllToServer(true, true);
|
await this.services.remote.replicateAllToRemote(true, true);
|
||||||
}
|
}
|
||||||
$rebuildRemote(): Promise<void> {
|
$rebuildRemote(): Promise<void> {
|
||||||
return this.rebuildRemote();
|
return this.rebuildRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
async rebuildEverything() {
|
async rebuildEverything() {
|
||||||
await this.core.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
await this.askUseNewAdapter();
|
await this.askUseNewAdapter();
|
||||||
this.core.settings.isConfigured = true;
|
this.core.settings.isConfigured = true;
|
||||||
await this.core.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$initializeDatabase(true, true, true);
|
await this.services.databaseEvents.initialiseDatabase(true, true, true);
|
||||||
await this.core.$$markRemoteLocked();
|
await this.services.remote.markLocked();
|
||||||
await this.core.$$tryResetRemoteDatabase();
|
await this.services.remote.tryResetDatabase();
|
||||||
await this.core.$$markRemoteLocked();
|
await this.services.remote.markLocked();
|
||||||
await delay(500);
|
await delay(500);
|
||||||
// We do not have any other devices' data, so we do not need to ask for overwriting.
|
// We do not have any other devices' data, so we do not need to ask for overwriting.
|
||||||
await this.askUsingOptionalFeature({ enableOverwrite: false });
|
await this.askUsingOptionalFeature({ enableOverwrite: false });
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$replicateAllToServer(true);
|
await this.services.remote.replicateAllToRemote(true);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$replicateAllToServer(true, true);
|
await this.services.remote.replicateAllToRemote(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rebuildEverything(): Promise<void> {
|
$rebuildEverything(): Promise<void> {
|
||||||
@@ -101,7 +101,7 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
this._log("Could not create red_flag_rebuild.md", LOG_LEVEL_NOTICE);
|
this._log("Could not create red_flag_rebuild.md", LOG_LEVEL_NOTICE);
|
||||||
this._log(ex, LOG_LEVEL_VERBOSE);
|
this._log(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
}
|
}
|
||||||
async scheduleFetch(): Promise<void> {
|
async scheduleFetch(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -110,20 +110,20 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
this._log("Could not create red_flag_fetch.md", LOG_LEVEL_NOTICE);
|
this._log("Could not create red_flag_fetch.md", LOG_LEVEL_NOTICE);
|
||||||
this._log(ex, LOG_LEVEL_VERBOSE);
|
this._log(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$tryResetRemoteDatabase(): Promise<void> {
|
private async _tryResetRemoteDatabase(): Promise<void> {
|
||||||
await this.core.replicator.tryResetRemoteDatabase(this.settings);
|
await this.core.replicator.tryResetRemoteDatabase(this.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$tryCreateRemoteDatabase(): Promise<void> {
|
private async _tryCreateRemoteDatabase(): Promise<void> {
|
||||||
await this.core.replicator.tryCreateRemoteDatabase(this.settings);
|
await this.core.replicator.tryCreateRemoteDatabase(this.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$resetLocalDatabase(): Promise<void> {
|
private async _resetLocalDatabase(): Promise<boolean> {
|
||||||
this.core.storageAccess.clearTouched();
|
this.core.storageAccess.clearTouched();
|
||||||
await this.localDatabase.resetDatabase();
|
return await this.localDatabase.resetDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
async suspendAllSync() {
|
async suspendAllSync() {
|
||||||
@@ -134,7 +134,7 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
this.core.settings.syncOnStart = false;
|
this.core.settings.syncOnStart = false;
|
||||||
this.core.settings.syncOnFileOpen = false;
|
this.core.settings.syncOnFileOpen = false;
|
||||||
this.core.settings.syncAfterMerge = false;
|
this.core.settings.syncAfterMerge = false;
|
||||||
await this.core.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
}
|
}
|
||||||
async suspendReflectingDatabase() {
|
async suspendReflectingDatabase() {
|
||||||
if (this.core.settings.doNotSuspendOnFetching) return;
|
if (this.core.settings.doNotSuspendOnFetching) return;
|
||||||
@@ -153,8 +153,8 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
this._log(`Database and storage reflection has been resumed!`, LOG_LEVEL_NOTICE);
|
this._log(`Database and storage reflection has been resumed!`, LOG_LEVEL_NOTICE);
|
||||||
this.core.settings.suspendParseReplicationResult = false;
|
this.core.settings.suspendParseReplicationResult = false;
|
||||||
this.core.settings.suspendFileWatching = false;
|
this.core.settings.suspendFileWatching = false;
|
||||||
await this.core.$$performFullScan(true);
|
await this.services.vault.scanVault(true);
|
||||||
await this.core.$everyBeforeReplicate(false); //TODO: Check actual need of this.
|
await this.services.replication.onBeforeReplicate(false); //TODO: Check actual need of this.
|
||||||
await this.core.saveSettings();
|
await this.core.saveSettings();
|
||||||
}
|
}
|
||||||
async askUseNewAdapter() {
|
async askUseNewAdapter() {
|
||||||
@@ -177,28 +177,28 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean) {
|
async fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean) {
|
||||||
await this.core.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
await this.askUseNewAdapter();
|
await this.askUseNewAdapter();
|
||||||
this.core.settings.isConfigured = true;
|
this.core.settings.isConfigured = true;
|
||||||
await this.suspendReflectingDatabase();
|
await this.suspendReflectingDatabase();
|
||||||
await this.core.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$openDatabase();
|
await this.services.database.openDatabase();
|
||||||
// this.core.isReady = true;
|
// this.core.isReady = true;
|
||||||
this.core.$$markIsReady();
|
this.services.appLifecycle.markIsReady();
|
||||||
if (makeLocalChunkBeforeSync) {
|
if (makeLocalChunkBeforeSync) {
|
||||||
await this.core.fileHandler.createAllChunks(true);
|
await this.core.fileHandler.createAllChunks(true);
|
||||||
} else if (!preventMakeLocalFilesBeforeSync) {
|
} else if (!preventMakeLocalFilesBeforeSync) {
|
||||||
await this.core.$$initializeDatabase(true, true, true);
|
await this.services.databaseEvents.initialiseDatabase(true, true, true);
|
||||||
} else {
|
} else {
|
||||||
// Do not create local file entries before sync (Means use remote information)
|
// Do not create local file entries before sync (Means use remote information)
|
||||||
}
|
}
|
||||||
await this.core.$$markRemoteResolved();
|
await this.services.remote.markResolved();
|
||||||
await delay(500);
|
await delay(500);
|
||||||
await this.core.$$replicateAllFromServer(true);
|
await this.services.remote.replicateAllFromRemote(true);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.core.$$replicateAllFromServer(true);
|
await this.services.remote.replicateAllFromRemote(true);
|
||||||
await this.resumeReflectingDatabase();
|
await this.resumeReflectingDatabase();
|
||||||
await this.askUsingOptionalFeature({ enableFetch: true });
|
await this.askUsingOptionalFeature({ enableFetch: true });
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,7 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
return await this.fetchLocal(true);
|
return await this.fetchLocal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $allSuspendAllSync(): Promise<boolean> {
|
private async _allSuspendAllSync(): Promise<boolean> {
|
||||||
await this.suspendAllSync();
|
await this.suspendAllSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -214,11 +214,11 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
async resetLocalDatabase() {
|
async resetLocalDatabase() {
|
||||||
if (this.core.settings.isConfigured && this.core.settings.additionalSuffixOfDatabaseName == "") {
|
if (this.core.settings.isConfigured && this.core.settings.additionalSuffixOfDatabaseName == "") {
|
||||||
// Discard the non-suffixed database
|
// Discard the non-suffixed database
|
||||||
await this.core.$$resetLocalDatabase();
|
await this.services.database.resetDatabase();
|
||||||
}
|
}
|
||||||
const suffix = (await this.core.$anyGetAppId()) || "";
|
const suffix = this.services.API.getAppID() || "";
|
||||||
this.core.settings.additionalSuffixOfDatabaseName = suffix;
|
this.core.settings.additionalSuffixOfDatabaseName = suffix;
|
||||||
await this.core.$$resetLocalDatabase();
|
await this.services.database.resetDatabase();
|
||||||
eventHub.emitEvent(EVENT_DATABASE_REBUILT);
|
eventHub.emitEvent(EVENT_DATABASE_REBUILT);
|
||||||
}
|
}
|
||||||
async fetchRemoteChunks() {
|
async fetchRemoteChunks() {
|
||||||
@@ -228,10 +228,10 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
this.core.settings.remoteType == REMOTE_COUCHDB
|
this.core.settings.remoteType == REMOTE_COUCHDB
|
||||||
) {
|
) {
|
||||||
this._log(`Fetching chunks`, LOG_LEVEL_NOTICE);
|
this._log(`Fetching chunks`, LOG_LEVEL_NOTICE);
|
||||||
const replicator = this.core.$$getReplicator() as LiveSyncCouchDBReplicator;
|
const replicator = this.services.replicator.getActiveReplicator() as LiveSyncCouchDBReplicator;
|
||||||
const remoteDB = await replicator.connectRemoteCouchDBWithSetting(
|
const remoteDB = await replicator.connectRemoteCouchDBWithSetting(
|
||||||
this.settings,
|
this.settings,
|
||||||
this.core.$$isMobile(),
|
this.services.API.isMobile(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
if (typeof remoteDB == "string") {
|
if (typeof remoteDB == "string") {
|
||||||
@@ -254,8 +254,15 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
|
|||||||
LOG_LEVEL_NOTICE,
|
LOG_LEVEL_NOTICE,
|
||||||
"resolveAllConflictedFilesByNewerOnes"
|
"resolveAllConflictedFilesByNewerOnes"
|
||||||
);
|
);
|
||||||
await this.core.$anyResolveConflictByNewest(file);
|
await this.services.conflict.resolveByNewest(file);
|
||||||
}
|
}
|
||||||
this._log(`Done!`, LOG_LEVEL_NOTICE, "resolveAllConflictedFilesByNewerOnes");
|
this._log(`Done!`, LOG_LEVEL_NOTICE, "resolveAllConflictedFilesByNewerOnes");
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.database.handleResetDatabase(this._resetLocalDatabase.bind(this));
|
||||||
|
services.remote.handleTryResetDatabase(this._tryResetRemoteDatabase.bind(this));
|
||||||
|
services.remote.handleTryCreateDatabase(this._tryCreateRemoteDatabase.bind(this));
|
||||||
|
services.setting.handleSuspendAllSync(this._allSuspendAllSync.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { fireAndForget, yieldMicrotask } from "octagonal-wheels/promises";
|
import { fireAndForget, yieldMicrotask } from "octagonal-wheels/promises";
|
||||||
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB";
|
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
import { Logger, LOG_LEVEL_NOTICE, LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { Logger, LOG_LEVEL_NOTICE, LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { isLockAcquired, shareRunningResult, skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
|
import { isLockAcquired, shareRunningResult, skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
|
||||||
import { balanceChunkPurgedDBs } from "@/lib/src/pouchdb/chunks";
|
import { balanceChunkPurgedDBs } from "@/lib/src/pouchdb/chunks";
|
||||||
@@ -34,17 +33,18 @@ import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveS
|
|||||||
|
|
||||||
import { $msg } from "../../lib/src/common/i18n";
|
import { $msg } from "../../lib/src/common/i18n";
|
||||||
import { clearHandlers } from "../../lib/src/replication/SyncParamsHandler";
|
import { clearHandlers } from "../../lib/src/replication/SyncParamsHandler";
|
||||||
|
import type { LiveSyncCore } from "../../main";
|
||||||
|
|
||||||
const KEY_REPLICATION_ON_EVENT = "replicationOnEvent";
|
const KEY_REPLICATION_ON_EVENT = "replicationOnEvent";
|
||||||
const REPLICATION_ON_EVENT_FORECASTED_TIME = 5000;
|
const REPLICATION_ON_EVENT_FORECASTED_TIME = 5000;
|
||||||
|
|
||||||
export class ModuleReplicator extends AbstractModule implements ICoreModule {
|
export class ModuleReplicator extends AbstractModule {
|
||||||
_replicatorType?: RemoteType;
|
_replicatorType?: RemoteType;
|
||||||
|
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
eventHub.onEvent(EVENT_FILE_SAVED, () => {
|
eventHub.onEvent(EVENT_FILE_SAVED, () => {
|
||||||
if (this.settings.syncOnSave && !this.core.$$isSuspended()) {
|
if (this.settings.syncOnSave && !this.core.services.appLifecycle.isSuspended()) {
|
||||||
scheduleTask("perform-replicate-after-save", 250, () => this.core.$$replicateByEvent());
|
scheduleTask("perform-replicate-after-save", 250, () => this.services.replication.replicateByEvent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
eventHub.onEvent(EVENT_SETTING_SAVED, (setting) => {
|
eventHub.onEvent(EVENT_SETTING_SAVED, (setting) => {
|
||||||
@@ -57,7 +57,7 @@ export class ModuleReplicator extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setReplicator() {
|
async setReplicator() {
|
||||||
const replicator = await this.core.$anyNewReplicator();
|
const replicator = await this.services.replicator.getNewReplicator();
|
||||||
if (!replicator) {
|
if (!replicator) {
|
||||||
this._log($msg("Replicator.Message.InitialiseFatalError"), LOG_LEVEL_NOTICE);
|
this._log($msg("Replicator.Message.InitialiseFatalError"), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
@@ -74,24 +74,28 @@ export class ModuleReplicator extends AbstractModule implements ICoreModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$getReplicator(): LiveSyncAbstractReplicator {
|
_getReplicator(): LiveSyncAbstractReplicator {
|
||||||
return this.core.replicator;
|
return this.core.replicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
_everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
return this.setReplicator();
|
return this.setReplicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
_everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
return this.setReplicator();
|
return this.setReplicator();
|
||||||
}
|
}
|
||||||
async ensureReplicatorPBKDF2Salt(showMessage: boolean = false): Promise<boolean> {
|
async ensureReplicatorPBKDF2Salt(showMessage: boolean = false): Promise<boolean> {
|
||||||
// Checking salt
|
// Checking salt
|
||||||
const replicator = this.core.$$getReplicator();
|
const replicator = this.services.replicator.getActiveReplicator();
|
||||||
|
if (!replicator) {
|
||||||
|
this._log($msg("Replicator.Message.InitialiseFatalError"), LOG_LEVEL_NOTICE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return await replicator.ensurePBKDF2Salt(this.settings, showMessage, true);
|
return await replicator.ensurePBKDF2Salt(this.settings, showMessage, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
async _everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
||||||
// Checking salt
|
// Checking salt
|
||||||
if (!this.core.managers.networkManager.isOnline) {
|
if (!this.core.managers.networkManager.isOnline) {
|
||||||
this._log("Network is offline", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
this._log("Network is offline", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
||||||
@@ -106,7 +110,7 @@ export class ModuleReplicator extends AbstractModule implements ICoreModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$replicate(showMessage: boolean = false): Promise<boolean | void> {
|
private async _replicate(showMessage: boolean = false): Promise<boolean | void> {
|
||||||
try {
|
try {
|
||||||
updatePreviousExecutionTime(KEY_REPLICATION_ON_EVENT, REPLICATION_ON_EVENT_FORECASTED_TIME);
|
updatePreviousExecutionTime(KEY_REPLICATION_ON_EVENT, REPLICATION_ON_EVENT_FORECASTED_TIME);
|
||||||
return await this.$$_replicate(showMessage);
|
return await this.$$_replicate(showMessage);
|
||||||
@@ -143,11 +147,11 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
await this.core.rebuilder.$performRebuildDB("localOnly");
|
await this.core.rebuilder.$performRebuildDB("localOnly");
|
||||||
}
|
}
|
||||||
if (ret == CHOICE_CLEAN) {
|
if (ret == CHOICE_CLEAN) {
|
||||||
const replicator = this.core.$$getReplicator();
|
const replicator = this.services.replicator.getActiveReplicator();
|
||||||
if (!(replicator instanceof LiveSyncCouchDBReplicator)) return;
|
if (!(replicator instanceof LiveSyncCouchDBReplicator)) return;
|
||||||
const remoteDB = await replicator.connectRemoteCouchDBWithSetting(
|
const remoteDB = await replicator.connectRemoteCouchDBWithSetting(
|
||||||
this.settings,
|
this.settings,
|
||||||
this.core.$$isMobile(),
|
this.services.API.isMobile(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
if (typeof remoteDB == "string") {
|
if (typeof remoteDB == "string") {
|
||||||
@@ -162,7 +166,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
await balanceChunkPurgedDBs(this.localDatabase.localDatabase, remoteDB.db);
|
await balanceChunkPurgedDBs(this.localDatabase.localDatabase, remoteDB.db);
|
||||||
await purgeUnreferencedChunks(this.localDatabase.localDatabase, false);
|
await purgeUnreferencedChunks(this.localDatabase.localDatabase, false);
|
||||||
this.localDatabase.clearCaches();
|
this.localDatabase.clearCaches();
|
||||||
await this.core.$$getReplicator().markRemoteResolved(this.settings);
|
await this.services.replicator.getActiveReplicator()?.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(
|
Logger(
|
||||||
@@ -174,8 +178,8 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$canReplicate(showMessage: boolean = false): Promise<boolean> {
|
async _canReplicate(showMessage: boolean = false): Promise<boolean> {
|
||||||
if (!this.core.$$isReady()) {
|
if (!this.services.appLifecycle.isReady()) {
|
||||||
Logger(`Not ready`);
|
Logger(`Not ready`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -190,7 +194,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.core.$everyCommitPendingFileEvent())) {
|
if (!(await this.services.fileProcessing.commitPendingFileEvents())) {
|
||||||
Logger($msg("Replicator.Message.Pending"), LOG_LEVEL_NOTICE);
|
Logger($msg("Replicator.Message.Pending"), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -199,7 +203,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
this._log("Network is offline", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
this._log("Network is offline", showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(await this.core.$everyBeforeReplicate(showMessage))) {
|
if (!(await this.services.replication.onBeforeReplicate(showMessage))) {
|
||||||
Logger($msg("Replicator.Message.SomeModuleFailed"), LOG_LEVEL_NOTICE);
|
Logger($msg("Replicator.Message.SomeModuleFailed"), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -207,14 +211,14 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
}
|
}
|
||||||
|
|
||||||
async $$_replicate(showMessage: boolean = false): Promise<boolean | void> {
|
async $$_replicate(showMessage: boolean = false): Promise<boolean | void> {
|
||||||
const checkBeforeReplicate = await this.$$canReplicate(showMessage);
|
const checkBeforeReplicate = await this.services.replication.isReplicationReady(showMessage);
|
||||||
if (!checkBeforeReplicate) return false;
|
if (!checkBeforeReplicate) return false;
|
||||||
|
|
||||||
//<-- Here could be an module.
|
//<-- Here could be an module.
|
||||||
const ret = await this.core.replicator.openReplication(this.settings, false, showMessage, false);
|
const ret = await this.core.replicator.openReplication(this.settings, false, showMessage, false);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (this.core.replicator.tweakSettingsMismatched && this.core.replicator.preferredTweakValue) {
|
if (this.core.replicator.tweakSettingsMismatched && this.core.replicator.preferredTweakValue) {
|
||||||
await this.core.$$askResolvingMismatchedTweaks(this.core.replicator.preferredTweakValue);
|
await this.services.tweakValue.askResolvingMismatched(this.core.replicator.preferredTweakValue);
|
||||||
} else {
|
} else {
|
||||||
if (this.core.replicator?.remoteLockedAndDeviceNotAccepted) {
|
if (this.core.replicator?.remoteLockedAndDeviceNotAccepted) {
|
||||||
if (this.core.replicator.remoteCleaned && this.settings.useIndexedDBAdapter) {
|
if (this.core.replicator.remoteCleaned && this.settings.useIndexedDBAdapter) {
|
||||||
@@ -236,7 +240,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
if (ret == CHOICE_FETCH) {
|
if (ret == CHOICE_FETCH) {
|
||||||
this._log($msg("Replicator.Dialogue.Locked.Message.Fetch"), LOG_LEVEL_NOTICE);
|
this._log($msg("Replicator.Dialogue.Locked.Message.Fetch"), LOG_LEVEL_NOTICE);
|
||||||
await this.core.rebuilder.scheduleFetch();
|
await this.core.rebuilder.scheduleFetch();
|
||||||
this.core.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
return;
|
return;
|
||||||
} else if (ret == CHOICE_UNLOCK) {
|
} else if (ret == CHOICE_UNLOCK) {
|
||||||
await this.core.replicator.markRemoteResolved(this.settings);
|
await this.core.replicator.markRemoteResolved(this.settings);
|
||||||
@@ -250,16 +254,16 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$replicateByEvent(): Promise<boolean | void> {
|
private async _replicateByEvent(): Promise<boolean | void> {
|
||||||
const least = this.settings.syncMinimumInterval;
|
const least = this.settings.syncMinimumInterval;
|
||||||
if (least > 0) {
|
if (least > 0) {
|
||||||
return rateLimitedSharedExecution(KEY_REPLICATION_ON_EVENT, least, async () => {
|
return rateLimitedSharedExecution(KEY_REPLICATION_ON_EVENT, least, async () => {
|
||||||
return await this.$$replicate();
|
return await this.services.replication.replicate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return await shareRunningResult(`replication`, () => this.core.$$replicate());
|
return await shareRunningResult(`replication`, () => this.services.replication.replicate());
|
||||||
}
|
}
|
||||||
$$parseReplicationResult(docs: Array<PouchDB.Core.ExistingDocument<EntryDoc>>): void {
|
_parseReplicationResult(docs: Array<PouchDB.Core.ExistingDocument<EntryDoc>>): void {
|
||||||
if (this.settings.suspendParseReplicationResult && !this.replicationResultProcessor.isSuspended) {
|
if (this.settings.suspendParseReplicationResult && !this.replicationResultProcessor.isSuspended) {
|
||||||
this.replicationResultProcessor.suspend();
|
this.replicationResultProcessor.suspend();
|
||||||
}
|
}
|
||||||
@@ -336,7 +340,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
this.localDatabase.onNewLeaf(change as EntryLeaf);
|
this.localDatabase.onNewLeaf(change as EntryLeaf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (await this.core.$anyModuleParsedReplicationResultItem(change)) return;
|
if (await this.services.replication.processVirtualDocument(change)) return;
|
||||||
// any addon needs this item?
|
// any addon needs this item?
|
||||||
// for (const proc of this.core.addOns) {
|
// for (const proc of this.core.addOns) {
|
||||||
// if (await proc.parseReplicationResultItem(change)) {
|
// if (await proc.parseReplicationResultItem(change)) {
|
||||||
@@ -361,7 +365,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
}
|
}
|
||||||
if (isAnyNote(change)) {
|
if (isAnyNote(change)) {
|
||||||
const docPath = getPath(change);
|
const docPath = getPath(change);
|
||||||
if (!(await this.core.$$isTargetFile(docPath))) {
|
if (!(await this.services.vault.isTargetFile(docPath))) {
|
||||||
Logger(`Skipped: ${docPath}`, LOG_LEVEL_VERBOSE);
|
Logger(`Skipped: ${docPath}`, LOG_LEVEL_VERBOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -369,7 +373,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
Logger(`Processing scheduled: ${docPath}`, LOG_LEVEL_INFO);
|
Logger(`Processing scheduled: ${docPath}`, LOG_LEVEL_INFO);
|
||||||
}
|
}
|
||||||
const size = change.size;
|
const size = change.size;
|
||||||
if (this.core.$$isFileSizeExceeded(size)) {
|
if (this.services.vault.isFileSizeTooLarge(size)) {
|
||||||
Logger(
|
Logger(
|
||||||
`Processing ${docPath} has been skipped due to file size exceeding the limit`,
|
`Processing ${docPath} has been skipped due to file size exceeding the limit`,
|
||||||
LOG_LEVEL_NOTICE
|
LOG_LEVEL_NOTICE
|
||||||
@@ -413,7 +417,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await this.core.$anyProcessOptionalSyncFiles(dbDoc)) {
|
if (await this.services.replication.processOptionalSynchroniseResult(dbDoc)) {
|
||||||
// Already processed
|
// Already processed
|
||||||
} else if (isValidPath(getPath(doc))) {
|
} else if (isValidPath(getPath(doc))) {
|
||||||
this.storageApplyingProcessor.enqueue(doc as MetaEntry);
|
this.storageApplyingProcessor.enqueue(doc as MetaEntry);
|
||||||
@@ -440,7 +444,7 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
storageApplyingProcessor = new QueueProcessor(
|
storageApplyingProcessor = new QueueProcessor(
|
||||||
async (docs: MetaEntry[]) => {
|
async (docs: MetaEntry[]) => {
|
||||||
const entry = docs[0];
|
const entry = docs[0];
|
||||||
await this.core.$anyProcessReplicatedDoc(entry);
|
await this.services.replication.processSynchroniseResult(entry);
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -458,17 +462,17 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
})
|
})
|
||||||
.startPipeline();
|
.startPipeline();
|
||||||
|
|
||||||
$everyBeforeSuspendProcess(): Promise<boolean> {
|
_everyBeforeSuspendProcess(): Promise<boolean> {
|
||||||
this.core.replicator.closeReplication();
|
this.core.replicator?.closeReplication();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$replicateAllToServer(
|
private async _replicateAllToServer(
|
||||||
showingNotice: boolean = false,
|
showingNotice: boolean = false,
|
||||||
sendChunksInBulkDisabled: boolean = false
|
sendChunksInBulkDisabled: boolean = false
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (!this.core.$$isReady()) return false;
|
if (!this.services.appLifecycle.isReady()) return false;
|
||||||
if (!(await this.core.$everyBeforeReplicate(showingNotice))) {
|
if (!(await this.services.replication.onBeforeReplicate(showingNotice))) {
|
||||||
Logger($msg("Replicator.Message.SomeModuleFailed"), LOG_LEVEL_NOTICE);
|
Logger($msg("Replicator.Message.SomeModuleFailed"), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -486,16 +490,31 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
}
|
}
|
||||||
const ret = await this.core.replicator.replicateAllToServer(this.settings, showingNotice);
|
const ret = await this.core.replicator.replicateAllToServer(this.settings, showingNotice);
|
||||||
if (ret) return true;
|
if (ret) return true;
|
||||||
const checkResult = await this.core.$anyAfterConnectCheckFailed();
|
const checkResult = await this.services.replication.checkConnectionFailure();
|
||||||
if (checkResult == "CHECKAGAIN") return await this.core.$$replicateAllToServer(showingNotice);
|
if (checkResult == "CHECKAGAIN") return await this.services.remote.replicateAllToRemote(showingNotice);
|
||||||
return !checkResult;
|
return !checkResult;
|
||||||
}
|
}
|
||||||
async $$replicateAllFromServer(showingNotice: boolean = false): Promise<boolean> {
|
async _replicateAllFromServer(showingNotice: boolean = false): Promise<boolean> {
|
||||||
if (!this.core.$$isReady()) return false;
|
if (!this.services.appLifecycle.isReady()) return false;
|
||||||
const ret = await this.core.replicator.replicateAllFromServer(this.settings, showingNotice);
|
const ret = await this.core.replicator.replicateAllFromServer(this.settings, showingNotice);
|
||||||
if (ret) return true;
|
if (ret) return true;
|
||||||
const checkResult = await this.core.$anyAfterConnectCheckFailed();
|
const checkResult = await this.services.replication.checkConnectionFailure();
|
||||||
if (checkResult == "CHECKAGAIN") return await this.core.$$replicateAllFromServer(showingNotice);
|
if (checkResult == "CHECKAGAIN") return await this.services.remote.replicateAllFromRemote(showingNotice);
|
||||||
return !checkResult;
|
return !checkResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.replicator.handleGetActiveReplicator(this._getReplicator.bind(this));
|
||||||
|
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
|
services.databaseEvents.handleOnResetDatabase(this._everyOnResetDatabase.bind(this));
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
services.replication.handleParseSynchroniseResult(this._parseReplicationResult.bind(this));
|
||||||
|
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
||||||
|
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
||||||
|
services.replication.handleIsReplicationReady(this._canReplicate.bind(this));
|
||||||
|
services.replication.handleReplicate(this._replicate.bind(this));
|
||||||
|
services.replication.handleReplicateByEvent(this._replicateByEvent.bind(this));
|
||||||
|
services.remote.handleReplicateAllToRemote(this._replicateAllToServer.bind(this));
|
||||||
|
services.remote.handleReplicateAllFromRemote(this._replicateAllFromServer.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ import { REMOTE_MINIO, REMOTE_P2P, type RemoteDBSettings } from "../../lib/src/c
|
|||||||
import { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator";
|
import { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator";
|
||||||
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
import type { LiveSyncCore } from "../../main";
|
||||||
|
|
||||||
export class ModuleReplicatorCouchDB extends AbstractModule implements ICoreModule {
|
export class ModuleReplicatorCouchDB extends AbstractModule {
|
||||||
$anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator | false> {
|
||||||
const settings = { ...this.settings, ...settingOverride };
|
const settings = { ...this.settings, ...settingOverride };
|
||||||
// If new remote types were added, add them here. Do not use `REMOTE_COUCHDB` directly for the safety valve.
|
// If new remote types were added, add them here. Do not use `REMOTE_COUCHDB` directly for the safety valve.
|
||||||
if (settings.remoteType == REMOTE_MINIO || settings.remoteType == REMOTE_P2P) {
|
if (settings.remoteType == REMOTE_MINIO || settings.remoteType == REMOTE_P2P) {
|
||||||
return undefined!;
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
return Promise.resolve(new LiveSyncCouchDBReplicator(this.core));
|
return Promise.resolve(new LiveSyncCouchDBReplicator(this.core));
|
||||||
}
|
}
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
_everyAfterResumeProcess(): Promise<boolean> {
|
||||||
if (!this.core.$$isSuspended) return Promise.resolve(true);
|
if (!this.services.appLifecycle.isSuspended()) return Promise.resolve(true);
|
||||||
if (!this.core.$$isReady) return Promise.resolve(true);
|
if (!this.services.appLifecycle.isReady()) return Promise.resolve(true);
|
||||||
if (this.settings.remoteType != REMOTE_MINIO && this.settings.remoteType != REMOTE_P2P) {
|
if (this.settings.remoteType != REMOTE_MINIO && this.settings.remoteType != REMOTE_P2P) {
|
||||||
const LiveSyncEnabled = this.settings.liveSync;
|
const LiveSyncEnabled = this.settings.liveSync;
|
||||||
const continuous = LiveSyncEnabled;
|
const continuous = LiveSyncEnabled;
|
||||||
@@ -27,7 +27,7 @@ export class ModuleReplicatorCouchDB extends AbstractModule implements ICoreModu
|
|||||||
// And note that we do not open the conflict detection dialogue directly during this process.
|
// And note that we do not open the conflict detection dialogue directly during this process.
|
||||||
// This should be raised explicitly if needed.
|
// This should be raised explicitly if needed.
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
const canReplicate = await this.core.$$canReplicate(false);
|
const canReplicate = await this.services.replication.isReplicationReady(false);
|
||||||
if (!canReplicate) return;
|
if (!canReplicate) return;
|
||||||
void this.core.replicator.openReplication(this.settings, continuous, false, false);
|
void this.core.replicator.openReplication(this.settings, continuous, false, false);
|
||||||
});
|
});
|
||||||
@@ -36,4 +36,8 @@ export class ModuleReplicatorCouchDB extends AbstractModule implements ICoreModu
|
|||||||
|
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
||||||
|
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { REMOTE_MINIO, type RemoteDBSettings } from "../../lib/src/common/types";
|
import { REMOTE_MINIO, type RemoteDBSettings } from "../../lib/src/common/types";
|
||||||
import { LiveSyncJournalReplicator } from "../../lib/src/replication/journal/LiveSyncJournalReplicator";
|
import { LiveSyncJournalReplicator } from "../../lib/src/replication/journal/LiveSyncJournalReplicator";
|
||||||
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
||||||
|
import type { LiveSyncCore } from "../../main";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
|
|
||||||
export class ModuleReplicatorMinIO extends AbstractModule implements ICoreModule {
|
export class ModuleReplicatorMinIO extends AbstractModule {
|
||||||
$anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator | false> {
|
||||||
const settings = { ...this.settings, ...settingOverride };
|
const settings = { ...this.settings, ...settingOverride };
|
||||||
if (settings.remoteType == REMOTE_MINIO) {
|
if (settings.remoteType == REMOTE_MINIO) {
|
||||||
return Promise.resolve(new LiveSyncJournalReplicator(this.core));
|
return Promise.resolve(new LiveSyncJournalReplicator(this.core));
|
||||||
}
|
}
|
||||||
return undefined!;
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { REMOTE_P2P, type RemoteDBSettings } from "../../lib/src/common/types";
|
import { REMOTE_P2P, type RemoteDBSettings } from "../../lib/src/common/types";
|
||||||
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
import { LiveSyncTrysteroReplicator } from "../../lib/src/replication/trystero/LiveSyncTrysteroReplicator";
|
import { LiveSyncTrysteroReplicator } from "../../lib/src/replication/trystero/LiveSyncTrysteroReplicator";
|
||||||
|
import type { LiveSyncCore } from "../../main";
|
||||||
|
|
||||||
export class ModuleReplicatorP2P extends AbstractModule implements ICoreModule {
|
export class ModuleReplicatorP2P extends AbstractModule {
|
||||||
$anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator> {
|
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator | false> {
|
||||||
const settings = { ...this.settings, ...settingOverride };
|
const settings = { ...this.settings, ...settingOverride };
|
||||||
if (settings.remoteType == REMOTE_P2P) {
|
if (settings.remoteType == REMOTE_P2P) {
|
||||||
return Promise.resolve(new LiveSyncTrysteroReplicator(this.core));
|
return Promise.resolve(new LiveSyncTrysteroReplicator(this.core));
|
||||||
}
|
}
|
||||||
return undefined!;
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
$everyAfterResumeProcess(): Promise<boolean> {
|
_everyAfterResumeProcess(): Promise<boolean> {
|
||||||
if (this.settings.remoteType == REMOTE_P2P) {
|
if (this.settings.remoteType == REMOTE_P2P) {
|
||||||
// // If LiveSync enabled, open replication
|
// // If LiveSync enabled, open replication
|
||||||
// if (this.settings.liveSync) {
|
// if (this.settings.liveSync) {
|
||||||
@@ -27,4 +27,8 @@ export class ModuleReplicatorP2P extends AbstractModule implements ICoreModule {
|
|||||||
|
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
||||||
|
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ import {
|
|||||||
} from "../../lib/src/common/types";
|
} from "../../lib/src/common/types";
|
||||||
import { addPrefix, isAcceptedAll } from "../../lib/src/string_and_binary/path";
|
import { addPrefix, isAcceptedAll } from "../../lib/src/string_and_binary/path";
|
||||||
import { AbstractModule } from "../AbstractModule";
|
import { AbstractModule } from "../AbstractModule";
|
||||||
import type { ICoreModule } from "../ModuleTypes";
|
|
||||||
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
|
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
|
||||||
import { isDirty } from "../../lib/src/common/utils";
|
import { isDirty } from "../../lib/src/common/utils";
|
||||||
export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
import type { LiveSyncCore } from "../../main";
|
||||||
|
export class ModuleTargetFilter extends AbstractModule {
|
||||||
reloadIgnoreFiles() {
|
reloadIgnoreFiles() {
|
||||||
this.ignoreFiles = this.settings.ignoreFiles.split(",").map((e) => e.trim());
|
this.ignoreFiles = this.settings.ignoreFiles.split(",").map((e) => e.trim());
|
||||||
}
|
}
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: ObsidianLiveSyncSettings) => {
|
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: ObsidianLiveSyncSettings) => {
|
||||||
this.reloadIgnoreFiles();
|
this.reloadIgnoreFiles();
|
||||||
});
|
});
|
||||||
@@ -35,7 +35,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$$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)) {
|
||||||
const out = stripInternalMetadataPrefix(tempId);
|
const out = stripInternalMetadataPrefix(tempId);
|
||||||
@@ -43,7 +43,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return tempId;
|
return tempId;
|
||||||
}
|
}
|
||||||
async $$path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise<DocumentID> {
|
async _path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise<DocumentID> {
|
||||||
const destPath = addPrefix(filename, prefix ?? "");
|
const destPath = addPrefix(filename, prefix ?? "");
|
||||||
return await path2id(
|
return await path2id(
|
||||||
destPath,
|
destPath,
|
||||||
@@ -52,7 +52,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$$isFileSizeExceeded(size: number) {
|
private _isFileSizeExceeded(size: number) {
|
||||||
if (this.settings.syncMaxSizeInMB > 0 && size > 0) {
|
if (this.settings.syncMaxSizeInMB > 0 && size > 0) {
|
||||||
if (this.settings.syncMaxSizeInMB * 1024 * 1024 < size) {
|
if (this.settings.syncMaxSizeInMB * 1024 * 1024 < size) {
|
||||||
return true;
|
return true;
|
||||||
@@ -61,7 +61,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$markFileListPossiblyChanged(): void {
|
_markFileListPossiblyChanged(): void {
|
||||||
this.totalFileEventCount++;
|
this.totalFileEventCount++;
|
||||||
}
|
}
|
||||||
totalFileEventCount = 0;
|
totalFileEventCount = 0;
|
||||||
@@ -72,7 +72,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$isTargetFile(file: string | UXFileInfoStub, keepFileCheckList = false) {
|
private async _isTargetFile(file: string | UXFileInfoStub, keepFileCheckList = false) {
|
||||||
const fileCount = useMemo<Record<string, number>>(
|
const fileCount = useMemo<Record<string, number>>(
|
||||||
{
|
{
|
||||||
key: "fileCount", // forceUpdate: !keepFileCheckList,
|
key: "fileCount", // forceUpdate: !keepFileCheckList,
|
||||||
@@ -109,7 +109,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
|
|
||||||
const filepath = getStoragePathFromUXFileInfo(file);
|
const filepath = getStoragePathFromUXFileInfo(file);
|
||||||
const lc = filepath.toLowerCase();
|
const lc = filepath.toLowerCase();
|
||||||
if (this.core.$$shouldCheckCaseInsensitive()) {
|
if (this.services.setting.shouldCheckCaseInsensitively()) {
|
||||||
if (lc in fileCount && fileCount[lc] > 1) {
|
if (lc in fileCount && fileCount[lc] > 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
// We must reload ignore files due to the its change.
|
// We must reload ignore files due to the its change.
|
||||||
await this.readIgnoreFile(filepath);
|
await this.readIgnoreFile(filepath);
|
||||||
}
|
}
|
||||||
if (await this.core.$$isIgnoredByIgnoreFiles(file)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
return await this.readIgnoreFile(path);
|
return await this.readIgnoreFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async $$isIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
|
private async _isIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
|
||||||
if (!this.settings.useIgnoreFiles) {
|
if (!this.settings.useIgnoreFiles) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -164,4 +164,14 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.vault.handleMarkFileListPossiblyChanged(this._markFileListPossiblyChanged.bind(this));
|
||||||
|
services.path.handleId2Path(this._id2path.bind(this));
|
||||||
|
services.path.handlePath2Id(this._path2id.bind(this));
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.vault.handleIsFileSizeTooLarge(this._isFileSizeExceeded.bind(this));
|
||||||
|
services.vault.handleIsIgnoredByIgnoreFile(this._isIgnoredByIgnoreFiles.bind(this));
|
||||||
|
services.vault.handleIsTargetFile(this._isTargetFile.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import { sizeToHumanReadable } from "octagonal-wheels/number";
|
import { sizeToHumanReadable } from "octagonal-wheels/number";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleCheckRemoteSize extends AbstractModule implements ICoreModule {
|
export class ModuleCheckRemoteSize extends AbstractModule {
|
||||||
async $allScanStat(): Promise<boolean> {
|
async _allScanStat(): Promise<boolean> {
|
||||||
if (this.core.managers.networkManager.isOnline === false) {
|
if (this.core.managers.networkManager.isOnline === false) {
|
||||||
this._log("Network is offline, skipping remote size check.", LOG_LEVEL_INFO);
|
this._log("Network is offline, skipping remote size check.", LOG_LEVEL_INFO);
|
||||||
return true;
|
return true;
|
||||||
@@ -109,4 +109,7 @@ export class ModuleCheckRemoteSize extends AbstractModule implements ICoreModule
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnScanningStartupIssues(this._allScanStat.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,35 +2,36 @@ import { AbstractModule } from "../AbstractModule.ts";
|
|||||||
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types";
|
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types";
|
||||||
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
||||||
import { sendValue } from "octagonal-wheels/messagepassing/signal";
|
import { sendValue } from "octagonal-wheels/messagepassing/signal";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleConflictChecker extends AbstractModule implements ICoreModule {
|
export class ModuleConflictChecker extends AbstractModule {
|
||||||
async $$queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise<void> {
|
async _queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise<void> {
|
||||||
const path = file;
|
const path = file;
|
||||||
if (this.settings.checkConflictOnlyOnOpen) {
|
if (this.settings.checkConflictOnlyOnOpen) {
|
||||||
const af = this.core.$$getActiveFilePath();
|
const af = this.services.vault.getActiveFilePath();
|
||||||
if (af && af != path) {
|
if (af && af != path) {
|
||||||
this._log(`${file} is conflicted, merging process has been postponed.`, LOG_LEVEL_NOTICE);
|
this._log(`${file} is conflicted, merging process has been postponed.`, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.core.$$queueConflictCheck(path);
|
await this.services.conflict.queueCheckFor(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$queueConflictCheck(file: FilePathWithPrefix): Promise<void> {
|
async _queueConflictCheck(file: FilePathWithPrefix): Promise<void> {
|
||||||
const optionalConflictResult = await this.core.$anyGetOptionalConflictCheckMethod(file);
|
const optionalConflictResult = await this.services.conflict.getOptionalConflictCheckMethod(file);
|
||||||
if (optionalConflictResult == true) {
|
if (optionalConflictResult == true) {
|
||||||
// The conflict has been resolved by another process.
|
// The conflict has been resolved by another process.
|
||||||
return;
|
return;
|
||||||
} else if (optionalConflictResult === "newer") {
|
} else if (optionalConflictResult === "newer") {
|
||||||
// The conflict should be resolved by the newer entry.
|
// The conflict should be resolved by the newer entry.
|
||||||
await this.core.$anyResolveConflictByNewest(file);
|
await this.services.conflict.resolveByNewest(file);
|
||||||
} else {
|
} else {
|
||||||
this.conflictCheckQueue.enqueue(file);
|
this.conflictCheckQueue.enqueue(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$$waitForAllConflictProcessed(): Promise<boolean> {
|
_waitForAllConflictProcessed(): Promise<boolean> {
|
||||||
return this.conflictResolveQueue.waitForAllProcessed();
|
return this.conflictResolveQueue.waitForAllProcessed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ export class ModuleConflictChecker extends AbstractModule implements ICoreModule
|
|||||||
conflictResolveQueue = new QueueProcessor(
|
conflictResolveQueue = new QueueProcessor(
|
||||||
async (filenames: FilePathWithPrefix[]) => {
|
async (filenames: FilePathWithPrefix[]) => {
|
||||||
const filename = filenames[0];
|
const filename = filenames[0];
|
||||||
return await this.core.$$resolveConflict(filename);
|
return await this.services.conflict.resolve(filename);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
suspended: false,
|
suspended: false,
|
||||||
@@ -73,4 +74,9 @@ export class ModuleConflictChecker extends AbstractModule implements ICoreModule
|
|||||||
totalRemainingReactiveSource: this.core.conflictProcessQueueCount,
|
totalRemainingReactiveSource: this.core.conflictProcessQueueCount,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.conflict.handleQueueCheckForIfOpen(this._queueConflictCheckIfOpen.bind(this));
|
||||||
|
services.conflict.handleQueueCheckFor(this._queueConflictCheck.bind(this));
|
||||||
|
services.conflict.handleEnsureAllProcessed(this._waitForAllConflictProcessed.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ import {
|
|||||||
} from "../../common/utils";
|
} from "../../common/utils";
|
||||||
import diff_match_patch from "diff-match-patch";
|
import diff_match_patch from "diff-match-patch";
|
||||||
import { stripAllPrefixes, isPlainText } from "../../lib/src/string_and_binary/path";
|
import { stripAllPrefixes, isPlainText } from "../../lib/src/string_and_binary/path";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { eventHub } from "../../common/events.ts";
|
import { eventHub } from "../../common/events.ts";
|
||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface LSEvents {
|
interface LSEvents {
|
||||||
@@ -29,8 +30,8 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModuleConflictResolver extends AbstractModule implements ICoreModule {
|
export class ModuleConflictResolver extends AbstractModule {
|
||||||
async $$resolveConflictByDeletingRev(
|
private async _resolveConflictByDeletingRev(
|
||||||
path: FilePathWithPrefix,
|
path: FilePathWithPrefix,
|
||||||
deleteRevision: string,
|
deleteRevision: string,
|
||||||
subTitle = ""
|
subTitle = ""
|
||||||
@@ -82,7 +83,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
return MISSING_OR_ERROR;
|
return MISSING_OR_ERROR;
|
||||||
}
|
}
|
||||||
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
||||||
return await this.core.$$resolveConflictByDeletingRev(path, ret.conflictedRev, "Sensible");
|
return await this.services.conflict.resolveByDeletingRevision(path, ret.conflictedRev, "Sensible");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rightRev, leftLeaf, rightLeaf } = ret;
|
const { rightRev, leftLeaf, rightLeaf } = ret;
|
||||||
@@ -95,7 +96,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
}
|
}
|
||||||
if (rightLeaf == false) {
|
if (rightLeaf == false) {
|
||||||
// Conflicted item could not load, delete this.
|
// Conflicted item could not load, delete this.
|
||||||
return await this.core.$$resolveConflictByDeletingRev(path, rightRev, "MISSING OLD REV");
|
return await this.services.conflict.resolveByDeletingRevision(path, rightRev, "MISSING OLD REV");
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSame = leftLeaf.data == rightLeaf.data && leftLeaf.deleted == rightLeaf.deleted;
|
const isSame = leftLeaf.data == rightLeaf.data && leftLeaf.deleted == rightLeaf.deleted;
|
||||||
@@ -115,7 +116,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
]
|
]
|
||||||
.filter((e) => e.trim())
|
.filter((e) => e.trim())
|
||||||
.join(",");
|
.join(",");
|
||||||
return await this.core.$$resolveConflictByDeletingRev(path, loser.rev, subTitle);
|
return await this.services.conflict.resolveByDeletingRevision(path, loser.rev, subTitle);
|
||||||
}
|
}
|
||||||
// make diff.
|
// make diff.
|
||||||
const dmp = new diff_match_patch();
|
const dmp = new diff_match_patch();
|
||||||
@@ -129,7 +130,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$resolveConflict(filename: FilePathWithPrefix): Promise<void> {
|
private async _resolveConflict(filename: FilePathWithPrefix): Promise<void> {
|
||||||
// const filename = filenames[0];
|
// const filename = filenames[0];
|
||||||
return await serialized(`conflict-resolve:${filename}`, async () => {
|
return await serialized(`conflict-resolve:${filename}`, async () => {
|
||||||
const conflictCheckResult = await this.checkConflictAndPerformAutoMerge(filename);
|
const conflictCheckResult = await this.checkConflictAndPerformAutoMerge(filename);
|
||||||
@@ -144,16 +145,16 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
}
|
}
|
||||||
if (conflictCheckResult === AUTO_MERGED) {
|
if (conflictCheckResult === AUTO_MERGED) {
|
||||||
//auto resolved, but need check again;
|
//auto resolved, but need check again;
|
||||||
if (this.settings.syncAfterMerge && !this.core.$$isSuspended()) {
|
if (this.settings.syncAfterMerge && !this.services.appLifecycle.isSuspended()) {
|
||||||
//Wait for the running replication, if not running replication, run it once.
|
//Wait for the running replication, if not running replication, run it once.
|
||||||
await this.core.$$replicateByEvent();
|
await this.services.replication.replicateByEvent();
|
||||||
}
|
}
|
||||||
this._log("[conflict] Automatically merged, but we have to check it again");
|
this._log("[conflict] Automatically merged, but we have to check it again");
|
||||||
await this.core.$$queueConflictCheck(filename);
|
await this.services.conflict.queueCheckFor(filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.settings.showMergeDialogOnlyOnActive) {
|
if (this.settings.showMergeDialogOnlyOnActive) {
|
||||||
const af = this.core.$$getActiveFilePath();
|
const af = this.services.vault.getActiveFilePath();
|
||||||
if (af && af != filename) {
|
if (af && af != filename) {
|
||||||
this._log(
|
this._log(
|
||||||
`[conflict] ${filename} is conflicted. Merging process has been postponed to the file have got opened.`,
|
`[conflict] ${filename} is conflicted. Merging process has been postponed to the file have got opened.`,
|
||||||
@@ -164,11 +165,11 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
}
|
}
|
||||||
this._log("[conflict] Manual merge required!");
|
this._log("[conflict] Manual merge required!");
|
||||||
eventHub.emitEvent("conflict-cancelled", filename);
|
eventHub.emitEvent("conflict-cancelled", filename);
|
||||||
await this.core.$anyResolveConflictByUI(filename, conflictCheckResult);
|
await this.services.conflict.resolveByUserInteraction(filename, conflictCheckResult);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyResolveConflictByNewest(filename: FilePathWithPrefix): Promise<boolean> {
|
private async _anyResolveConflictByNewest(filename: FilePathWithPrefix): Promise<boolean> {
|
||||||
const currentRev = await this.core.databaseFileAccess.fetchEntryMeta(filename, undefined, true);
|
const currentRev = await this.core.databaseFileAccess.fetchEntryMeta(filename, undefined, true);
|
||||||
if (currentRev == false) {
|
if (currentRev == false) {
|
||||||
this._log(`Could not get current revision of ${filename}`);
|
this._log(`Could not get current revision of ${filename}`);
|
||||||
@@ -206,8 +207,14 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
|
|||||||
this._log(
|
this._log(
|
||||||
`conflict: Deleting the older revision ${mTimeAndRev[i][1]} (${new Date(mTimeAndRev[i][0]).toLocaleString()}) of ${filename}`
|
`conflict: Deleting the older revision ${mTimeAndRev[i][1]} (${new Date(mTimeAndRev[i][0]).toLocaleString()}) of ${filename}`
|
||||||
);
|
);
|
||||||
await this.core.$$resolveConflictByDeletingRev(filename, mTimeAndRev[i][1], "NEWEST");
|
await this.services.conflict.resolveByDeletingRevision(filename, mTimeAndRev[i][1], "NEWEST");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.conflict.handleResolveByDeletingRevision(this._resolveConflictByDeletingRev.bind(this));
|
||||||
|
services.conflict.handleResolve(this._resolveConflict.bind(this));
|
||||||
|
services.conflict.handleResolveByNewest(this._anyResolveConflictByNewest.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import {
|
|||||||
type ObsidianLiveSyncSettings,
|
type ObsidianLiveSyncSettings,
|
||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { $msg } from "../../lib/src/common/i18n.ts";
|
import { $msg } from "../../lib/src/common/i18n.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
export class ModuleRedFlag extends AbstractModule {
|
||||||
async isFlagFileExist(path: string) {
|
async isFlagFileExist(path: string) {
|
||||||
const redflag = await this.core.storageAccess.isExists(normalizePath(path));
|
const redflag = await this.core.storageAccess.isExists(normalizePath(path));
|
||||||
if (redflag) {
|
if (redflag) {
|
||||||
@@ -48,7 +48,7 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
await this.deleteFlagFile(FLAGMD_REDFLAG3);
|
await this.deleteFlagFile(FLAGMD_REDFLAG3);
|
||||||
await this.deleteFlagFile(FLAGMD_REDFLAG3_HR);
|
await this.deleteFlagFile(FLAGMD_REDFLAG3_HR);
|
||||||
}
|
}
|
||||||
async $everyOnLayoutReady(): Promise<boolean> {
|
async _everyOnLayoutReady(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const isRedFlagRaised = await this.isRedFlagRaised();
|
const isRedFlagRaised = await this.isRedFlagRaised();
|
||||||
const isRedFlag2Raised = await this.isRedFlag2Raised();
|
const isRedFlag2Raised = await this.isRedFlag2Raised();
|
||||||
@@ -63,7 +63,7 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
)) !== "yes"
|
)) !== "yes"
|
||||||
) {
|
) {
|
||||||
await this.deleteRedFlag2();
|
await this.deleteRedFlag2();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,13 +75,13 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
})) !== "yes"
|
})) !== "yes"
|
||||||
) {
|
) {
|
||||||
await this.deleteRedFlag3();
|
await this.deleteRedFlag3();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.settings.batchSave = false;
|
this.settings.batchSave = false;
|
||||||
await this.core.$allSuspendAllSync();
|
await this.services.setting.suspendAllSync();
|
||||||
await this.core.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
this.settings.suspendFileWatching = true;
|
this.settings.suspendFileWatching = true;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
if (isRedFlag2Raised) {
|
if (isRedFlag2Raised) {
|
||||||
@@ -99,7 +99,7 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
) {
|
) {
|
||||||
this.settings.suspendFileWatching = false;
|
this.settings.suspendFileWatching = false;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (isRedFlag3Raised) {
|
} else if (isRedFlag3Raised) {
|
||||||
@@ -148,7 +148,7 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
if (fetchRemote === optionFetchRemoteConf) {
|
if (fetchRemote === optionFetchRemoteConf) {
|
||||||
this._log("Fetching remote configuration", LOG_LEVEL_NOTICE);
|
this._log("Fetching remote configuration", LOG_LEVEL_NOTICE);
|
||||||
const newSettings = JSON.parse(JSON.stringify(this.core.settings)) as ObsidianLiveSyncSettings;
|
const newSettings = JSON.parse(JSON.stringify(this.core.settings)) as ObsidianLiveSyncSettings;
|
||||||
const remoteConfig = await this.core.$$fetchRemotePreferredTweakValues(newSettings);
|
const remoteConfig = await this.services.tweakValue.fetchRemotePreferred(newSettings);
|
||||||
if (remoteConfig) {
|
if (remoteConfig) {
|
||||||
this._log("Remote configuration found.", LOG_LEVEL_NOTICE);
|
this._log("Remote configuration found.", LOG_LEVEL_NOTICE);
|
||||||
const mergedSettings = {
|
const mergedSettings = {
|
||||||
@@ -174,7 +174,7 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
) {
|
) {
|
||||||
this.settings.suspendFileWatching = false;
|
this.settings.suspendFileWatching = false;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -198,4 +198,8 @@ export class ModuleRedFlag extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
super.onBindFunction(core, services);
|
||||||
|
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
|
|
||||||
export class ModuleRemoteGovernor extends AbstractModule implements ICoreModule {
|
export class ModuleRemoteGovernor extends AbstractModule {
|
||||||
async $$markRemoteLocked(lockByClean: boolean = false): Promise<void> {
|
private async _markRemoteLocked(lockByClean: boolean = false): Promise<void> {
|
||||||
return await this.core.replicator.markRemoteLocked(this.settings, true, lockByClean);
|
return await this.core.replicator.markRemoteLocked(this.settings, true, lockByClean);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$markRemoteUnlocked(): Promise<void> {
|
private async _markRemoteUnlocked(): Promise<void> {
|
||||||
return await this.core.replicator.markRemoteLocked(this.settings, false, false);
|
return await this.core.replicator.markRemoteLocked(this.settings, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$markRemoteResolved(): Promise<void> {
|
private async _markRemoteResolved(): Promise<void> {
|
||||||
return await this.core.replicator.markRemoteResolved(this.settings);
|
return await this.core.replicator.markRemoteResolved(this.settings);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.remote.handleMarkLocked(this._markRemoteLocked.bind(this));
|
||||||
|
services.remote.handleMarkUnlocked(this._markRemoteUnlocked.bind(this));
|
||||||
|
services.remote.handleMarkResolved(this._markRemoteResolved.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,21 +11,22 @@ import {
|
|||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { escapeMarkdownValue } from "../../lib/src/common/utils.ts";
|
import { escapeMarkdownValue } from "../../lib/src/common/utils.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { $msg } from "../../lib/src/common/i18n.ts";
|
import { $msg } from "../../lib/src/common/i18n.ts";
|
||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleResolvingMismatchedTweaks extends AbstractModule implements ICoreModule {
|
export class ModuleResolvingMismatchedTweaks extends AbstractModule {
|
||||||
async $anyAfterConnectCheckFailed(): Promise<boolean | "CHECKAGAIN" | undefined> {
|
async _anyAfterConnectCheckFailed(): Promise<boolean | "CHECKAGAIN" | undefined> {
|
||||||
if (!this.core.replicator.tweakSettingsMismatched && !this.core.replicator.preferredTweakValue) return false;
|
if (!this.core.replicator.tweakSettingsMismatched && !this.core.replicator.preferredTweakValue) return false;
|
||||||
const preferred = this.core.replicator.preferredTweakValue;
|
const preferred = this.core.replicator.preferredTweakValue;
|
||||||
if (!preferred) return false;
|
if (!preferred) return false;
|
||||||
const ret = await this.core.$$askResolvingMismatchedTweaks(preferred);
|
const ret = await this.services.tweakValue.askResolvingMismatched(preferred);
|
||||||
if (ret == "OK") return false;
|
if (ret == "OK") return false;
|
||||||
if (ret == "CHECKAGAIN") return "CHECKAGAIN";
|
if (ret == "CHECKAGAIN") return "CHECKAGAIN";
|
||||||
if (ret == "IGNORE") return true;
|
if (ret == "IGNORE") return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$checkAndAskResolvingMismatchedTweaks(
|
async _checkAndAskResolvingMismatchedTweaks(
|
||||||
preferred: Partial<TweakValues>
|
preferred: Partial<TweakValues>
|
||||||
): Promise<[TweakValues | boolean, boolean]> {
|
): Promise<[TweakValues | boolean, boolean]> {
|
||||||
const mine = extractObject(TweakValuesShouldMatchedTemplate, this.settings);
|
const mine = extractObject(TweakValuesShouldMatchedTemplate, this.settings);
|
||||||
@@ -127,7 +128,7 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
return CHOICES[retKey];
|
return CHOICES[retKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$askResolvingMismatchedTweaks(): Promise<"OK" | "CHECKAGAIN" | "IGNORE"> {
|
async _askResolvingMismatchedTweaks(): Promise<"OK" | "CHECKAGAIN" | "IGNORE"> {
|
||||||
if (!this.core.replicator.tweakSettingsMismatched) {
|
if (!this.core.replicator.tweakSettingsMismatched) {
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
@@ -137,7 +138,7 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
}
|
}
|
||||||
const preferred = extractObject(TweakValuesShouldMatchedTemplate, tweaks);
|
const preferred = extractObject(TweakValuesShouldMatchedTemplate, tweaks);
|
||||||
|
|
||||||
const [conf, rebuildRequired] = await this.core.$$checkAndAskResolvingMismatchedTweaks(preferred);
|
const [conf, rebuildRequired] = await this.services.tweakValue.checkAndAskResolvingMismatched(preferred);
|
||||||
if (!conf) return "IGNORE";
|
if (!conf) return "IGNORE";
|
||||||
|
|
||||||
if (conf === true) {
|
if (conf === true) {
|
||||||
@@ -154,7 +155,7 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
if (conf) {
|
if (conf) {
|
||||||
this.settings = { ...this.settings, ...conf };
|
this.settings = { ...this.settings, ...conf };
|
||||||
await this.core.replicator.setPreferredRemoteTweakSettings(this.settings);
|
await this.core.replicator.setPreferredRemoteTweakSettings(this.settings);
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
if (rebuildRequired) {
|
if (rebuildRequired) {
|
||||||
await this.core.rebuilder.$fetchLocal();
|
await this.core.rebuilder.$fetchLocal();
|
||||||
}
|
}
|
||||||
@@ -164,8 +165,12 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
return "IGNORE";
|
return "IGNORE";
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$fetchRemotePreferredTweakValues(trialSetting: RemoteDBSettings): Promise<TweakValues | false> {
|
async _fetchRemotePreferredTweakValues(trialSetting: RemoteDBSettings): Promise<TweakValues | false> {
|
||||||
const replicator = await this.core.$anyNewReplicator();
|
const replicator = await this.services.replicator.getNewReplicator(trialSetting);
|
||||||
|
if (!replicator) {
|
||||||
|
this._log("The remote type is not supported for fetching preferred tweak values.", LOG_LEVEL_NOTICE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (await replicator.tryConnectRemote(trialSetting)) {
|
if (await replicator.tryConnectRemote(trialSetting)) {
|
||||||
const preferred = await replicator.getRemotePreferredTweakValues(trialSetting);
|
const preferred = await replicator.getRemotePreferredTweakValues(trialSetting);
|
||||||
if (preferred) {
|
if (preferred) {
|
||||||
@@ -178,17 +183,17 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$checkAndAskUseRemoteConfiguration(
|
async _checkAndAskUseRemoteConfiguration(
|
||||||
trialSetting: RemoteDBSettings
|
trialSetting: RemoteDBSettings
|
||||||
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
||||||
const preferred = await this.core.$$fetchRemotePreferredTweakValues(trialSetting);
|
const preferred = await this.services.tweakValue.fetchRemotePreferred(trialSetting);
|
||||||
if (preferred) {
|
if (preferred) {
|
||||||
return await this.$$askUseRemoteConfiguration(trialSetting, preferred);
|
return await this.services.tweakValue.askUseRemoteConfiguration(trialSetting, preferred);
|
||||||
}
|
}
|
||||||
return { result: false, requireFetch: false };
|
return { result: false, requireFetch: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$askUseRemoteConfiguration(
|
async _askUseRemoteConfiguration(
|
||||||
trialSetting: RemoteDBSettings,
|
trialSetting: RemoteDBSettings,
|
||||||
preferred: TweakValues
|
preferred: TweakValues
|
||||||
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
): Promise<{ result: false | TweakValues; requireFetch: boolean }> {
|
||||||
@@ -278,4 +283,13 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule implements I
|
|||||||
}
|
}
|
||||||
return { result: false, requireFetch: false };
|
return { result: false, requireFetch: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.tweakValue.handleFetchRemotePreferred(this._fetchRemotePreferredTweakValues.bind(this));
|
||||||
|
services.tweakValue.handleCheckAndAskResolvingMismatched(this._checkAndAskResolvingMismatchedTweaks.bind(this));
|
||||||
|
services.tweakValue.handleAskResolvingMismatched(this._askResolvingMismatchedTweaks.bind(this));
|
||||||
|
services.tweakValue.handleCheckAndAskUseRemoteConfiguration(this._checkAndAskUseRemoteConfiguration.bind(this));
|
||||||
|
services.tweakValue.handleAskUseRemoteConfiguration(this._askUseRemoteConfiguration.bind(this));
|
||||||
|
services.replication.handleCheckConnectionFailure(this._anyAfterConnectCheckFailed.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { TFile, TFolder, type ListedFiles } from "obsidian";
|
import { TFile, TFolder, type ListedFiles } from "obsidian";
|
||||||
import { SerializedFileAccess } from "./storageLib/SerializedFileAccess";
|
import { SerializedFileAccess } from "./storageLib/SerializedFileAccess";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import type {
|
import type {
|
||||||
FilePath,
|
FilePath,
|
||||||
@@ -16,10 +16,13 @@ import { StorageEventManagerObsidian, type StorageEventManager } from "./storage
|
|||||||
import type { StorageAccess } from "../interfaces/StorageAccess";
|
import type { StorageAccess } from "../interfaces/StorageAccess";
|
||||||
import { createBlob, type CustomRegExp } from "../../lib/src/common/utils";
|
import { createBlob, type CustomRegExp } from "../../lib/src/common/utils";
|
||||||
import { serialized } from "octagonal-wheels/concurrency/lock_v2";
|
import { serialized } from "octagonal-wheels/concurrency/lock_v2";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
import type ObsidianLiveSyncPlugin from "../../main.ts";
|
||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
|
||||||
const fileLockPrefix = "file-lock:";
|
const fileLockPrefix = "file-lock:";
|
||||||
|
|
||||||
export class ModuleFileAccessObsidian extends AbstractObsidianModule implements IObsidianModule, StorageAccess {
|
export class ModuleFileAccessObsidian extends AbstractObsidianModule implements StorageAccess {
|
||||||
processingFiles: Set<FilePathWithPrefix> = new Set();
|
processingFiles: Set<FilePathWithPrefix> = new Set();
|
||||||
processWriteFile<T>(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise<T>): Promise<T> {
|
processWriteFile<T>(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise<T>): Promise<T> {
|
||||||
const path = typeof file === "string" ? file : file.path;
|
const path = typeof file === "string" ? file : file.path;
|
||||||
@@ -49,39 +52,35 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
}
|
}
|
||||||
vaultAccess!: SerializedFileAccess;
|
vaultAccess!: SerializedFileAccess;
|
||||||
vaultManager: StorageEventManager = new StorageEventManagerObsidian(this.plugin, this.core, this);
|
vaultManager: StorageEventManager = new StorageEventManagerObsidian(this.plugin, this.core, this);
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
this.core.storageAccess = this;
|
this.core.storageAccess = this;
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyOnFirstInitialize(): Promise<boolean> {
|
_everyOnFirstInitialize(): Promise<boolean> {
|
||||||
this.vaultManager.beginWatch();
|
this.vaultManager.beginWatch();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$allOnUnload(): Promise<boolean> {
|
|
||||||
// this.vaultManager.
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $$flushFileEventQueue(): void {
|
// $$flushFileEventQueue(): void {
|
||||||
// this.vaultManager.flushQueue();
|
// this.vaultManager.flushQueue();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
$everyCommitPendingFileEvent(): Promise<boolean> {
|
_everyCommitPendingFileEvent(): Promise<boolean> {
|
||||||
this.vaultManager.flushQueue();
|
this.vaultManager.flushQueue();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.vaultAccess = new SerializedFileAccess(this.app, this.plugin, this);
|
this.vaultAccess = new SerializedFileAccess(this.app, this.plugin, this);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$$isStorageInsensitive(): boolean {
|
_isStorageInsensitive(): boolean {
|
||||||
return this.vaultAccess.isStorageInsensitive();
|
return this.vaultAccess.isStorageInsensitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
$$shouldCheckCaseInsensitive(): boolean {
|
_shouldCheckCaseInsensitive(): boolean {
|
||||||
if (this.$$isStorageInsensitive()) return false;
|
if (this.services.vault.isStorageInsensitive()) return false;
|
||||||
return !this.settings.handleFilenameCaseSensitive;
|
return !this.settings.handleFilenameCaseSensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +274,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
if (excludeFilter && excludeFilter.some((ee) => ee.test(file))) {
|
if (excludeFilter && excludeFilter.some((ee) => ee.test(file))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(file)) continue;
|
if (await this.services.vault.isIgnoredByIgnoreFile(file)) continue;
|
||||||
files.push(file);
|
files.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +287,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
if (excludeFilter && excludeFilter.some((e) => e.test(v))) {
|
if (excludeFilter && excludeFilter.some((e) => e.test(v))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(v)) {
|
if (await this.services.vault.isIgnoredByIgnoreFile(v)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// OK, deep dive!
|
// OK, deep dive!
|
||||||
@@ -346,7 +345,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
|
|
||||||
async _deleteVaultItem(file: TFile | TFolder) {
|
async _deleteVaultItem(file: TFile | TFolder) {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
if (!(await this.core.$$isTargetFile(file.path))) return;
|
if (!(await this.services.vault.isTargetFile(file.path))) return;
|
||||||
}
|
}
|
||||||
const dir = file.parent;
|
const dir = file.parent;
|
||||||
if (this.settings.trashInsteadDelete) {
|
if (this.settings.trashInsteadDelete) {
|
||||||
@@ -376,4 +375,16 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
return await this._deleteVaultItem(file);
|
return await this._deleteVaultItem(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore) {
|
||||||
|
super(plugin, core);
|
||||||
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.vault.handleIsStorageInsensitive(this._isStorageInsensitive.bind(this));
|
||||||
|
services.setting.handleShouldCheckCaseInsensitively(this._shouldCheckCaseInsensitive.bind(this));
|
||||||
|
services.appLifecycle.handleFirstInitialise(this._everyOnFirstInitialize.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.fileProcessing.handleCommitPendingFileEvents(this._everyCommitPendingFileEvent.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ModuleInputUIObsidian.ts
|
// ModuleInputUIObsidian.ts
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
||||||
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject } from "../../common/utils.ts";
|
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject } from "../../common/utils.ts";
|
||||||
import {
|
import {
|
||||||
@@ -13,12 +13,13 @@ import { Notice } from "../../deps.ts";
|
|||||||
import type { Confirm } from "../../lib/src/interfaces/Confirm.ts";
|
import type { Confirm } from "../../lib/src/interfaces/Confirm.ts";
|
||||||
import { setConfirmInstance } from "../../lib/src/PlatformAPIs/obsidian/Confirm.ts";
|
import { setConfirmInstance } from "../../lib/src/PlatformAPIs/obsidian/Confirm.ts";
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
// This module cannot be a common module because it depends on Obsidian's API.
|
// This module cannot be a common module because it depends on Obsidian's API.
|
||||||
// However, we have to make compatible one for other platform.
|
// However, we have to make compatible one for other platform.
|
||||||
|
|
||||||
export class ModuleInputUIObsidian extends AbstractObsidianModule implements IObsidianModule, Confirm {
|
export class ModuleInputUIObsidian extends AbstractObsidianModule implements Confirm {
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
this.core.confirm = this;
|
this.core.confirm = this;
|
||||||
setConfirmInstance(this);
|
setConfirmInstance(this);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
@@ -110,4 +111,8 @@ export class ModuleInputUIObsidian extends AbstractObsidianModule implements IOb
|
|||||||
): Promise<(typeof buttons)[number] | false> {
|
): Promise<(typeof buttons)[number] | false> {
|
||||||
return confirmWithMessage(this.plugin, title, contentMd, buttons, defaultAction, timeout);
|
return confirmWithMessage(this.plugin, title, contentMd, buttons, defaultAction, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import {
|
|||||||
LOG_LEVEL_INFO,
|
LOG_LEVEL_INFO,
|
||||||
LOG_LEVEL_NOTICE,
|
LOG_LEVEL_NOTICE,
|
||||||
LOG_LEVEL_VERBOSE,
|
LOG_LEVEL_VERBOSE,
|
||||||
|
type FileEventType,
|
||||||
type FilePath,
|
type FilePath,
|
||||||
type FilePathWithPrefix,
|
type FilePathWithPrefix,
|
||||||
type UXFileInfoStub,
|
type UXFileInfoStub,
|
||||||
type UXInternalFileInfoStub,
|
type UXInternalFileInfoStub,
|
||||||
} from "../../../lib/src/common/types.ts";
|
} from "../../../lib/src/common/types.ts";
|
||||||
import { delay, fireAndForget, getFileRegExp } from "../../../lib/src/common/utils.ts";
|
import { delay, fireAndForget, getFileRegExp } from "../../../lib/src/common/utils.ts";
|
||||||
import { type FileEventItem, type FileEventType } from "../../../common/types.ts";
|
import { type FileEventItem } from "../../../common/types.ts";
|
||||||
import { serialized, skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
|
import { serialized, skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
|
||||||
import {
|
import {
|
||||||
finishAllWaitingForTimeout,
|
finishAllWaitingForTimeout,
|
||||||
@@ -48,6 +49,9 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
plugin: ObsidianLiveSyncPlugin;
|
plugin: ObsidianLiveSyncPlugin;
|
||||||
core: LiveSyncCore;
|
core: LiveSyncCore;
|
||||||
storageAccess: StorageAccess;
|
storageAccess: StorageAccess;
|
||||||
|
get services() {
|
||||||
|
return this.core.services;
|
||||||
|
}
|
||||||
|
|
||||||
get shouldBatchSave() {
|
get shouldBatchSave() {
|
||||||
return this.core.settings?.batchSave && this.core.settings?.liveSync != true;
|
return this.core.settings?.batchSave && this.core.settings?.liveSync != true;
|
||||||
@@ -175,7 +179,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
if (this.plugin.settings.useIgnoreFiles) {
|
if (this.plugin.settings.useIgnoreFiles) {
|
||||||
// If it is one of ignore files, refresh the cached one.
|
// If it is one of ignore files, refresh the cached one.
|
||||||
// (Calling$$isTargetFile will refresh the cache)
|
// (Calling$$isTargetFile will refresh the cache)
|
||||||
void this.plugin.$$isTargetFile(path).then(() => this._watchVaultRawEvents(path));
|
void this.services.vault.isTargetFile(path).then(() => this._watchVaultRawEvents(path));
|
||||||
} else {
|
} else {
|
||||||
this._watchVaultRawEvents(path);
|
this._watchVaultRawEvents(path);
|
||||||
}
|
}
|
||||||
@@ -209,7 +213,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
async appendQueue(params: FileEvent[], ctx?: any) {
|
async appendQueue(params: FileEvent[], ctx?: any) {
|
||||||
if (!this.core.settings.isConfigured) return;
|
if (!this.core.settings.isConfigured) return;
|
||||||
if (this.core.settings.suspendFileWatching) return;
|
if (this.core.settings.suspendFileWatching) return;
|
||||||
this.core.$$markFileListPossiblyChanged();
|
this.core.services.vault.markFileListPossiblyChanged();
|
||||||
// Flag up to be reload
|
// Flag up to be reload
|
||||||
const processFiles = new Set<FilePath>();
|
const processFiles = new Set<FilePath>();
|
||||||
for (const param of params) {
|
for (const param of params) {
|
||||||
@@ -222,7 +226,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
const oldPath = param.oldPath;
|
const oldPath = param.oldPath;
|
||||||
if (type !== "INTERNAL") {
|
if (type !== "INTERNAL") {
|
||||||
const size = (file as UXFileInfoStub).stat.size;
|
const size = (file as UXFileInfoStub).stat.size;
|
||||||
if (this.core.$$isFileSizeExceeded(size) && (type == "CREATE" || type == "CHANGED")) {
|
if (this.services.vault.isFileSizeTooLarge(size) && (type == "CREATE" || type == "CHANGED")) {
|
||||||
Logger(
|
Logger(
|
||||||
`The storage file has been changed but exceeds the maximum size. Skipping: ${param.file.path}`,
|
`The storage file has been changed but exceeds the maximum size. Skipping: ${param.file.path}`,
|
||||||
LOG_LEVEL_NOTICE
|
LOG_LEVEL_NOTICE
|
||||||
@@ -234,7 +238,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
// TODO: Confirm why only the TFolder skipping
|
// TODO: Confirm why only the TFolder skipping
|
||||||
// Possibly following line is needed...
|
// Possibly following line is needed...
|
||||||
// if (file?.isFolder) continue;
|
// if (file?.isFolder) continue;
|
||||||
if (!(await this.core.$$isTargetFile(file.path))) continue;
|
if (!(await this.services.vault.isTargetFile(file.path))) continue;
|
||||||
|
|
||||||
// Stop cache using to prevent the corruption;
|
// Stop cache using to prevent the corruption;
|
||||||
// let cache: null | string | ArrayBuffer;
|
// let cache: null | string | ArrayBuffer;
|
||||||
@@ -411,12 +415,12 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
const lockKey = `handleFile:${file.path}`;
|
const lockKey = `handleFile:${file.path}`;
|
||||||
return await serialized(lockKey, async () => {
|
return await serialized(lockKey, async () => {
|
||||||
if (queue.type == "INTERNAL" || file.isInternal) {
|
if (queue.type == "INTERNAL" || file.isInternal) {
|
||||||
await this.core.$anyProcessOptionalFileEvent(file.path as unknown as FilePath);
|
await this.core.services.fileProcessing.processOptionalFileEvent(file.path as unknown as FilePath);
|
||||||
} else {
|
} else {
|
||||||
const key = `file-last-proc-${queue.type}-${file.path}`;
|
const key = `file-last-proc-${queue.type}-${file.path}`;
|
||||||
const last = Number((await this.core.kvDB.get(key)) || 0);
|
const last = Number((await this.core.kvDB.get(key)) || 0);
|
||||||
if (queue.type == "DELETE") {
|
if (queue.type == "DELETE") {
|
||||||
await this.core.$anyHandlerProcessesFileEvent(queue);
|
await this.core.services.fileProcessing.processFileEvent(queue);
|
||||||
} else {
|
} else {
|
||||||
if (file.stat.mtime == last) {
|
if (file.stat.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);
|
||||||
@@ -424,7 +428,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
// this.cancelRelativeEvent(queue);
|
// this.cancelRelativeEvent(queue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(await this.core.$anyHandlerProcessesFileEvent(queue))) {
|
if (!(await this.core.services.fileProcessing.processFileEvent(queue))) {
|
||||||
Logger(
|
Logger(
|
||||||
`STORAGE -> DB: Handler failed, cancel the relative operations: ${file.path}`,
|
`STORAGE -> DB: Handler failed, cancel the relative operations: ${file.path}`,
|
||||||
LOG_LEVEL_INFO
|
LOG_LEVEL_INFO
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ import {
|
|||||||
import { isAnyNote } from "../../lib/src/common/utils.ts";
|
import { isAnyNote } from "../../lib/src/common/utils.ts";
|
||||||
import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { withConcurrency } from "octagonal-wheels/iterable/map";
|
import { withConcurrency } from "octagonal-wheels/iterable/map";
|
||||||
export class ModuleInitializerFile extends AbstractModule implements ICoreModule {
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
async $$performFullScan(showingNotice?: boolean, ignoreSuspending: boolean = false): Promise<void> {
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
export class ModuleInitializerFile extends AbstractModule {
|
||||||
|
private async _performFullScan(showingNotice?: boolean, ignoreSuspending: boolean = false): Promise<boolean> {
|
||||||
this._log("Opening the key-value database", LOG_LEVEL_VERBOSE);
|
this._log("Opening the key-value database", LOG_LEVEL_VERBOSE);
|
||||||
const isInitialized = (await this.core.kvDB.get<boolean>("initialized")) || false;
|
const isInitialized = (await this.core.kvDB.get<boolean>("initialized")) || false;
|
||||||
// synchronize all files between database and storage.
|
// synchronize all files between database and storage.
|
||||||
@@ -32,7 +33,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
"syncAll"
|
"syncAll"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ignoreSuspending && this.settings.suspendFileWatching) {
|
if (!ignoreSuspending && this.settings.suspendFileWatching) {
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
@@ -42,7 +43,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
"syncAll"
|
"syncAll"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
@@ -59,7 +60,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
const _filesStorage = [] as typeof filesStorageSrc;
|
const _filesStorage = [] as typeof filesStorageSrc;
|
||||||
|
|
||||||
for (const f of filesStorageSrc) {
|
for (const f of filesStorageSrc) {
|
||||||
if (await this.core.$$isTargetFile(f.path, f != filesStorageSrc[0])) {
|
if (await this.services.vault.isTargetFile(f.path, f != filesStorageSrc[0])) {
|
||||||
_filesStorage.push(f);
|
_filesStorage.push(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +104,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
);
|
);
|
||||||
const path = getPath(doc);
|
const path = getPath(doc);
|
||||||
|
|
||||||
if (isValidPath(path) && (await this.core.$$isTargetFile(path, true))) {
|
if (isValidPath(path) && (await this.services.vault.isTargetFile(path, true))) {
|
||||||
if (!isMetaEntry(doc)) {
|
if (!isMetaEntry(doc)) {
|
||||||
this._log(`Invalid entry: ${path}`, LOG_LEVEL_INFO);
|
this._log(`Invalid entry: ${path}`, LOG_LEVEL_INFO);
|
||||||
continue;
|
continue;
|
||||||
@@ -133,7 +134,6 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
this._log(`Total files in the database: ${databaseFileNames.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
this._log(`Total files in the database: ${databaseFileNames.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
||||||
this._log(`Total files in the storage: ${storageFileNames.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
this._log(`Total files in the storage: ${storageFileNames.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
||||||
this._log(`Total files: ${allFiles.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
this._log(`Total files: ${allFiles.length}`, LOG_LEVEL_VERBOSE, "syncAll");
|
||||||
|
|
||||||
const filesExistOnlyInStorage = allFiles.filter((e) => !databaseFileNameCI2CS[e]);
|
const filesExistOnlyInStorage = allFiles.filter((e) => !databaseFileNameCI2CS[e]);
|
||||||
const filesExistOnlyInDatabase = allFiles.filter((e) => !storageFileNameCI2CS[e]);
|
const filesExistOnlyInDatabase = allFiles.filter((e) => !storageFileNameCI2CS[e]);
|
||||||
const filesExistBoth = allFiles.filter((e) => databaseFileNameCI2CS[e] && storageFileNameCI2CS[e]);
|
const filesExistBoth = allFiles.filter((e) => databaseFileNameCI2CS[e] && storageFileNameCI2CS[e]);
|
||||||
@@ -192,7 +192,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
runAll("UPDATE DATABASE", filesExistOnlyInStorage, async (e) => {
|
runAll("UPDATE DATABASE", filesExistOnlyInStorage, async (e) => {
|
||||||
// Exists in storage but not in database.
|
// Exists in storage but not in database.
|
||||||
const file = storageFileNameMap[storageFileNameCI2CS[e]];
|
const file = storageFileNameMap[storageFileNameCI2CS[e]];
|
||||||
if (!this.core.$$isFileSizeExceeded(file.stat.size)) {
|
if (!this.services.vault.isFileSizeTooLarge(file.stat.size)) {
|
||||||
const path = file.path;
|
const path = file.path;
|
||||||
await this.core.fileHandler.storeFileToDB(file);
|
await this.core.fileHandler.storeFileToDB(file);
|
||||||
// fireAndForget(() => this.checkAndApplySettingFromMarkdown(path, true));
|
// fireAndForget(() => this.checkAndApplySettingFromMarkdown(path, true));
|
||||||
@@ -208,7 +208,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
// Exists in database but not in storage.
|
// Exists in database but not in storage.
|
||||||
const path = getPath(w) ?? e;
|
const path = getPath(w) ?? e;
|
||||||
if (w && !(w.deleted || w._deleted)) {
|
if (w && !(w.deleted || w._deleted)) {
|
||||||
if (!this.core.$$isFileSizeExceeded(w.size)) {
|
if (!this.services.vault.isFileSizeTooLarge(w.size)) {
|
||||||
// Prevent applying the conflicted state to the storage.
|
// Prevent applying the conflicted state to the storage.
|
||||||
if (w._conflicts?.length ?? 0 > 0) {
|
if (w._conflicts?.length ?? 0 > 0) {
|
||||||
this._log(`UPDATE STORAGE: ${path} has conflicts. skipped (x)`, LOG_LEVEL_INFO);
|
this._log(`UPDATE STORAGE: ${path} has conflicts. skipped (x)`, LOG_LEVEL_INFO);
|
||||||
@@ -250,7 +250,10 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
this._log(`SYNC DATABASE AND STORAGE: ${file.path} has conflicts. skipped`, LOG_LEVEL_INFO);
|
this._log(`SYNC DATABASE AND STORAGE: ${file.path} has conflicts. skipped`, LOG_LEVEL_INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.core.$$isFileSizeExceeded(file.stat.size) && !this.core.$$isFileSizeExceeded(doc.size)) {
|
if (
|
||||||
|
!this.services.vault.isFileSizeTooLarge(file.stat.size) &&
|
||||||
|
!this.services.vault.isFileSizeTooLarge(doc.size)
|
||||||
|
) {
|
||||||
await this.syncFileBetweenDBandStorage(file, doc);
|
await this.syncFileBetweenDBandStorage(file, doc);
|
||||||
} else {
|
} else {
|
||||||
this._log(
|
this._log(
|
||||||
@@ -271,6 +274,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
this._log("Initialize done!", LOG_LEVEL_NOTICE, "syncAll");
|
this._log("Initialize done!", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async syncFileBetweenDBandStorage(file: UXFileInfoStub, doc: MetaEntry) {
|
async syncFileBetweenDBandStorage(file: UXFileInfoStub, doc: MetaEntry) {
|
||||||
@@ -289,7 +293,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
const compareResult = compareFileFreshness(file, doc);
|
const compareResult = compareFileFreshness(file, doc);
|
||||||
switch (compareResult) {
|
switch (compareResult) {
|
||||||
case BASE_IS_NEW:
|
case BASE_IS_NEW:
|
||||||
if (!this.core.$$isFileSizeExceeded(file.stat.size)) {
|
if (!this.services.vault.isFileSizeTooLarge(file.stat.size)) {
|
||||||
this._log("STORAGE -> DB :" + file.path);
|
this._log("STORAGE -> DB :" + file.path);
|
||||||
await this.core.fileHandler.storeFileToDB(file);
|
await this.core.fileHandler.storeFileToDB(file);
|
||||||
} else {
|
} else {
|
||||||
@@ -300,7 +304,7 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TARGET_IS_NEW:
|
case TARGET_IS_NEW:
|
||||||
if (!this.core.$$isFileSizeExceeded(doc.size)) {
|
if (!this.services.vault.isFileSizeTooLarge(doc.size)) {
|
||||||
this._log("STORAGE <- DB :" + file.path);
|
this._log("STORAGE <- DB :" + file.path);
|
||||||
if (await this.core.fileHandler.dbToStorage(doc, stripAllPrefixes(file.path), true)) {
|
if (await this.core.fileHandler.dbToStorage(doc, stripAllPrefixes(file.path), true)) {
|
||||||
eventHub.emitEvent("event-file-changed", {
|
eventHub.emitEvent("event-file-changed", {
|
||||||
@@ -365,27 +369,31 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
|
|||||||
this._log(`Checking expired file history done`);
|
this._log(`Checking expired file history done`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$initializeDatabase(
|
private async _initializeDatabase(
|
||||||
showingNotice: boolean = false,
|
showingNotice: boolean = false,
|
||||||
reopenDatabase = true,
|
reopenDatabase = true,
|
||||||
ignoreSuspending: boolean = false
|
ignoreSuspending: boolean = false
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
this.core.$$resetIsReady();
|
this.services.appLifecycle.resetIsReady();
|
||||||
if (!reopenDatabase || (await this.core.$$openDatabase())) {
|
if (!reopenDatabase || (await this.services.database.openDatabase())) {
|
||||||
if (this.localDatabase.isReady) {
|
if (this.localDatabase.isReady) {
|
||||||
await this.core.$$performFullScan(showingNotice, ignoreSuspending);
|
await this.services.vault.scanVault(showingNotice, ignoreSuspending);
|
||||||
}
|
}
|
||||||
if (!(await this.core.$everyOnDatabaseInitialized(showingNotice))) {
|
if (!(await this.services.databaseEvents.onDatabaseInitialised(showingNotice))) {
|
||||||
this._log(`Initializing database has been failed on some module`, LOG_LEVEL_NOTICE);
|
this._log(`Initializing database has been failed on some module!`, LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.core.$$markIsReady();
|
this.services.appLifecycle.markIsReady();
|
||||||
// run queued event once.
|
// run queued event once.
|
||||||
await this.core.$everyCommitPendingFileEvent();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
this.core.$$resetIsReady();
|
this.services.appLifecycle.resetIsReady();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
services.databaseEvents.handleInitialiseDatabase(this._initializeDatabase.bind(this));
|
||||||
|
services.vault.handleScanVault(this._performFullScan.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { OpenKeyValueDatabase } from "../../common/KeyValueDB.ts";
|
|||||||
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
||||||
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleKeyValueDB extends AbstractModule implements ICoreModule {
|
export class ModuleKeyValueDB extends AbstractModule {
|
||||||
tryCloseKvDB() {
|
tryCloseKvDB() {
|
||||||
try {
|
try {
|
||||||
this.core.kvDB?.close();
|
this.core.kvDB?.close();
|
||||||
@@ -22,7 +22,7 @@ export class ModuleKeyValueDB extends AbstractModule implements ICoreModule {
|
|||||||
this.tryCloseKvDB();
|
this.tryCloseKvDB();
|
||||||
await delay(10);
|
await delay(10);
|
||||||
await yieldMicrotask();
|
await yieldMicrotask();
|
||||||
this.core.kvDB = await OpenKeyValueDatabase(this.core.$$getVaultName() + "-livesync-kv");
|
this.core.kvDB = await OpenKeyValueDatabase(this.services.vault.getVaultName() + "-livesync-kv");
|
||||||
await yieldMicrotask();
|
await yieldMicrotask();
|
||||||
await delay(100);
|
await delay(100);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -33,21 +33,23 @@ export class ModuleKeyValueDB extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$allOnDBUnload(db: LiveSyncLocalDB): void {
|
_onDBUnload(db: LiveSyncLocalDB) {
|
||||||
if (this.core.kvDB) this.core.kvDB.close();
|
if (this.core.kvDB) this.core.kvDB.close();
|
||||||
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$allOnDBClose(db: LiveSyncLocalDB): void {
|
_onDBClose(db: LiveSyncLocalDB) {
|
||||||
if (this.core.kvDB) this.core.kvDB.close();
|
if (this.core.kvDB) this.core.kvDB.close();
|
||||||
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private async _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
if (!(await this.openKeyValueDB())) {
|
if (!(await this.openKeyValueDB())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.core.simpleStore = this.core.$$getSimpleStore<any>("os");
|
this.core.simpleStore = this.services.database.openSimpleStore<any>("os");
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$$getSimpleStore<T>(kind: string) {
|
_getSimpleStore<T>(kind: string) {
|
||||||
const prefix = `${kind}-`;
|
const prefix = `${kind}-`;
|
||||||
return {
|
return {
|
||||||
get: async (key: string): Promise<T> => {
|
get: async (key: string): Promise<T> => {
|
||||||
@@ -75,18 +77,18 @@ export class ModuleKeyValueDB extends AbstractModule implements ICoreModule {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
$everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
_everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
return this.openKeyValueDB();
|
return this.openKeyValueDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
async _everyOnResetDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const kvDBKey = "queued-files";
|
const kvDBKey = "queued-files";
|
||||||
await this.core.kvDB.del(kvDBKey);
|
await this.core.kvDB.del(kvDBKey);
|
||||||
// localStorage.removeItem(lsKey);
|
// localStorage.removeItem(lsKey);
|
||||||
await this.core.kvDB.destroy();
|
await this.core.kvDB.destroy();
|
||||||
await yieldMicrotask();
|
await yieldMicrotask();
|
||||||
this.core.kvDB = await OpenKeyValueDatabase(this.core.$$getVaultName() + "-livesync-kv");
|
this.core.kvDB = await OpenKeyValueDatabase(this.services.vault.getVaultName() + "-livesync-kv");
|
||||||
await delay(100);
|
await delay(100);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.core.kvDB = undefined!;
|
this.core.kvDB = undefined!;
|
||||||
@@ -96,4 +98,12 @@ export class ModuleKeyValueDB extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.databaseEvents.handleOnUnloadDatabase(this._onDBUnload.bind(this));
|
||||||
|
services.databaseEvents.handleOnCloseDatabase(this._onDBClose.bind(this));
|
||||||
|
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
|
services.databaseEvents.handleOnResetDatabase(this._everyOnResetDatabase.bind(this));
|
||||||
|
services.database.handleOpenSimpleStore(this._getSimpleStore.bind(this));
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import {
|
|||||||
eventHub,
|
eventHub,
|
||||||
} from "../../common/events.ts";
|
} from "../../common/events.ts";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
import { performDoctorConsultation, RebuildOptions } from "../../lib/src/common/configForDoc.ts";
|
import { performDoctorConsultation, RebuildOptions } from "../../lib/src/common/configForDoc.ts";
|
||||||
import { getPath, isValidPath } from "../../common/utils.ts";
|
import { getPath, isValidPath } from "../../common/utils.ts";
|
||||||
import { isMetaEntry } from "../../lib/src/common/types.ts";
|
import { isMetaEntry } from "../../lib/src/common/types.ts";
|
||||||
import { isDeletedEntry, isDocContentSame, isLoadedEntry, readAsBlob } from "../../lib/src/common/utils.ts";
|
import { isDeletedEntry, isDocContentSame, isLoadedEntry, readAsBlob } from "../../lib/src/common/utils.ts";
|
||||||
import { countCompromisedChunks } from "../../lib/src/pouchdb/negotiation.ts";
|
import { countCompromisedChunks } from "../../lib/src/pouchdb/negotiation.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
type ErrorInfo = {
|
type ErrorInfo = {
|
||||||
path: string;
|
path: string;
|
||||||
@@ -26,7 +26,7 @@ type ErrorInfo = {
|
|||||||
isConflicted?: boolean;
|
isConflicted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ModuleMigration extends AbstractModule implements ICoreModule {
|
export class ModuleMigration extends AbstractModule {
|
||||||
async migrateUsingDoctor(skipRebuild: boolean = false, activateReason = "updated", forceRescan = false) {
|
async migrateUsingDoctor(skipRebuild: boolean = false, activateReason = "updated", forceRescan = false) {
|
||||||
const { shouldRebuild, shouldRebuildLocal, isModified, settings } = await performDoctorConsultation(
|
const { shouldRebuild, shouldRebuildLocal, isModified, settings } = await performDoctorConsultation(
|
||||||
this.core,
|
this.core,
|
||||||
@@ -45,11 +45,11 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
if (!skipRebuild) {
|
if (!skipRebuild) {
|
||||||
if (shouldRebuild) {
|
if (shouldRebuild) {
|
||||||
await this.core.rebuilder.scheduleRebuild();
|
await this.core.rebuilder.scheduleRebuild();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
} else if (shouldRebuildLocal) {
|
} else if (shouldRebuildLocal) {
|
||||||
await this.core.rebuilder.scheduleFetch();
|
await this.core.rebuilder.scheduleFetch();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
if (!isValidPath(path)) {
|
if (!isValidPath(path)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(await this.core.$$isTargetFile(path, true))) {
|
if (!(await this.services.vault.isTargetFile(path, true))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isMetaEntry(metaDoc)) {
|
if (!isMetaEntry(metaDoc)) {
|
||||||
@@ -257,9 +257,9 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
// Check local database for compromised chunks
|
// Check local database for compromised chunks
|
||||||
const localCompromised = await countCompromisedChunks(this.localDatabase.localDatabase);
|
const localCompromised = await countCompromisedChunks(this.localDatabase.localDatabase);
|
||||||
const remote = this.core.$$getReplicator();
|
const remote = this.services.replicator.getActiveReplicator();
|
||||||
const remoteCompromised = this.core.managers.networkManager.isOnline
|
const remoteCompromised = this.core.managers.networkManager.isOnline
|
||||||
? await remote.countCompromisedChunks()
|
? await remote?.countCompromisedChunks()
|
||||||
: 0;
|
: 0;
|
||||||
if (localCompromised === false) {
|
if (localCompromised === false) {
|
||||||
Logger(`Failed to count compromised chunks in local database`, LOG_LEVEL_NOTICE);
|
Logger(`Failed to count compromised chunks in local database`, LOG_LEVEL_NOTICE);
|
||||||
@@ -293,12 +293,12 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
if (result === REBUILD) {
|
if (result === REBUILD) {
|
||||||
// Rebuild the database
|
// Rebuild the database
|
||||||
await this.core.rebuilder.scheduleRebuild();
|
await this.core.rebuilder.scheduleRebuild();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
} else if (result === FETCH) {
|
} else if (result === FETCH) {
|
||||||
// Fetch the latest data from remote
|
// Fetch the latest data from remote
|
||||||
await this.core.rebuilder.scheduleFetch();
|
await this.core.rebuilder.scheduleFetch();
|
||||||
await this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// User chose to dismiss the issue
|
// User chose to dismiss the issue
|
||||||
@@ -307,7 +307,7 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyOnFirstInitialize(): Promise<boolean> {
|
async _everyOnFirstInitialize(): Promise<boolean> {
|
||||||
if (!this.localDatabase.isReady) {
|
if (!this.localDatabase.isReady) {
|
||||||
this._log($msg("moduleMigration.logLocalDatabaseNotReady"), LOG_LEVEL_NOTICE);
|
this._log($msg("moduleMigration.logLocalDatabaseNotReady"), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
@@ -337,7 +337,7 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$everyOnLayoutReady(): Promise<boolean> {
|
_everyOnLayoutReady(): Promise<boolean> {
|
||||||
eventHub.onEvent(EVENT_REQUEST_RUN_DOCTOR, async (reason) => {
|
eventHub.onEvent(EVENT_REQUEST_RUN_DOCTOR, async (reason) => {
|
||||||
await this.migrateUsingDoctor(false, reason, true);
|
await this.migrateUsingDoctor(false, reason, true);
|
||||||
});
|
});
|
||||||
@@ -346,4 +346,9 @@ export class ModuleMigration extends AbstractModule implements ICoreModule {
|
|||||||
});
|
});
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
super.onBindFunction(core, services);
|
||||||
|
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
||||||
|
services.appLifecycle.handleFirstInitialise(this._everyOnFirstInitialize.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { LOG_LEVEL_DEBUG, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_DEBUG, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { Notice, requestUrl, type RequestUrlParam, type RequestUrlResponse } from "../../deps.ts";
|
import { Notice, requestUrl, type RequestUrlParam, type RequestUrlResponse } from "../../deps.ts";
|
||||||
import { type CouchDBCredentials, type EntryDoc, type FilePathWithPrefix } from "../../lib/src/common/types.ts";
|
import { type CouchDBCredentials, type EntryDoc, type FilePath } from "../../lib/src/common/types.ts";
|
||||||
import { getPathFromTFile } from "../../common/utils.ts";
|
import { getPathFromTFile } from "../../common/utils.ts";
|
||||||
import { isCloudantURI, isValidRemoteCouchDBURI } from "../../lib/src/pouchdb/utils_couchdb.ts";
|
import { isCloudantURI, isValidRemoteCouchDBURI } from "../../lib/src/pouchdb/utils_couchdb.ts";
|
||||||
import { replicationFilter } from "@/lib/src/pouchdb/compress.ts";
|
import { replicationFilter } from "@/lib/src/pouchdb/compress.ts";
|
||||||
@@ -11,6 +11,7 @@ import { setNoticeClass } from "../../lib/src/mock_and_interop/wrapper.ts";
|
|||||||
import { ObsHttpHandler } from "./APILib/ObsHttpHandler.ts";
|
import { ObsHttpHandler } from "./APILib/ObsHttpHandler.ts";
|
||||||
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser.ts";
|
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser.ts";
|
||||||
import { AuthorizationHeaderGenerator } from "../../lib/src/replication/httplib.ts";
|
import { AuthorizationHeaderGenerator } from "../../lib/src/replication/httplib.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
setNoticeClass(Notice);
|
setNoticeClass(Notice);
|
||||||
|
|
||||||
@@ -19,17 +20,17 @@ async function fetchByAPI(request: RequestUrlParam, errorAsResult = false): Prom
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModuleObsidianAPI extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianAPI extends AbstractObsidianModule {
|
||||||
_customHandler!: ObsHttpHandler;
|
_customHandler!: ObsHttpHandler;
|
||||||
|
|
||||||
_authHeader = new AuthorizationHeaderGenerator();
|
_authHeader = new AuthorizationHeaderGenerator();
|
||||||
|
|
||||||
last_successful_post = false;
|
last_successful_post = false;
|
||||||
$$customFetchHandler(): ObsHttpHandler {
|
_customFetchHandler(): ObsHttpHandler {
|
||||||
if (!this._customHandler) this._customHandler = new ObsHttpHandler(undefined, undefined);
|
if (!this._customHandler) this._customHandler = new ObsHttpHandler(undefined, undefined);
|
||||||
return this._customHandler;
|
return this._customHandler;
|
||||||
}
|
}
|
||||||
$$getLastPostFailedBySize(): boolean {
|
_getLastPostFailedBySize(): boolean {
|
||||||
return !this.last_successful_post;
|
return !this.last_successful_post;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ export class ModuleObsidianAPI extends AbstractObsidianModule implements IObsidi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$connectRemoteCouchDB(
|
async _connectRemoteCouchDB(
|
||||||
uri: string,
|
uri: string,
|
||||||
auth: CouchDBCredentials,
|
auth: CouchDBCredentials,
|
||||||
disableRequestURI: boolean,
|
disableRequestURI: boolean,
|
||||||
@@ -252,21 +253,21 @@ export class ModuleObsidianAPI extends AbstractObsidianModule implements IObsidi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$$isMobile(): boolean {
|
_isMobile(): boolean {
|
||||||
//@ts-ignore : internal API
|
//@ts-ignore : internal API
|
||||||
return this.app.isMobile;
|
return this.app.isMobile;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$vaultName(): string {
|
_vaultName(): string {
|
||||||
return this.app.vault.getName();
|
return this.app.vault.getName();
|
||||||
}
|
}
|
||||||
$$getVaultName(): string {
|
_getVaultName(): string {
|
||||||
return (
|
return (
|
||||||
this.core.$$vaultName() +
|
this.services.vault.vaultName() +
|
||||||
(this.settings?.additionalSuffixOfDatabaseName ? "-" + this.settings.additionalSuffixOfDatabaseName : "")
|
(this.settings?.additionalSuffixOfDatabaseName ? "-" + this.settings.additionalSuffixOfDatabaseName : "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$$getActiveFilePath(): FilePathWithPrefix | undefined {
|
_getActiveFilePath(): FilePath | undefined {
|
||||||
const file = this.app.workspace.getActiveFile();
|
const file = this.app.workspace.getActiveFile();
|
||||||
if (file) {
|
if (file) {
|
||||||
return getPathFromTFile(file);
|
return getPathFromTFile(file);
|
||||||
@@ -274,7 +275,18 @@ export class ModuleObsidianAPI extends AbstractObsidianModule implements IObsidi
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
$anyGetAppId(): Promise<string | undefined> {
|
_anyGetAppId(): string {
|
||||||
return Promise.resolve(`${"appId" in this.app ? this.app.appId : ""}`);
|
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
|
services.API.handleGetCustomFetchHandler(this._customFetchHandler.bind(this));
|
||||||
|
services.API.handleIsLastPostFailedDueToPayloadSize(this._getLastPostFailedBySize.bind(this));
|
||||||
|
services.remote.handleConnect(this._connectRemoteCouchDB.bind(this));
|
||||||
|
services.API.handleIsMobile(this._isMobile.bind(this));
|
||||||
|
services.vault.handleGetVaultName(this._getVaultName.bind(this));
|
||||||
|
services.vault.handleVaultName(this._vaultName.bind(this));
|
||||||
|
services.vault.handleGetActiveFilePath(this._getActiveFilePath.bind(this));
|
||||||
|
services.API.handleGetAppID(this._anyGetAppId.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { EVENT_FILE_RENAMED, EVENT_LEAF_ACTIVE_CHANGED, eventHub } from "../../common/events.js";
|
import { EVENT_FILE_RENAMED, EVENT_LEAF_ACTIVE_CHANGED, eventHub } from "../../common/events.js";
|
||||||
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
||||||
@@ -12,9 +12,10 @@ import {
|
|||||||
hiddenFilesEventCount,
|
hiddenFilesEventCount,
|
||||||
hiddenFilesProcessingCount,
|
hiddenFilesProcessingCount,
|
||||||
} from "../../lib/src/mock_and_interop/stores.ts";
|
} from "../../lib/src/mock_and_interop/stores.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleObsidianEvents extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianEvents extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
// this.registerEvent(this.app.workspace.on("editor-change", ));
|
// this.registerEvent(this.app.workspace.on("editor-change", ));
|
||||||
this.plugin.registerEvent(
|
this.plugin.registerEvent(
|
||||||
this.app.vault.on("rename", (file, oldPath) => {
|
this.app.vault.on("rename", (file, oldPath) => {
|
||||||
@@ -30,7 +31,7 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$$performRestart(): void {
|
private _performRestart(): void {
|
||||||
this._performAppReload();
|
this._performAppReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,14 +50,14 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
this.initialCallback = save;
|
this.initialCallback = save;
|
||||||
saveCommandDefinition.callback = () => {
|
saveCommandDefinition.callback = () => {
|
||||||
scheduleTask("syncOnEditorSave", 250, () => {
|
scheduleTask("syncOnEditorSave", 250, () => {
|
||||||
if (this.core.$$isUnloaded()) {
|
if (this.services.appLifecycle.hasUnloaded()) {
|
||||||
this._log("Unload and remove the handler.", LOG_LEVEL_VERBOSE);
|
this._log("Unload and remove the handler.", LOG_LEVEL_VERBOSE);
|
||||||
saveCommandDefinition.callback = this.initialCallback;
|
saveCommandDefinition.callback = this.initialCallback;
|
||||||
this.initialCallback = undefined;
|
this.initialCallback = undefined;
|
||||||
} else {
|
} else {
|
||||||
if (this.settings.syncOnEditorSave) {
|
if (this.settings.syncOnEditorSave) {
|
||||||
this._log("Sync on Editor Save.", LOG_LEVEL_VERBOSE);
|
this._log("Sync on Editor Save.", LOG_LEVEL_VERBOSE);
|
||||||
fireAndForget(() => this.core.$$replicateByEvent());
|
fireAndForget(() => this.services.replication.replicateByEvent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -106,14 +107,14 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
// TODO:FIXME AT V0.17.31, this logic has been disabled.
|
// TODO:FIXME AT V0.17.31, this logic has been disabled.
|
||||||
if (navigator.onLine && this.localDatabase.needScanning) {
|
if (navigator.onLine && this.localDatabase.needScanning) {
|
||||||
this.localDatabase.needScanning = false;
|
this.localDatabase.needScanning = false;
|
||||||
await this.core.$$performFullScan();
|
await this.services.vault.scanVault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchWindowVisibilityAsync() {
|
async watchWindowVisibilityAsync() {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
if (!this.settings.isConfigured) return;
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.core.$$isReady()) return;
|
if (!this.services.appLifecycle.isReady()) return;
|
||||||
|
|
||||||
if (this.isLastHidden && !this.hasFocus) {
|
if (this.isLastHidden && !this.hasFocus) {
|
||||||
// NO OP while non-focused after made hidden;
|
// NO OP while non-focused after made hidden;
|
||||||
@@ -126,22 +127,22 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
}
|
}
|
||||||
this.isLastHidden = isHidden;
|
this.isLastHidden = isHidden;
|
||||||
|
|
||||||
await this.core.$everyCommitPendingFileEvent();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
|
|
||||||
if (isHidden) {
|
if (isHidden) {
|
||||||
await this.core.$everyBeforeSuspendProcess();
|
await this.services.appLifecycle.onSuspending();
|
||||||
} else {
|
} else {
|
||||||
// suspend all temporary.
|
// suspend all temporary.
|
||||||
if (this.core.$$isSuspended()) return;
|
if (this.services.appLifecycle.isSuspended()) return;
|
||||||
if (!this.hasFocus) return;
|
if (!this.hasFocus) return;
|
||||||
await this.core.$everyOnResumeProcess();
|
await this.services.appLifecycle.onResuming();
|
||||||
await this.core.$everyAfterResumeProcess();
|
await this.services.appLifecycle.onResumed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
watchWorkspaceOpen(file: TFile | null) {
|
watchWorkspaceOpen(file: TFile | null) {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
if (!this.settings.isConfigured) return;
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.core.$$isReady()) return;
|
if (!this.services.appLifecycle.isReady()) return;
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file)));
|
scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file)));
|
||||||
}
|
}
|
||||||
@@ -149,25 +150,25 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
async watchWorkspaceOpenAsync(file: TFile) {
|
async watchWorkspaceOpenAsync(file: TFile) {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
if (!this.settings.isConfigured) return;
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.core.$$isReady()) return;
|
if (!this.services.appLifecycle.isReady()) return;
|
||||||
await this.core.$everyCommitPendingFileEvent();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.settings.syncOnFileOpen && !this.core.$$isSuspended()) {
|
if (this.settings.syncOnFileOpen && !this.services.appLifecycle.isSuspended()) {
|
||||||
await this.core.$$replicateByEvent();
|
await this.services.replication.replicateByEvent();
|
||||||
}
|
}
|
||||||
await this.core.$$queueConflictCheckIfOpen(file.path as FilePathWithPrefix);
|
await this.services.conflict.queueCheckForIfOpen(file.path as FilePathWithPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnLayoutReady(): Promise<boolean> {
|
_everyOnLayoutReady(): Promise<boolean> {
|
||||||
this.swapSaveCommand();
|
this.swapSaveCommand();
|
||||||
this.registerWatchEvents();
|
this.registerWatchEvents();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$$askReload(message?: string) {
|
private _askReload(message?: string) {
|
||||||
if (this.core.$$isReloadingScheduled()) {
|
if (this.services.appLifecycle.isReloadingScheduled()) {
|
||||||
this._log(`Reloading is already scheduled`, LOG_LEVEL_VERBOSE);
|
this._log(`Reloading is already scheduled`, LOG_LEVEL_VERBOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -183,11 +184,11 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
if (ret == RESTART_NOW) {
|
if (ret == RESTART_NOW) {
|
||||||
this._performAppReload();
|
this._performAppReload();
|
||||||
} else if (ret == RESTART_AFTER_STABLE) {
|
} else if (ret == RESTART_AFTER_STABLE) {
|
||||||
this.core.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$$scheduleAppReload() {
|
private _scheduleAppReload() {
|
||||||
if (!this.core._totalProcessingCount) {
|
if (!this.core._totalProcessingCount) {
|
||||||
const __tick = reactiveSource(0);
|
const __tick = reactiveSource(0);
|
||||||
this.core._totalProcessingCount = reactive(() => {
|
this.core._totalProcessingCount = reactive(() => {
|
||||||
@@ -237,4 +238,11 @@ export class ModuleObsidianEvents extends AbstractObsidianModule implements IObs
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handlePerformRestart(this._performRestart.bind(this));
|
||||||
|
services.appLifecycle.handleAskRestart(this._askReload.bind(this));
|
||||||
|
services.appLifecycle.handleScheduleRestart(this._scheduleAppReload.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { fireAndForget } from "octagonal-wheels/promises";
|
import { fireAndForget } from "octagonal-wheels/promises";
|
||||||
import { addIcon, type Editor, type MarkdownFileInfo, type MarkdownView } from "../../deps.ts";
|
import { addIcon, type Editor, type MarkdownFileInfo, type MarkdownView } from "../../deps.ts";
|
||||||
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types.ts";
|
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types.ts";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianMenu extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
// UI
|
// UI
|
||||||
addIcon(
|
addIcon(
|
||||||
"replicate",
|
"replicate",
|
||||||
@@ -18,21 +19,21 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.addRibbonIcon("replicate", $msg("moduleObsidianMenu.replicate"), async () => {
|
this.addRibbonIcon("replicate", $msg("moduleObsidianMenu.replicate"), async () => {
|
||||||
await this.core.$$replicate(true);
|
await this.services.replication.replicate(true);
|
||||||
}).addClass("livesync-ribbon-replicate");
|
}).addClass("livesync-ribbon-replicate");
|
||||||
|
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-replicate",
|
id: "livesync-replicate",
|
||||||
name: "Replicate now",
|
name: "Replicate now",
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-dump",
|
id: "livesync-dump",
|
||||||
name: "Dump information of this doc ",
|
name: "Dump information of this doc ",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const file = this.core.$$getActiveFilePath();
|
const file = this.services.vault.getActiveFilePath();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
fireAndForget(() => this.localDatabase.getDBEntry(file, {}, true, false));
|
fireAndForget(() => this.localDatabase.getDBEntry(file, {}, true, false));
|
||||||
},
|
},
|
||||||
@@ -43,7 +44,7 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
editorCallback: (editor: Editor, view: MarkdownView | MarkdownFileInfo) => {
|
editorCallback: (editor: Editor, view: MarkdownView | MarkdownFileInfo) => {
|
||||||
const file = view.file;
|
const file = view.file;
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
void this.core.$$queueConflictCheckIfOpen(file.path as FilePathWithPrefix);
|
void this.services.conflict.queueCheckForIfOpen(file.path as FilePathWithPrefix);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,23 +59,23 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
this.settings.liveSync = true;
|
this.settings.liveSync = true;
|
||||||
this._log("LiveSync Enabled.", LOG_LEVEL_NOTICE);
|
this._log("LiveSync Enabled.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
await this.core.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-suspendall",
|
id: "livesync-suspendall",
|
||||||
name: "Toggle All Sync.",
|
name: "Toggle All Sync.",
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
if (this.core.$$isSuspended()) {
|
if (this.services.appLifecycle.isSuspended()) {
|
||||||
this.core.$$setSuspended(false);
|
this.services.appLifecycle.setSuspended(false);
|
||||||
this._log("Self-hosted LiveSync resumed", LOG_LEVEL_NOTICE);
|
this._log("Self-hosted LiveSync resumed", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
this.core.$$setSuspended(true);
|
this.services.appLifecycle.setSuspended(true);
|
||||||
this._log("Self-hosted LiveSync suspended", LOG_LEVEL_NOTICE);
|
this._log("Self-hosted LiveSync suspended", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
await this.core.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
id: "livesync-scan-files",
|
id: "livesync-scan-files",
|
||||||
name: "Scan storage and database again",
|
name: "Scan storage and database again",
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
await this.core.$$performFullScan(true);
|
await this.services.vault.scanVault(true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
id: "livesync-runbatch",
|
id: "livesync-runbatch",
|
||||||
name: "Run pended batch processes",
|
name: "Run pended batch processes",
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
await this.core.$everyCommitPendingFileEvent();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -104,12 +105,15 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
});
|
});
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyOnload(): Promise<boolean> {
|
_onWorkspaceReady() {
|
||||||
this.app.workspace.onLayoutReady(this.core.$$onLiveSyncReady.bind(this.core));
|
void this.services.appLifecycle.onReady();
|
||||||
|
}
|
||||||
|
private _everyOnload(): Promise<boolean> {
|
||||||
|
this.app.workspace.onLayoutReady(this._onWorkspaceReady.bind(this));
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$showView(viewType: string) {
|
private async _showView(viewType: string) {
|
||||||
const leaves = this.app.workspace.getLeavesOfType(viewType);
|
const leaves = this.app.workspace.getLeavesOfType(viewType);
|
||||||
if (leaves.length == 0) {
|
if (leaves.length == 0) {
|
||||||
await this.app.workspace.getLeaf(true).setViewState({
|
await this.app.workspace.getLeaf(true).setViewState({
|
||||||
@@ -126,4 +130,9 @@ export class ModuleObsidianMenu extends AbstractObsidianModule implements IObsid
|
|||||||
await this.app.workspace.revealLeaf(leaves[0]);
|
await this.app.workspace.revealLeaf(leaves[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.API.handleShowWindow(this._showView.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
|
|
||||||
export class ModuleExtraSyncObsidian extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleExtraSyncObsidian extends AbstractObsidianModule {
|
||||||
deviceAndVaultName: string = "";
|
deviceAndVaultName: string = "";
|
||||||
|
|
||||||
$$getDeviceAndVaultName(): string {
|
_getDeviceAndVaultName(): string {
|
||||||
return this.deviceAndVaultName;
|
return this.deviceAndVaultName;
|
||||||
}
|
}
|
||||||
$$setDeviceAndVaultName(name: string): void {
|
_setDeviceAndVaultName(name: string): void {
|
||||||
this.deviceAndVaultName = name;
|
this.deviceAndVaultName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.setting.handleGetDeviceAndVaultName(this._getDeviceAndVaultName.bind(this));
|
||||||
|
services.setting.handleSetDeviceAndVaultName(this._setDeviceAndVaultName.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { delay, fireAndForget } from "octagonal-wheels/promises";
|
import { delay, fireAndForget } from "octagonal-wheels/promises";
|
||||||
import { __onMissingTranslation } from "../../lib/src/common/i18n";
|
import { __onMissingTranslation } from "../../lib/src/common/i18n";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { eventHub } from "../../common/events";
|
import { eventHub } from "../../common/events";
|
||||||
import { enableTestFunction } from "./devUtil/testUtils.ts";
|
import { enableTestFunction } from "./devUtil/testUtils.ts";
|
||||||
import { TestPaneView, VIEW_TYPE_TEST } from "./devUtil/TestPaneView.ts";
|
import { TestPaneView, VIEW_TYPE_TEST } from "./devUtil/TestPaneView.ts";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import type { FilePathWithPrefix } from "../../lib/src/common/types.ts";
|
import type { FilePathWithPrefix } from "../../lib/src/common/types.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleDev extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleDev extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
__onMissingTranslation(() => {});
|
__onMissingTranslation(() => {});
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
this.onMissingTranslation = this.onMissingTranslation.bind(this);
|
this.onMissingTranslation = this.onMissingTranslation.bind(this);
|
||||||
__onMissingTranslation((key) => {
|
__onMissingTranslation((key) => {
|
||||||
@@ -92,12 +93,12 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
|
|||||||
id: "view-test",
|
id: "view-test",
|
||||||
name: "Open Test dialogue",
|
name: "Open Test dialogue",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
void this.core.$$showView(VIEW_TYPE_TEST);
|
void this.services.API.showWindow(VIEW_TYPE_TEST);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
async $everyOnLayoutReady(): Promise<boolean> {
|
async _everyOnLayoutReady(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
// if (await this.core.storageAccess.isExistsIncludeHidden("_SHOWDIALOGAUTO.md")) {
|
// if (await this.core.storageAccess.isExistsIncludeHidden("_SHOWDIALOGAUTO.md")) {
|
||||||
// void this.core.$$showView(VIEW_TYPE_TEST);
|
// void this.core.$$showView(VIEW_TYPE_TEST);
|
||||||
@@ -121,7 +122,7 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (w) {
|
if (w) {
|
||||||
const id = await this.core.$$path2id(filename as FilePathWithPrefix);
|
const id = await this.services.path.path2id(filename as FilePathWithPrefix);
|
||||||
const f = await this.core.localDatabase.getRaw(id);
|
const f = await this.core.localDatabase.getRaw(id);
|
||||||
console.log(f);
|
console.log(f);
|
||||||
console.log(f._rev);
|
console.log(f._rev);
|
||||||
@@ -139,14 +140,14 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
|
|||||||
testResults = writable<[boolean, string, string][]>([]);
|
testResults = writable<[boolean, string, string][]>([]);
|
||||||
// testResults: string[] = [];
|
// testResults: string[] = [];
|
||||||
|
|
||||||
$$addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void {
|
private _addTestResult(name: string, key: string, result: boolean, summary?: string, message?: string): void {
|
||||||
const logLine = `${name}: ${key} ${summary ?? ""}`;
|
const logLine = `${name}: ${key} ${summary ?? ""}`;
|
||||||
this.testResults.update((results) => {
|
this.testResults.update((results) => {
|
||||||
results.push([result, logLine, message ?? ""]);
|
results.push([result, logLine, message ?? ""]);
|
||||||
return results;
|
return results;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$everyModuleTest(): Promise<boolean> {
|
private _everyModuleTest(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
// this.core.$$addTestResult("DevModule", "Test", true);
|
// this.core.$$addTestResult("DevModule", "Test", true);
|
||||||
// return Promise.resolve(true);
|
// return Promise.resolve(true);
|
||||||
@@ -155,4 +156,11 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
|
|||||||
// this.addTestResult("Test of test3", true);
|
// this.addTestResult("Test of test3", true);
|
||||||
return this.testDone();
|
return this.testDone();
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
services.test.handleTest(this._everyModuleTest.bind(this));
|
||||||
|
services.test.handleAddTestResult(this._addTestResult.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { delay } from "octagonal-wheels/promises";
|
import { delay } from "octagonal-wheels/promises";
|
||||||
import { LOG_LEVEL_NOTICE, REMOTE_MINIO, type FilePathWithPrefix } from "src/lib/src/common/types";
|
import { LOG_LEVEL_NOTICE, REMOTE_MINIO, type FilePathWithPrefix } from "src/lib/src/common/types";
|
||||||
import { shareRunningResult } from "octagonal-wheels/concurrency/lock";
|
import { shareRunningResult } from "octagonal-wheels/concurrency/lock";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule";
|
||||||
|
|
||||||
export class ModuleIntegratedTest extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleIntegratedTest extends AbstractObsidianModule {
|
||||||
async waitFor(proc: () => Promise<boolean>, timeout = 10000): Promise<boolean> {
|
async waitFor(proc: () => Promise<boolean>, timeout = 10000): Promise<boolean> {
|
||||||
await delay(100);
|
await delay(100);
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
@@ -54,7 +54,7 @@ export class ModuleIntegratedTest extends AbstractObsidianModule implements IObs
|
|||||||
tryReplicate() {
|
tryReplicate() {
|
||||||
if (!this.settings.liveSync) {
|
if (!this.settings.liveSync) {
|
||||||
return shareRunningResult("replicate-test", async () => {
|
return shareRunningResult("replicate-test", async () => {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ export class ModuleIntegratedTest extends AbstractObsidianModule implements IObs
|
|||||||
const stepFile = "_STEP.md" as FilePathWithPrefix;
|
const stepFile = "_STEP.md" as FilePathWithPrefix;
|
||||||
const stepAckFile = "_STEP_ACK.md" as FilePathWithPrefix;
|
const stepAckFile = "_STEP_ACK.md" as FilePathWithPrefix;
|
||||||
const stepContent = `Step ${no}`;
|
const stepContent = `Step ${no}`;
|
||||||
await this.core.$anyResolveConflictByNewest(stepFile);
|
await this.services.conflict.resolveByNewest(stepFile);
|
||||||
await this.core.storageAccess.writeFileAuto(stepFile, stepContent);
|
await this.core.storageAccess.writeFileAuto(stepFile, stepContent);
|
||||||
await this._orDie(`Wait for acknowledge ${no}`, async () => {
|
await this._orDie(`Wait for acknowledge ${no}`, async () => {
|
||||||
if (
|
if (
|
||||||
@@ -96,7 +96,7 @@ export class ModuleIntegratedTest extends AbstractObsidianModule implements IObs
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
await this.core.$anyResolveConflictByNewest(stepAckFile);
|
await this.services.conflict.resolveByNewest(stepAckFile);
|
||||||
await this.core.storageAccess.writeFileAuto(stepAckFile, stepContent);
|
await this.core.storageAccess.writeFileAuto(stepAckFile, stepContent);
|
||||||
await this.tryReplicate();
|
await this.tryReplicate();
|
||||||
return true;
|
return true;
|
||||||
@@ -424,9 +424,9 @@ Line4:D`;
|
|||||||
await this._test("basic", async () => await this.nonLiveTestRunner(isLeader, (t, l) => this.testBasic(t, l)));
|
await this._test("basic", async () => await this.nonLiveTestRunner(isLeader, (t, l) => this.testBasic(t, l)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $everyModuleTestMultiDevice(): Promise<boolean> {
|
async _everyModuleTestMultiDevice(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
const isLeader = this.core.$$vaultName().indexOf("recv") === -1;
|
const isLeader = this.core.services.vault.vaultName().indexOf("recv") === -1;
|
||||||
this.addTestResult("-------", true, `Test as ${isLeader ? "Leader" : "Receiver"}`);
|
this.addTestResult("-------", true, `Test as ${isLeader ? "Leader" : "Receiver"}`);
|
||||||
try {
|
try {
|
||||||
this._log(`Starting Test`);
|
this._log(`Starting Test`);
|
||||||
@@ -440,4 +440,7 @@ Line4:D`;
|
|||||||
|
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
|
services.test.handleTestMultiDevice(this._everyModuleTestMultiDevice.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { delay } from "octagonal-wheels/promises";
|
import { delay } from "octagonal-wheels/promises";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { eventHub } from "../../common/events";
|
import { eventHub } from "../../common/events";
|
||||||
import { getWebCrypto } from "../../lib/src/mods.ts";
|
import { getWebCrypto } from "../../lib/src/mods.ts";
|
||||||
@@ -8,6 +8,7 @@ import { parseYaml, requestUrl, stringifyYaml } from "obsidian";
|
|||||||
import type { FilePath } from "../../lib/src/common/types.ts";
|
import type { FilePath } from "../../lib/src/common/types.ts";
|
||||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
||||||
import { getFileRegExp } from "../../lib/src/common/utils.ts";
|
import { getFileRegExp } from "../../lib/src/common/utils.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface LSEvents {
|
interface LSEvents {
|
||||||
@@ -15,12 +16,15 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModuleReplicateTest extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleReplicateTest extends AbstractObsidianModule {
|
||||||
testRootPath = "_test/";
|
testRootPath = "_test/";
|
||||||
testInfoPath = "_testinfo/";
|
testInfoPath = "_testinfo/";
|
||||||
|
|
||||||
get isLeader() {
|
get isLeader() {
|
||||||
return this.core.$$getVaultName().indexOf("dev") >= 0 && this.core.$$vaultName().indexOf("recv") < 0;
|
return (
|
||||||
|
this.services.vault.getVaultName().indexOf("dev") >= 0 &&
|
||||||
|
this.services.vault.vaultName().indexOf("recv") < 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get nameByKind() {
|
get nameByKind() {
|
||||||
@@ -58,12 +62,12 @@ export class ModuleReplicateTest extends AbstractObsidianModule implements IObsi
|
|||||||
await this._dumpFileList("files.md");
|
await this._dumpFileList("files.md");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async $everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
async _everyBeforeReplicate(showMessage: boolean): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
await this.dumpList();
|
await this.dumpList();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "dump-file-structure-normal",
|
id: "dump-file-structure-normal",
|
||||||
@@ -169,7 +173,7 @@ export class ModuleReplicateTest extends AbstractObsidianModule implements IObsi
|
|||||||
const out = [] as any[];
|
const out = [] as any[];
|
||||||
const webcrypto = await getWebCrypto();
|
const webcrypto = await getWebCrypto();
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (!(await this.core.$$isTargetFile(file.path))) {
|
if (!(await this.services.vault.isTargetFile(file.path))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (file.path.startsWith(this.testInfoPath)) continue;
|
if (file.path.startsWith(this.testInfoPath)) continue;
|
||||||
@@ -316,7 +320,7 @@ export class ModuleReplicateTest extends AbstractObsidianModule implements IObsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
async testConflictedManually1() {
|
async testConflictedManually1() {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
|
|
||||||
const commonFile = `Resolve!
|
const commonFile = `Resolve!
|
||||||
*****, the amazing chocolatier!!`;
|
*****, the amazing chocolatier!!`;
|
||||||
@@ -325,8 +329,8 @@ export class ModuleReplicateTest extends AbstractObsidianModule implements IObsi
|
|||||||
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "wonka.md", commonFile);
|
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "wonka.md", commonFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
if (
|
if (
|
||||||
(await this.core.confirm.askYesNoDialog("Ready to begin the test conflict Manually 1?", {
|
(await this.core.confirm.askYesNoDialog("Ready to begin the test conflict Manually 1?", {
|
||||||
timeout: 30,
|
timeout: 30,
|
||||||
@@ -356,12 +360,12 @@ Charlie Bucket, Charlie Bucket, the amazing chocolatier!!`;
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!(await this.waitFor(async () => {
|
!(await this.waitFor(async () => {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
return (
|
return (
|
||||||
(await this.__assertStorageContent(
|
(await this.__assertStorageContent(
|
||||||
(this.testRootPath + "wonka.md") as FilePath,
|
(this.testRootPath + "wonka.md") as FilePath,
|
||||||
@@ -379,7 +383,7 @@ Charlie Bucket, Charlie Bucket, the amazing chocolatier!!`;
|
|||||||
}
|
}
|
||||||
|
|
||||||
async testConflictedManually2() {
|
async testConflictedManually2() {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
|
|
||||||
const commonFile = `Resolve To concatenate
|
const commonFile = `Resolve To concatenate
|
||||||
ABCDEFG`;
|
ABCDEFG`;
|
||||||
@@ -388,8 +392,8 @@ ABCDEFG`;
|
|||||||
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "concat.md", commonFile);
|
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "concat.md", commonFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
if (
|
if (
|
||||||
(await this.core.confirm.askYesNoDialog("Ready to begin the test conflict Manually 2?", {
|
(await this.core.confirm.askYesNoDialog("Ready to begin the test conflict Manually 2?", {
|
||||||
timeout: 30,
|
timeout: 30,
|
||||||
@@ -420,12 +424,12 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!(await this.waitFor(async () => {
|
!(await this.waitFor(async () => {
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
return (
|
return (
|
||||||
(await this.__assertStorageContent(
|
(await this.__assertStorageContent(
|
||||||
(this.testRootPath + "concat.md") as FilePath,
|
(this.testRootPath + "concat.md") as FilePath,
|
||||||
@@ -457,8 +461,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "task.md", baseDoc);
|
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "task.md", baseDoc);
|
||||||
}
|
}
|
||||||
await delay(100);
|
await delay(100);
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(await this.core.confirm.askYesNoDialog("Ready to test conflict?", {
|
(await this.core.confirm.askYesNoDialog("Ready to test conflict?", {
|
||||||
@@ -487,8 +491,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "task.md", mod2Doc);
|
await this.core.storageAccess.writeHiddenFileAuto(this.testRootPath + "task.md", mod2Doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
if (
|
if (
|
||||||
(await this.core.confirm.askYesNoDialog("Ready to check result?", { timeout: 30, defaultOption: "Yes" })) ==
|
(await this.core.confirm.askYesNoDialog("Ready to check result?", { timeout: 30, defaultOption: "Yes" })) ==
|
||||||
@@ -496,8 +500,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
const mergedDoc = `Tasks!
|
const mergedDoc = `Tasks!
|
||||||
- [ ] Task 1
|
- [ ] Task 1
|
||||||
- [v] Task 2
|
- [v] Task 2
|
||||||
@@ -511,7 +515,7 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
this._log("Before testing conflicted files, resolve all once", LOG_LEVEL_NOTICE);
|
this._log("Before testing conflicted files, resolve all once", LOG_LEVEL_NOTICE);
|
||||||
await this.core.rebuilder.resolveAllConflictedFilesByNewerOnes();
|
await this.core.rebuilder.resolveAllConflictedFilesByNewerOnes();
|
||||||
await this.core.rebuilder.resolveAllConflictedFilesByNewerOnes();
|
await this.core.rebuilder.resolveAllConflictedFilesByNewerOnes();
|
||||||
await this.core.$$replicate();
|
await this.services.replication.replicate();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
if (!(await this.testConflictAutomatic())) {
|
if (!(await this.testConflictAutomatic())) {
|
||||||
this._log("Conflict resolution (Auto) failed", LOG_LEVEL_NOTICE);
|
this._log("Conflict resolution (Auto) failed", LOG_LEVEL_NOTICE);
|
||||||
@@ -569,11 +573,16 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
// return results;
|
// return results;
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
async $everyModuleTestMultiDevice(): Promise<boolean> {
|
private async _everyModuleTestMultiDevice(): Promise<boolean> {
|
||||||
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
if (!this.settings.enableDebugTools) return Promise.resolve(true);
|
||||||
// this.core.$$addTestResult("DevModule", "Test", true);
|
// this.core.$$addTestResult("DevModule", "Test", true);
|
||||||
// return Promise.resolve(true);
|
// return Promise.resolve(true);
|
||||||
await this._test("Conflict resolution", async () => await this.checkConflictResolution());
|
await this._test("Conflict resolution", async () => await this.checkConflictResolution());
|
||||||
return this.testDone();
|
return this.testDone();
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
||||||
|
services.test.handleTestMultiDevice(this._everyModuleTestMultiDevice.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,14 +57,14 @@
|
|||||||
function moduleMultiDeviceTest() {
|
function moduleMultiDeviceTest() {
|
||||||
if (moduleTesting) return;
|
if (moduleTesting) return;
|
||||||
moduleTesting = true;
|
moduleTesting = true;
|
||||||
plugin.$everyModuleTestMultiDevice().finally(() => {
|
plugin.services.test.testMultiDevice().finally(() => {
|
||||||
moduleTesting = false;
|
moduleTesting = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function moduleSingleDeviceTest() {
|
function moduleSingleDeviceTest() {
|
||||||
if (moduleTesting) return;
|
if (moduleTesting) return;
|
||||||
moduleTesting = true;
|
moduleTesting = true;
|
||||||
plugin.$everyModuleTest().finally(() => {
|
plugin.services.test.test().finally(() => {
|
||||||
moduleTesting = false;
|
moduleTesting = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
if (moduleTesting) return;
|
if (moduleTesting) return;
|
||||||
moduleTesting = true;
|
moduleTesting = true;
|
||||||
try {
|
try {
|
||||||
await plugin.$everyModuleTest();
|
await plugin.services.test.test();
|
||||||
await plugin.$everyModuleTestMultiDevice();
|
await plugin.services.test.testMultiDevice();
|
||||||
} finally {
|
} finally {
|
||||||
moduleTesting = false;
|
moduleTesting = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ function readDocument(w: LoadedEntry) {
|
|||||||
}
|
}
|
||||||
export class DocumentHistoryModal extends Modal {
|
export class DocumentHistoryModal extends Modal {
|
||||||
plugin: ObsidianLiveSyncPlugin;
|
plugin: ObsidianLiveSyncPlugin;
|
||||||
|
get services() {
|
||||||
|
return this.plugin.services;
|
||||||
|
}
|
||||||
range!: HTMLInputElement;
|
range!: HTMLInputElement;
|
||||||
contentView!: HTMLDivElement;
|
contentView!: HTMLDivElement;
|
||||||
info!: HTMLDivElement;
|
info!: HTMLDivElement;
|
||||||
@@ -74,7 +77,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.initialRev = revision;
|
this.initialRev = revision;
|
||||||
if (!file && id) {
|
if (!file && id) {
|
||||||
this.file = this.plugin.$$id2path(id);
|
this.file = this.services.path.id2path(id);
|
||||||
}
|
}
|
||||||
if (localStorage.getItem("ols-history-highlightdiff") == "1") {
|
if (localStorage.getItem("ols-history-highlightdiff") == "1") {
|
||||||
this.showDiff = true;
|
this.showDiff = true;
|
||||||
@@ -83,7 +86,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
|
|
||||||
async loadFile(initialRev?: string) {
|
async loadFile(initialRev?: string) {
|
||||||
if (!this.id) {
|
if (!this.id) {
|
||||||
this.id = await this.plugin.$$path2id(this.file);
|
this.id = await this.services.path.path2id(this.file);
|
||||||
}
|
}
|
||||||
const db = this.plugin.localDatabase;
|
const db = this.plugin.localDatabase;
|
||||||
try {
|
try {
|
||||||
@@ -126,7 +129,7 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
}
|
}
|
||||||
this.BlobURLs.delete(key);
|
this.BlobURLs.delete(key);
|
||||||
}
|
}
|
||||||
generateBlobURL(key: string, data: Uint8Array) {
|
generateBlobURL(key: string, data: Uint8Array<ArrayBuffer>) {
|
||||||
this.revokeURL(key);
|
this.revokeURL(key);
|
||||||
const v = URL.createObjectURL(new Blob([data], { endings: "transparent", type: "application/octet-stream" }));
|
const v = URL.createObjectURL(new Blob([data], { endings: "transparent", type: "application/octet-stream" }));
|
||||||
this.BlobURLs.set(key, v);
|
this.BlobURLs.set(key, v);
|
||||||
@@ -175,7 +178,10 @@ export class DocumentHistoryModal extends Modal {
|
|||||||
result = result.replace(/\n/g, "<br>");
|
result = result.replace(/\n/g, "<br>");
|
||||||
} else if (isImage(this.file)) {
|
} else if (isImage(this.file)) {
|
||||||
const src = this.generateBlobURL("base", w1data);
|
const src = this.generateBlobURL("base", w1data);
|
||||||
const overlay = this.generateBlobURL("overlay", readDocument(w2) as Uint8Array);
|
const overlay = this.generateBlobURL(
|
||||||
|
"overlay",
|
||||||
|
readDocument(w2) as Uint8Array<ArrayBuffer>
|
||||||
|
);
|
||||||
result = `<div class='ls-imgdiff-wrap'>
|
result = `<div class='ls-imgdiff-wrap'>
|
||||||
<div class='overlay'>
|
<div class='overlay'>
|
||||||
<img class='img-base' src="${src}">
|
<img class='img-base' src="${src}">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { VIEW_TYPE_GLOBAL_HISTORY, GlobalHistoryView } from "./GlobalHistory/GlobalHistoryView.ts";
|
import { VIEW_TYPE_GLOBAL_HISTORY, GlobalHistoryView } from "./GlobalHistory/GlobalHistoryView.ts";
|
||||||
|
|
||||||
export class ModuleObsidianGlobalHistory extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianGlobalHistory extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-global-history",
|
id: "livesync-global-history",
|
||||||
name: "Show vault history",
|
name: "Show vault history",
|
||||||
@@ -17,6 +17,9 @@ export class ModuleObsidianGlobalHistory extends AbstractObsidianModule implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
showGlobalHistory() {
|
showGlobalHistory() {
|
||||||
void this.core.$$showView(VIEW_TYPE_GLOBAL_HISTORY);
|
void this.services.API.showWindow(VIEW_TYPE_GLOBAL_HISTORY);
|
||||||
|
}
|
||||||
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import {
|
|||||||
type diff_result,
|
type diff_result,
|
||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { ConflictResolveModal } from "./InteractiveConflictResolving/ConflictResolveModal.ts";
|
import { ConflictResolveModal } from "./InteractiveConflictResolving/ConflictResolveModal.ts";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { displayRev, getPath, getPathWithoutPrefix } from "../../common/utils.ts";
|
import { displayRev, getPath, getPathWithoutPrefix } from "../../common/utils.ts";
|
||||||
import { fireAndForget } from "octagonal-wheels/promises";
|
import { fireAndForget } from "octagonal-wheels/promises";
|
||||||
import { serialized } from "octagonal-wheels/concurrency/lock";
|
import { serialized } from "octagonal-wheels/concurrency/lock";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleInteractiveConflictResolver extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleInteractiveConflictResolver extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-conflictcheck",
|
id: "livesync-conflictcheck",
|
||||||
name: "Pick a file to resolve conflict",
|
name: "Pick a file to resolve conflict",
|
||||||
@@ -34,7 +35,7 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $anyResolveConflictByUI(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise<boolean> {
|
async _anyResolveConflictByUI(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise<boolean> {
|
||||||
// UI for resolving conflicts should one-by-one.
|
// UI for resolving conflicts should one-by-one.
|
||||||
return await serialized(`conflict-resolve-ui`, async () => {
|
return await serialized(`conflict-resolve-ui`, async () => {
|
||||||
this._log("Merge:open conflict dialog", LOG_LEVEL_VERBOSE);
|
this._log("Merge:open conflict dialog", LOG_LEVEL_VERBOSE);
|
||||||
@@ -68,7 +69,7 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
}
|
}
|
||||||
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
||||||
if (
|
if (
|
||||||
(await this.core.$$resolveConflictByDeletingRev(filename, delRev, "UI Concatenated")) ==
|
(await this.services.conflict.resolveByDeletingRevision(filename, delRev, "UI Concatenated")) ==
|
||||||
MISSING_OR_ERROR
|
MISSING_OR_ERROR
|
||||||
) {
|
) {
|
||||||
this._log(
|
this._log(
|
||||||
@@ -80,7 +81,7 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
} else if (typeof toDelete === "string") {
|
} else if (typeof toDelete === "string") {
|
||||||
// Select one of the conflicted revision to delete.
|
// Select one of the conflicted revision to delete.
|
||||||
if (
|
if (
|
||||||
(await this.core.$$resolveConflictByDeletingRev(filename, toDelete, "UI Selected")) ==
|
(await this.services.conflict.resolveByDeletingRevision(filename, toDelete, "UI Selected")) ==
|
||||||
MISSING_OR_ERROR
|
MISSING_OR_ERROR
|
||||||
) {
|
) {
|
||||||
this._log(`Merge: Something went wrong: ${filename}, (${toDelete})`, LOG_LEVEL_NOTICE);
|
this._log(`Merge: Something went wrong: ${filename}, (${toDelete})`, LOG_LEVEL_NOTICE);
|
||||||
@@ -93,11 +94,11 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
// In here, some merge has been processed.
|
// In here, some merge has been processed.
|
||||||
// So we have to run replication if configured.
|
// So we have to run replication if configured.
|
||||||
// TODO: Make this is as a event request
|
// TODO: Make this is as a event request
|
||||||
if (this.settings.syncAfterMerge && !this.core.$$isSuspended()) {
|
if (this.settings.syncAfterMerge && !this.services.appLifecycle.isSuspended()) {
|
||||||
await this.core.$$replicateByEvent();
|
await this.services.replication.replicateByEvent();
|
||||||
}
|
}
|
||||||
// And, check it again.
|
// And, check it again.
|
||||||
await this.core.$$queueConflictCheck(filename);
|
await this.services.conflict.queueCheckFor(filename);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -120,14 +121,14 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
const target = await this.core.confirm.askSelectString("File to resolve conflict", notesList);
|
const target = await this.core.confirm.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)!;
|
||||||
await this.core.$$queueConflictCheck(targetItem.path);
|
await this.services.conflict.queueCheckFor(targetItem.path);
|
||||||
await this.core.$$waitForAllConflictProcessed();
|
await this.services.conflict.ensureAllProcessed();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $allScanStat(): Promise<boolean> {
|
async _allScanStat(): Promise<boolean> {
|
||||||
const notes: { path: string; mtime: number }[] = [];
|
const notes: { path: string; mtime: number }[] = [];
|
||||||
this._log(`Checking conflicted files`, LOG_LEVEL_VERBOSE);
|
this._log(`Checking conflicted files`, LOG_LEVEL_VERBOSE);
|
||||||
for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) {
|
for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) {
|
||||||
@@ -157,4 +158,9 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnScanningStartupIssues(this._allScanStat.bind(this));
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.conflict.handleResolveByUserInteraction(this._anyResolveConflictByUI.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from "../../lib/src/mock_and_interop/stores.ts";
|
} from "../../lib/src/mock_and_interop/stores.ts";
|
||||||
import { eventHub } from "../../lib/src/hub/hub.ts";
|
import { eventHub } from "../../lib/src/hub/hub.ts";
|
||||||
import { EVENT_FILE_RENAMED, EVENT_LAYOUT_READY, EVENT_LEAF_ACTIVE_CHANGED } from "../../common/events.ts";
|
import { EVENT_FILE_RENAMED, EVENT_LAYOUT_READY, EVENT_LEAF_ACTIVE_CHANGED } from "../../common/events.ts";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { addIcon, normalizePath, Notice } from "../../deps.ts";
|
import { addIcon, normalizePath, Notice } from "../../deps.ts";
|
||||||
import { LOG_LEVEL_NOTICE, setGlobalLogFunction } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_NOTICE, setGlobalLogFunction } from "octagonal-wheels/common/logger";
|
||||||
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
|
||||||
@@ -28,6 +28,7 @@ import { LogPaneView, VIEW_TYPE_LOG } from "./Log/LogPaneView.ts";
|
|||||||
import { serialized } from "octagonal-wheels/concurrency/lock";
|
import { serialized } from "octagonal-wheels/concurrency/lock";
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
import { $msg } from "src/lib/src/common/i18n.ts";
|
||||||
import { P2PLogCollector } from "../../lib/src/replication/trystero/P2PReplicatorCore.ts";
|
import { P2PLogCollector } from "../../lib/src/replication/trystero/P2PReplicatorCore.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
// This module cannot be a core module because it depends on the Obsidian UI.
|
// This module cannot be a core module because it depends on the Obsidian UI.
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ const recentLogProcessor = new QueueProcessor(
|
|||||||
|
|
||||||
const showDebugLog = false;
|
const showDebugLog = false;
|
||||||
export const MARK_DONE = "\u{2009}\u{2009}";
|
export const MARK_DONE = "\u{2009}\u{2009}";
|
||||||
export class ModuleLog extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleLog extends AbstractObsidianModule {
|
||||||
registerView = this.plugin.registerView.bind(this.plugin);
|
registerView = this.plugin.registerView.bind(this.plugin);
|
||||||
|
|
||||||
statusBar?: HTMLElement;
|
statusBar?: HTMLElement;
|
||||||
@@ -178,7 +179,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
});
|
});
|
||||||
|
|
||||||
const statusBarLabels = reactive(() => {
|
const statusBarLabels = reactive(() => {
|
||||||
const scheduleMessage = this.core.$$isReloadingScheduled()
|
const scheduleMessage = this.services.appLifecycle.isReloadingScheduled()
|
||||||
? `WARNING! RESTARTING OBSIDIAN IS SCHEDULED!\n`
|
? `WARNING! RESTARTING OBSIDIAN IS SCHEDULED!\n`
|
||||||
: "";
|
: "";
|
||||||
const { message } = statusLineLabel();
|
const { message } = statusLineLabel();
|
||||||
@@ -199,7 +200,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
statusBarLabels.onChanged((label) => applyToDisplay(label.value));
|
statusBarLabels.onChanged((label) => applyToDisplay(label.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
eventHub.onEvent(EVENT_LEAF_ACTIVE_CHANGED, () => this.onActiveLeafChange());
|
eventHub.onEvent(EVENT_LEAF_ACTIVE_CHANGED, () => this.onActiveLeafChange());
|
||||||
eventHub.onceEvent(EVENT_LAYOUT_READY, () => this.onActiveLeafChange());
|
eventHub.onceEvent(EVENT_LAYOUT_READY, () => this.onActiveLeafChange());
|
||||||
|
|
||||||
@@ -219,15 +220,15 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
const thisFile = this.app.workspace.getActiveFile();
|
const thisFile = this.app.workspace.getActiveFile();
|
||||||
if (!thisFile) return "";
|
if (!thisFile) return "";
|
||||||
// Case Sensitivity
|
// Case Sensitivity
|
||||||
if (this.core.$$shouldCheckCaseInsensitive()) {
|
if (this.services.setting.shouldCheckCaseInsensitively()) {
|
||||||
const f = this.core.storageAccess
|
const f = this.core.storageAccess
|
||||||
.getFiles()
|
.getFiles()
|
||||||
.map((e) => e.path)
|
.map((e) => e.path)
|
||||||
.filter((e) => e.toLowerCase() == thisFile.path.toLowerCase());
|
.filter((e) => e.toLowerCase() == thisFile.path.toLowerCase());
|
||||||
if (f.length > 1) return "Not synchronised: There are multiple files with the same name";
|
if (f.length > 1) return "Not synchronised: There are multiple files with the same name";
|
||||||
}
|
}
|
||||||
if (!(await this.core.$$isTargetFile(thisFile.path))) return "Not synchronised: not a target file";
|
if (!(await this.services.vault.isTargetFile(thisFile.path))) return "Not synchronised: not a target file";
|
||||||
if (this.core.$$isFileSizeExceeded(thisFile.stat.size)) return "Not synchronised: File size exceeded";
|
if (this.services.vault.isFileSizeTooLarge(thisFile.stat.size)) return "Not synchronised: File size exceeded";
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
async setFileStatus() {
|
async setFileStatus() {
|
||||||
@@ -287,14 +288,14 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$allStartOnUnload(): Promise<boolean> {
|
private _allStartOnUnload(): Promise<boolean> {
|
||||||
if (this.statusDiv) {
|
if (this.statusDiv) {
|
||||||
this.statusDiv.remove();
|
this.statusDiv.remove();
|
||||||
}
|
}
|
||||||
document.querySelectorAll(`.livesync-status`)?.forEach((e) => e.remove());
|
document.querySelectorAll(`.livesync-status`)?.forEach((e) => e.remove());
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
addIcon(
|
addIcon(
|
||||||
"view-log",
|
"view-log",
|
||||||
`<g transform="matrix(1.28 0 0 1.28 -131 -411)" fill="currentColor" fill-rule="evenodd">
|
`<g transform="matrix(1.28 0 0 1.28 -131 -411)" fill="currentColor" fill-rule="evenodd">
|
||||||
@@ -303,23 +304,23 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
</g>`
|
</g>`
|
||||||
);
|
);
|
||||||
this.addRibbonIcon("view-log", $msg("moduleLog.showLog"), () => {
|
this.addRibbonIcon("view-log", $msg("moduleLog.showLog"), () => {
|
||||||
void this.core.$$showView(VIEW_TYPE_LOG);
|
void this.services.API.showWindow(VIEW_TYPE_LOG);
|
||||||
}).addClass("livesync-ribbon-showlog");
|
}).addClass("livesync-ribbon-showlog");
|
||||||
|
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "view-log",
|
id: "view-log",
|
||||||
name: "Show log",
|
name: "Show log",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
void this.core.$$showView(VIEW_TYPE_LOG);
|
void this.services.API.showWindow(VIEW_TYPE_LOG);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.registerView(VIEW_TYPE_LOG, (leaf) => new LogPaneView(leaf, this.plugin));
|
this.registerView(VIEW_TYPE_LOG, (leaf) => new LogPaneView(leaf, this.plugin));
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
private _everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||||
logStore
|
logStore
|
||||||
.pipeTo(
|
.pipeTo(
|
||||||
new QueueProcessor((logs) => logs.forEach((e) => this.core.$$addLog(e.message, e.level, e.key)), {
|
new QueueProcessor((logs) => logs.forEach((e) => this._addLog(e.message, e.level, e.key)), {
|
||||||
suspended: false,
|
suspended: false,
|
||||||
batchSize: 20,
|
batchSize: 20,
|
||||||
concurrentLimit: 1,
|
concurrentLimit: 1,
|
||||||
@@ -366,7 +367,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$$addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
|
_addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
|
||||||
if (level == LOG_LEVEL_DEBUG && !showDebugLog) {
|
if (level == LOG_LEVEL_DEBUG && !showDebugLog) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,7 +377,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
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.core.$$getVaultName();
|
const vaultName = this.services.vault.getVaultName();
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timestamp = now.toLocaleString();
|
const timestamp = now.toLocaleString();
|
||||||
const messageContent =
|
const messageContent =
|
||||||
@@ -437,4 +438,10 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
services.appLifecycle.handleOnBeforeUnload(this._allStartOnUnload.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ import { type TFile } from "obsidian";
|
|||||||
import { eventHub } from "../../common/events.ts";
|
import { eventHub } from "../../common/events.ts";
|
||||||
import { EVENT_REQUEST_SHOW_HISTORY } from "../../common/obsidianEvents.ts";
|
import { EVENT_REQUEST_SHOW_HISTORY } from "../../common/obsidianEvents.ts";
|
||||||
import type { FilePathWithPrefix, LoadedEntry, DocumentID } from "../../lib/src/common/types.ts";
|
import type { FilePathWithPrefix, LoadedEntry, DocumentID } from "../../lib/src/common/types.ts";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { DocumentHistoryModal } from "./DocumentHistory/DocumentHistoryModal.ts";
|
import { DocumentHistoryModal } from "./DocumentHistory/DocumentHistoryModal.ts";
|
||||||
import { getPath } from "../../common/utils.ts";
|
import { getPath } from "../../common/utils.ts";
|
||||||
import { fireAndForget } from "octagonal-wheels/promises";
|
import { fireAndForget } from "octagonal-wheels/promises";
|
||||||
|
|
||||||
export class ModuleObsidianDocumentHistory extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianDocumentHistory extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-history",
|
id: "livesync-history",
|
||||||
name: "Show history",
|
name: "Show history",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const file = this.core.$$getActiveFilePath();
|
const file = this.services.vault.getActiveFilePath();
|
||||||
if (file) this.showHistory(file, undefined);
|
if (file) this.showHistory(file, undefined);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -51,4 +51,7 @@ export class ModuleObsidianDocumentHistory extends AbstractObsidianModule implem
|
|||||||
this.showHistory(targetId.path, targetId.id);
|
this.showHistory(targetId.path, targetId.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type IObsidianModule, AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||||
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
|
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
|
||||||
import {
|
import {
|
||||||
@@ -16,8 +16,9 @@ import { isCloudantURI } from "../../lib/src/pouchdb/utils_couchdb.ts";
|
|||||||
import { getLanguage } from "obsidian";
|
import { getLanguage } from "obsidian";
|
||||||
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "../../lib/src/common/rosetta.ts";
|
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "../../lib/src/common/rosetta.ts";
|
||||||
import { decryptString, encryptString } from "@/lib/src/encryption/stringEncryption.ts";
|
import { decryptString, encryptString } from "@/lib/src/encryption/stringEncryption.ts";
|
||||||
export class ModuleObsidianSettings extends AbstractObsidianModule implements IObsidianModule {
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
async $everyOnLayoutReady(): Promise<boolean> {
|
export class ModuleObsidianSettings extends AbstractObsidianModule {
|
||||||
|
async _everyOnLayoutReady(): Promise<boolean> {
|
||||||
let isChanged = false;
|
let isChanged = false;
|
||||||
if (this.settings.displayLanguage == "") {
|
if (this.settings.displayLanguage == "") {
|
||||||
const obsidianLanguage = getLanguage();
|
const obsidianLanguage = getLanguage();
|
||||||
@@ -32,7 +33,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
} else if (this.settings.displayLanguage == "") {
|
} else if (this.settings.displayLanguage == "") {
|
||||||
this.settings.displayLanguage = "def";
|
this.settings.displayLanguage = "def";
|
||||||
setLang(this.settings.displayLanguage);
|
setLang(this.settings.displayLanguage);
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isChanged) {
|
if (isChanged) {
|
||||||
@@ -46,7 +47,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
this.settings.displayLanguage = "def";
|
this.settings.displayLanguage = "def";
|
||||||
setLang(this.settings.displayLanguage);
|
setLang(this.settings.displayLanguage);
|
||||||
}
|
}
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -61,13 +62,13 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
return methodFunc();
|
return methodFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
$$saveDeviceAndVaultName(): void {
|
_saveDeviceAndVaultName(): void {
|
||||||
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.core.$$getVaultName();
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.services.vault.getVaultName();
|
||||||
localStorage.setItem(lsKey, this.core.$$getDeviceAndVaultName() || "");
|
localStorage.setItem(lsKey, this.services.setting.getDeviceAndVaultName() || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
usedPassphrase = "";
|
usedPassphrase = "";
|
||||||
$$clearUsedPassphrase(): void {
|
private _clearUsedPassphrase(): void {
|
||||||
this.usedPassphrase = "";
|
this.usedPassphrase = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +107,8 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$saveSettingData() {
|
async _saveSettingData() {
|
||||||
this.core.$$saveDeviceAndVaultName();
|
this.services.setting.saveDeviceAndVaultName();
|
||||||
const settings = { ...this.settings };
|
const settings = { ...this.settings };
|
||||||
settings.deviceAndVaultName = "";
|
settings.deviceAndVaultName = "";
|
||||||
if (this.usedPassphrase == "" && !(await this.getPassphrase(settings))) {
|
if (this.usedPassphrase == "" && !(await this.getPassphrase(settings))) {
|
||||||
@@ -174,7 +175,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$decryptSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
async _decryptSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
||||||
const passphrase = await this.getPassphrase(settings);
|
const passphrase = await this.getPassphrase(settings);
|
||||||
if (passphrase === false) {
|
if (passphrase === false) {
|
||||||
this._log("No passphrase found for data.json! Verify configuration before syncing.", LOG_LEVEL_URGENT);
|
this._log("No passphrase found for data.json! Verify configuration before syncing.", LOG_LEVEL_URGENT);
|
||||||
@@ -234,7 +235,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
* @param settings
|
* @param settings
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
$$adjustSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
_adjustSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings> {
|
||||||
// Adjust settings as needed
|
// Adjust settings as needed
|
||||||
|
|
||||||
// Delete this feature to avoid problems on mobile.
|
// Delete this feature to avoid problems on mobile.
|
||||||
@@ -264,7 +265,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
return Promise.resolve(settings);
|
return Promise.resolve(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$loadSettings(): Promise<void> {
|
async _loadSettings(): Promise<void> {
|
||||||
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.core.loadData()) as ObsidianLiveSyncSettings;
|
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.core.loadData()) as ObsidianLiveSyncSettings;
|
||||||
|
|
||||||
if (typeof settings.isConfigured == "undefined") {
|
if (typeof settings.isConfigured == "undefined") {
|
||||||
@@ -277,17 +278,17 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.settings = await this.core.$$decryptSettings(settings);
|
this.settings = await this.services.setting.decryptSettings(settings);
|
||||||
|
|
||||||
setLang(this.settings.displayLanguage);
|
setLang(this.settings.displayLanguage);
|
||||||
|
|
||||||
await this.core.$$adjustSettings(this.settings);
|
await this.services.setting.adjustSettings(this.settings);
|
||||||
|
|
||||||
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.core.$$getVaultName();
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.services.vault.getVaultName();
|
||||||
if (this.settings.deviceAndVaultName != "") {
|
if (this.settings.deviceAndVaultName != "") {
|
||||||
if (!localStorage.getItem(lsKey)) {
|
if (!localStorage.getItem(lsKey)) {
|
||||||
this.core.$$setDeviceAndVaultName(this.settings.deviceAndVaultName);
|
this.services.setting.setDeviceAndVaultName(this.settings.deviceAndVaultName);
|
||||||
this.$$saveDeviceAndVaultName();
|
this.services.setting.saveDeviceAndVaultName();
|
||||||
this.settings.deviceAndVaultName = "";
|
this.settings.deviceAndVaultName = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,8 +299,8 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
);
|
);
|
||||||
this.settings.customChunkSize = 0;
|
this.settings.customChunkSize = 0;
|
||||||
}
|
}
|
||||||
this.core.$$setDeviceAndVaultName(localStorage.getItem(lsKey) || "");
|
this.services.setting.setDeviceAndVaultName(localStorage.getItem(lsKey) || "");
|
||||||
if (this.core.$$getDeviceAndVaultName() == "") {
|
if (this.services.setting.getDeviceAndVaultName() == "") {
|
||||||
if (this.settings.usePluginSync) {
|
if (this.settings.usePluginSync) {
|
||||||
this._log("Device name missing. Disabling plug-in sync.", LOG_LEVEL_NOTICE);
|
this._log("Device name missing. Disabling plug-in sync.", LOG_LEVEL_NOTICE);
|
||||||
this.settings.usePluginSync = false;
|
this.settings.usePluginSync = false;
|
||||||
@@ -309,4 +310,14 @@ export class ModuleObsidianSettings extends AbstractObsidianModule implements IO
|
|||||||
// this.core.ignoreFiles = this.settings.ignoreFiles.split(",").map(e => e.trim());
|
// this.core.ignoreFiles = this.settings.ignoreFiles.split(",").map(e => e.trim());
|
||||||
eventHub.emitEvent(EVENT_REQUEST_RELOAD_SETTING_TAB);
|
eventHub.emitEvent(EVENT_REQUEST_RELOAD_SETTING_TAB);
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
super.onBindFunction(core, services);
|
||||||
|
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
||||||
|
services.setting.handleClearUsedPassphrase(this._clearUsedPassphrase.bind(this));
|
||||||
|
services.setting.handleDecryptSettings(this._decryptSettings.bind(this));
|
||||||
|
services.setting.handleAdjustSettings(this._adjustSettings.bind(this));
|
||||||
|
services.setting.handleLoadSettings(this._loadSettings.bind(this));
|
||||||
|
services.setting.handleSaveDeviceAndVaultName(this._saveDeviceAndVaultName.bind(this));
|
||||||
|
services.setting.handleSaveSettingData(this._saveSettingData.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type IObsidianModule, AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||||
import { isObjectDifferent } from "octagonal-wheels/object";
|
import { isObjectDifferent } from "octagonal-wheels/object";
|
||||||
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events";
|
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events";
|
||||||
@@ -8,8 +8,8 @@ import { parseYaml, stringifyYaml } from "../../deps";
|
|||||||
import { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
const SETTING_HEADER = "````yaml:livesync-setting\n";
|
const SETTING_HEADER = "````yaml:livesync-setting\n";
|
||||||
const SETTING_FOOTER = "\n````";
|
const SETTING_FOOTER = "\n````";
|
||||||
export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule {
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: "livesync-export-config",
|
id: "livesync-export-config",
|
||||||
name: "Write setting markdown manually",
|
name: "Write setting markdown manually",
|
||||||
@@ -18,7 +18,7 @@ export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule imp
|
|||||||
return this.settings.settingSyncFile != "";
|
return this.settings.settingSyncFile != "";
|
||||||
}
|
}
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -160,7 +160,7 @@ export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule imp
|
|||||||
result == APPLY_AND_FETCH
|
result == APPLY_AND_FETCH
|
||||||
) {
|
) {
|
||||||
this.core.settings = settingToApply;
|
this.core.settings = settingToApply;
|
||||||
await this.core.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
if (result == APPLY_ONLY) {
|
if (result == APPLY_ONLY) {
|
||||||
this._log("Loaded settings have been applied!", LOG_LEVEL_NOTICE);
|
this._log("Loaded settings have been applied!", LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
@@ -171,7 +171,7 @@ export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule imp
|
|||||||
if (result == APPLY_AND_FETCH) {
|
if (result == APPLY_AND_FETCH) {
|
||||||
await this.core.rebuilder.scheduleFetch();
|
await this.core.rebuilder.scheduleFetch();
|
||||||
}
|
}
|
||||||
this.core.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -242,4 +242,7 @@ We can perform a command in this file.
|
|||||||
this._log(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE);
|
this._log(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSettingTab.ts";
|
import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSettingTab.ts";
|
||||||
import { type IObsidianModule, AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||||
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "../../common/events.ts";
|
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "../../common/events.ts";
|
||||||
|
|
||||||
export class ModuleObsidianSettingDialogue extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
|
||||||
settingTab!: ObsidianLiveSyncSettingTab;
|
settingTab!: ObsidianLiveSyncSettingTab;
|
||||||
|
|
||||||
$everyOnloadStart(): Promise<boolean> {
|
_everyOnloadStart(): Promise<boolean> {
|
||||||
this.settingTab = new ObsidianLiveSyncSettingTab(this.app, this.plugin);
|
this.settingTab = new ObsidianLiveSyncSettingTab(this.app, this.plugin);
|
||||||
this.plugin.addSettingTab(this.settingTab);
|
this.plugin.addSettingTab(this.settingTab);
|
||||||
eventHub.onEvent(EVENT_REQUEST_OPEN_SETTINGS, () => this.openSetting());
|
eventHub.onEvent(EVENT_REQUEST_OPEN_SETTINGS, () => this.openSetting());
|
||||||
@@ -29,4 +29,7 @@ export class ModuleObsidianSettingDialogue extends AbstractObsidianModule implem
|
|||||||
get appId() {
|
get appId() {
|
||||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,16 @@ import {
|
|||||||
EVENT_REQUEST_SHOW_SETUP_QR,
|
EVENT_REQUEST_SHOW_SETUP_QR,
|
||||||
eventHub,
|
eventHub,
|
||||||
} from "../../common/events.ts";
|
} from "../../common/events.ts";
|
||||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||||
import { decodeAnyArray, encodeAnyArray } from "../../common/utils.ts";
|
import { decodeAnyArray, encodeAnyArray } from "../../common/utils.ts";
|
||||||
import qrcode from "qrcode-generator";
|
import qrcode from "qrcode-generator";
|
||||||
import { $msg } from "../../lib/src/common/i18n.ts";
|
import { $msg } from "../../lib/src/common/i18n.ts";
|
||||||
import { performDoctorConsultation, RebuildOptions } from "@/lib/src/common/configForDoc.ts";
|
import { performDoctorConsultation, RebuildOptions } from "@/lib/src/common/configForDoc.ts";
|
||||||
import { encryptString, decryptString } from "@/lib/src/encryption/stringEncryption.ts";
|
import { encryptString, decryptString } from "@/lib/src/encryption/stringEncryption.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleSetupObsidian extends AbstractObsidianModule implements IObsidianModule {
|
export class ModuleSetupObsidian extends AbstractObsidianModule {
|
||||||
$everyOnload(): Promise<boolean> {
|
private _everyOnload(): Promise<boolean> {
|
||||||
this.registerObsidianProtocolHandler("setuplivesync", async (conf: any) => {
|
this.registerObsidianProtocolHandler("setuplivesync", async (conf: any) => {
|
||||||
if (conf.settings) {
|
if (conf.settings) {
|
||||||
await this.setupWizard(conf.settings);
|
await this.setupWizard(conf.settings);
|
||||||
@@ -182,7 +183,7 @@ export class ModuleSetupObsidian extends AbstractObsidianModule implements IObsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newSettings = JSON.parse(JSON.stringify(tryingSettings)) as ObsidianLiveSyncSettings;
|
const newSettings = JSON.parse(JSON.stringify(tryingSettings)) as ObsidianLiveSyncSettings;
|
||||||
const remoteConfig = await this.core.$$fetchRemotePreferredTweakValues(newSettings);
|
const remoteConfig = await this.services.tweakValue.fetchRemotePreferred(newSettings);
|
||||||
if (remoteConfig) {
|
if (remoteConfig) {
|
||||||
this._log("Remote configuration found.", LOG_LEVEL_NOTICE);
|
this._log("Remote configuration found.", LOG_LEVEL_NOTICE);
|
||||||
const resultSettings = {
|
const resultSettings = {
|
||||||
@@ -282,16 +283,16 @@ export class ModuleSetupObsidian extends AbstractObsidianModule implements IObsi
|
|||||||
);
|
);
|
||||||
if (setupType == setupJustImport) {
|
if (setupType == setupJustImport) {
|
||||||
this.core.settings = newSettingW;
|
this.core.settings = newSettingW;
|
||||||
this.core.$$clearUsedPassphrase();
|
this.services.setting.clearUsedPassphrase();
|
||||||
await this.core.saveSettings();
|
await this.core.saveSettings();
|
||||||
} else if (setupType == setupAsNew) {
|
} else if (setupType == setupAsNew) {
|
||||||
this.core.settings = newSettingW;
|
this.core.settings = newSettingW;
|
||||||
this.core.$$clearUsedPassphrase();
|
this.services.setting.clearUsedPassphrase();
|
||||||
await this.core.saveSettings();
|
await this.core.saveSettings();
|
||||||
await this.core.rebuilder.$fetchLocal();
|
await this.core.rebuilder.$fetchLocal();
|
||||||
} else if (setupType == setupAsMerge) {
|
} else if (setupType == setupAsMerge) {
|
||||||
this.core.settings = newSettingW;
|
this.core.settings = newSettingW;
|
||||||
this.core.$$clearUsedPassphrase();
|
this.services.setting.clearUsedPassphrase();
|
||||||
await this.core.saveSettings();
|
await this.core.saveSettings();
|
||||||
await this.core.rebuilder.$fetchLocal(true);
|
await this.core.rebuilder.$fetchLocal(true);
|
||||||
} else if (setupType == setupAgain) {
|
} else if (setupType == setupAgain) {
|
||||||
@@ -308,7 +309,7 @@ export class ModuleSetupObsidian extends AbstractObsidianModule implements IObsi
|
|||||||
}
|
}
|
||||||
this.core.settings = newSettingW;
|
this.core.settings = newSettingW;
|
||||||
await this.core.saveSettings();
|
await this.core.saveSettings();
|
||||||
this.core.$$clearUsedPassphrase();
|
this.services.setting.clearUsedPassphrase();
|
||||||
await this.core.rebuilder.$rebuildEverything();
|
await this.core.rebuilder.$rebuildEverything();
|
||||||
} else {
|
} else {
|
||||||
// Explicitly cancel the operation or the dialog was closed.
|
// Explicitly cancel the operation or the dialog was closed.
|
||||||
@@ -345,4 +346,7 @@ export class ModuleSetupObsidian extends AbstractObsidianModule implements IObsi
|
|||||||
this._log(ex, LOG_LEVEL_VERBOSE);
|
this._log(ex, LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
|
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ export function createStub(name: string, key: string, value: string, panel: stri
|
|||||||
|
|
||||||
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||||
plugin: ObsidianLiveSyncPlugin;
|
plugin: ObsidianLiveSyncPlugin;
|
||||||
|
get services() {
|
||||||
|
return this.plugin.services;
|
||||||
|
}
|
||||||
selectedScreen = "";
|
selectedScreen = "";
|
||||||
|
|
||||||
_editingSettings?: AllSettings;
|
_editingSettings?: AllSettings;
|
||||||
@@ -139,8 +142,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
return await Promise.resolve();
|
return await Promise.resolve();
|
||||||
}
|
}
|
||||||
if (key == "deviceAndVaultName") {
|
if (key == "deviceAndVaultName") {
|
||||||
this.plugin.$$setDeviceAndVaultName(this.editingSettings?.[key] ?? "");
|
this.services.setting.setDeviceAndVaultName(this.editingSettings?.[key] ?? "");
|
||||||
this.plugin.$$saveDeviceAndVaultName();
|
this.services.setting.saveDeviceAndVaultName();
|
||||||
return await Promise.resolve();
|
return await Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +213,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const ret = { ...OnDialogSettingsDefault };
|
const ret = { ...OnDialogSettingsDefault };
|
||||||
ret.configPassphrase = localStorage.getItem("ls-setting-passphrase") || "";
|
ret.configPassphrase = localStorage.getItem("ls-setting-passphrase") || "";
|
||||||
ret.preset = "";
|
ret.preset = "";
|
||||||
ret.deviceAndVaultName = this.plugin.$$getDeviceAndVaultName();
|
ret.deviceAndVaultName = this.services.setting.getDeviceAndVaultName();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
computeAllLocalSettings(): Partial<OnDialogSettings> {
|
computeAllLocalSettings(): Partial<OnDialogSettings> {
|
||||||
@@ -295,7 +298,11 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
async testConnection(settingOverride: Partial<ObsidianLiveSyncSettings> = {}): Promise<void> {
|
async testConnection(settingOverride: Partial<ObsidianLiveSyncSettings> = {}): Promise<void> {
|
||||||
const trialSetting = { ...this.editingSettings, ...settingOverride };
|
const trialSetting = { ...this.editingSettings, ...settingOverride };
|
||||||
const replicator = await this.plugin.$anyNewReplicator(trialSetting);
|
const replicator = await this.services.replicator.getNewReplicator(trialSetting);
|
||||||
|
if (!replicator) {
|
||||||
|
Logger("No replicator available for the current settings.", LOG_LEVEL_NOTICE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
await replicator.tryConnectRemote(trialSetting);
|
await replicator.tryConnectRemote(trialSetting);
|
||||||
const status = await replicator.getRemoteStatus(trialSetting);
|
const status = await replicator.getRemoteStatus(trialSetting);
|
||||||
if (status) {
|
if (status) {
|
||||||
@@ -546,10 +553,14 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const settingForCheck: RemoteDBSettings = {
|
const settingForCheck: RemoteDBSettings = {
|
||||||
...this.editingSettings,
|
...this.editingSettings,
|
||||||
};
|
};
|
||||||
const replicator = this.plugin.$anyNewReplicator(settingForCheck);
|
const replicator = this.services.replicator.getNewReplicator(settingForCheck);
|
||||||
if (!(replicator instanceof LiveSyncCouchDBReplicator)) return true;
|
if (!(replicator instanceof LiveSyncCouchDBReplicator)) return true;
|
||||||
|
|
||||||
const db = await replicator.connectRemoteCouchDBWithSetting(settingForCheck, this.plugin.$$isMobile(), true);
|
const db = await replicator.connectRemoteCouchDBWithSetting(
|
||||||
|
settingForCheck,
|
||||||
|
this.services.API.isMobile(),
|
||||||
|
true
|
||||||
|
);
|
||||||
if (typeof db === "string") {
|
if (typeof db === "string") {
|
||||||
Logger($msg("obsidianLiveSyncSettingTab.logCheckPassphraseFailed", { db }), LOG_LEVEL_NOTICE);
|
Logger($msg("obsidianLiveSyncSettingTab.logCheckPassphraseFailed", { db }), LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
@@ -588,8 +599,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.editingSettings.passphrase = "";
|
this.editingSettings.passphrase = "";
|
||||||
}
|
}
|
||||||
this.applyAllSettings();
|
this.applyAllSettings();
|
||||||
await this.plugin.$allSuspendAllSync();
|
await this.services.setting.suspendAllSync();
|
||||||
await this.plugin.$allSuspendExtraSync();
|
await this.services.setting.suspendExtraSync();
|
||||||
this.reloadAllSettings();
|
this.reloadAllSettings();
|
||||||
this.editingSettings.isConfigured = true;
|
this.editingSettings.isConfigured = true;
|
||||||
Logger($msg("obsidianLiveSyncSettingTab.logRebuildNote"), LOG_LEVEL_NOTICE);
|
Logger($msg("obsidianLiveSyncSettingTab.logRebuildNote"), LOG_LEVEL_NOTICE);
|
||||||
@@ -638,12 +649,12 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
await this.applyAllSettings();
|
await this.applyAllSettings();
|
||||||
if (result == OPTION_FETCH) {
|
if (result == OPTION_FETCH) {
|
||||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
||||||
this.plugin.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// await rebuildDB("localOnly");
|
// await rebuildDB("localOnly");
|
||||||
} else if (result == OPTION_REBUILD_BOTH) {
|
} else if (result == OPTION_REBUILD_BOTH) {
|
||||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
||||||
this.plugin.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
} else if (result == OPTION_ONLY_SETTING) {
|
} else if (result == OPTION_ONLY_SETTING) {
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement,
|
|||||||
}
|
}
|
||||||
const obsidianInfo = {
|
const obsidianInfo = {
|
||||||
navigator: navigator.userAgent,
|
navigator: navigator.userAgent,
|
||||||
fileSystem: this.plugin.$$isStorageInsensitive() ? "insensitive" : "sensitive",
|
fileSystem: this.plugin.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
|
||||||
};
|
};
|
||||||
const msgConfig = `# ---- Obsidian info ----
|
const msgConfig = `# ---- Obsidian info ----
|
||||||
${stringifyYaml(obsidianInfo)}
|
${stringifyYaml(obsidianInfo)}
|
||||||
@@ -182,10 +182,10 @@ ${stringifyYaml({
|
|||||||
|
|
||||||
void addPanel(paneEl, "Scram Switches").then((paneEl) => {
|
void addPanel(paneEl, "Scram Switches").then((paneEl) => {
|
||||||
new Setting(paneEl).autoWireToggle("suspendFileWatching");
|
new Setting(paneEl).autoWireToggle("suspendFileWatching");
|
||||||
this.addOnSaved("suspendFileWatching", () => this.plugin.$$askReload());
|
this.addOnSaved("suspendFileWatching", () => this.services.appLifecycle.askRestart());
|
||||||
|
|
||||||
new Setting(paneEl).autoWireToggle("suspendParseReplicationResult");
|
new Setting(paneEl).autoWireToggle("suspendParseReplicationResult");
|
||||||
this.addOnSaved("suspendParseReplicationResult", () => this.plugin.$$askReload());
|
this.addOnSaved("suspendParseReplicationResult", () => this.services.appLifecycle.askRestart());
|
||||||
});
|
});
|
||||||
|
|
||||||
void addPanel(paneEl, "Recovery and Repair").then((paneEl) => {
|
void addPanel(paneEl, "Recovery and Repair").then((paneEl) => {
|
||||||
@@ -384,15 +384,16 @@ ${stringifyYaml({
|
|||||||
? await this.plugin.storageAccess.statHidden(path)
|
? await this.plugin.storageAccess.statHidden(path)
|
||||||
: false;
|
: false;
|
||||||
const fileOnStorage = stat != null ? stat : false;
|
const fileOnStorage = stat != null ? stat : false;
|
||||||
if (!(await this.plugin.$$isTargetFile(path))) return incProc();
|
if (!(await this.services.vault.isTargetFile(path))) return incProc();
|
||||||
const releaser = await semaphore.acquire(1);
|
const releaser = await semaphore.acquire(1);
|
||||||
if (fileOnStorage && this.plugin.$$isFileSizeExceeded(fileOnStorage.size))
|
if (fileOnStorage && this.services.vault.isFileSizeTooLarge(fileOnStorage.size))
|
||||||
return incProc();
|
return incProc();
|
||||||
try {
|
try {
|
||||||
const isHiddenFile = path.startsWith(".");
|
const isHiddenFile = path.startsWith(".");
|
||||||
const dbPath = isHiddenFile ? addPrefix(path, ICHeader) : path;
|
const dbPath = isHiddenFile ? addPrefix(path, ICHeader) : path;
|
||||||
const fileOnDB = await this.plugin.localDatabase.getDBEntry(dbPath);
|
const fileOnDB = await this.plugin.localDatabase.getDBEntry(dbPath);
|
||||||
if (fileOnDB && this.plugin.$$isFileSizeExceeded(fileOnDB.size)) return incProc();
|
if (fileOnDB && this.services.vault.isFileSizeTooLarge(fileOnDB.size))
|
||||||
|
return incProc();
|
||||||
|
|
||||||
if (!fileOnDB && fileOnStorage) {
|
if (!fileOnDB && fileOnStorage) {
|
||||||
Logger(`Compare: Not found on the local database: ${path}`, LOG_LEVEL_NOTICE);
|
Logger(`Compare: Not found on the local database: ${path}`, LOG_LEVEL_NOTICE);
|
||||||
@@ -436,7 +437,7 @@ ${stringifyYaml({
|
|||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
for await (const docName of this.plugin.localDatabase.findAllDocNames()) {
|
for await (const docName of this.plugin.localDatabase.findAllDocNames()) {
|
||||||
if (!docName.startsWith("f:")) {
|
if (!docName.startsWith("f:")) {
|
||||||
const idEncoded = await this.plugin.$$path2id(docName as FilePathWithPrefix);
|
const idEncoded = await this.services.path.path2id(docName as FilePathWithPrefix);
|
||||||
const doc = await this.plugin.localDatabase.getRaw(docName as DocumentID);
|
const doc = await this.plugin.localDatabase.getRaw(docName as DocumentID);
|
||||||
if (!doc) continue;
|
if (!doc) continue;
|
||||||
if (doc.type != "newnote" && doc.type != "plain") {
|
if (doc.type != "newnote" && doc.type != "plain") {
|
||||||
@@ -477,7 +478,7 @@ ${stringifyYaml({
|
|||||||
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.$$queueConflictCheckIfOpen(docName as FilePathWithPrefix);
|
await this.services.conflict.queueCheckForIfOpen(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);
|
||||||
@@ -512,7 +513,7 @@ ${stringifyYaml({
|
|||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
this.editingSettings.isConfigured = false;
|
this.editingSettings.isConfigured = false;
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
this.plugin.$$askReload();
|
this.services.appLifecycle.askRestart();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function paneMaintenance(
|
|||||||
(e) => {
|
(e) => {
|
||||||
e.addEventListener("click", () => {
|
e.addEventListener("click", () => {
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
await this.plugin.$$markRemoteResolved();
|
await this.services.remote.markResolved();
|
||||||
this.display();
|
this.display();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -59,7 +59,7 @@ export function paneMaintenance(
|
|||||||
(e) => {
|
(e) => {
|
||||||
e.addEventListener("click", () => {
|
e.addEventListener("click", () => {
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
await this.plugin.$$markRemoteUnlocked();
|
await this.services.remote.markUnlocked();
|
||||||
this.display();
|
this.display();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -78,7 +78,7 @@ export function paneMaintenance(
|
|||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.setWarning()
|
.setWarning()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.plugin.$$markRemoteLocked();
|
await this.services.remote.markLocked();
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.addOnUpdate(this.onlyOnCouchDBOrMinIO);
|
.addOnUpdate(this.onlyOnCouchDBOrMinIO);
|
||||||
@@ -93,7 +93,7 @@ export function paneMaintenance(
|
|||||||
.setWarning()
|
.setWarning()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
|
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG, "");
|
||||||
this.plugin.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -255,7 +255,7 @@ export function paneMaintenance(
|
|||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG3_HR, "");
|
||||||
this.plugin.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.addButton((button) =>
|
.addButton((button) =>
|
||||||
@@ -294,7 +294,7 @@ export function paneMaintenance(
|
|||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
await this.plugin.storageAccess.writeFileAuto(FLAGMD_REDFLAG2_HR, "");
|
||||||
this.plugin.$$performRestart();
|
this.services.appLifecycle.performRestart();
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.addButton((button) =>
|
.addButton((button) =>
|
||||||
@@ -405,8 +405,8 @@ export function paneMaintenance(
|
|||||||
.setWarning()
|
.setWarning()
|
||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.plugin.$$resetLocalDatabase();
|
await this.services.database.resetDatabase();
|
||||||
await this.plugin.$$initializeDatabase();
|
await this.services.databaseEvents.initialiseDatabase();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
|||||||
|
|
||||||
this.addOnSaved("additionalSuffixOfDatabaseName", async (key) => {
|
this.addOnSaved("additionalSuffixOfDatabaseName", async (key) => {
|
||||||
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.services.databaseEvents.initialiseDatabase();
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(paneEl).autoWireDropDown("hashAlg", {
|
new Setting(paneEl).autoWireDropDown("hashAlg", {
|
||||||
|
|||||||
@@ -403,7 +403,7 @@ The pane also can be launched by \`P2P Replicator\` command from the Command Pal
|
|||||||
|
|
||||||
void addPanel(paneEl, $msg("obsidianLiveSyncSettingTab.titleCouchDB"), undefined, this.onlyOnCouchDB).then(
|
void addPanel(paneEl, $msg("obsidianLiveSyncSettingTab.titleCouchDB"), undefined, this.onlyOnCouchDB).then(
|
||||||
(paneEl) => {
|
(paneEl) => {
|
||||||
if (this.plugin.$$isMobile()) {
|
if (this.services.API.isMobile()) {
|
||||||
this.createEl(
|
this.createEl(
|
||||||
paneEl,
|
paneEl,
|
||||||
"div",
|
"div",
|
||||||
@@ -630,7 +630,8 @@ The pane also can be launched by \`P2P Replicator\` command from the Command Pal
|
|||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
const trialSetting = { ...this.initialSettings, ...this.editingSettings };
|
const trialSetting = { ...this.initialSettings, ...this.editingSettings };
|
||||||
const newTweaks = await this.plugin.$$checkAndAskUseRemoteConfiguration(trialSetting);
|
const newTweaks =
|
||||||
|
await this.services.tweakValue.checkAndAskUseRemoteConfiguration(trialSetting);
|
||||||
if (newTweaks.result !== false) {
|
if (newTweaks.result !== false) {
|
||||||
if (this.inWizard) {
|
if (this.inWizard) {
|
||||||
this.editingSettings = { ...this.editingSettings, ...newTweaks.result };
|
this.editingSettings = { ...this.editingSettings, ...newTweaks.result };
|
||||||
@@ -648,15 +649,15 @@ The pane also can be launched by \`P2P Replicator\` command from the Command Pal
|
|||||||
}
|
}
|
||||||
)) == "no"
|
)) == "no"
|
||||||
) {
|
) {
|
||||||
await this.plugin.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.plugin.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
await this.plugin.rebuilder.scheduleFetch();
|
await this.plugin.rebuilder.scheduleFetch();
|
||||||
await this.plugin.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
await this.plugin.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,7 +728,7 @@ The pane also can be launched by \`P2P Replicator\` command from the Command Pal
|
|||||||
)) == "yes"
|
)) == "yes"
|
||||||
) {
|
) {
|
||||||
const trialSetting = { ...this.initialSettings, ...this.editingSettings };
|
const trialSetting = { ...this.initialSettings, ...this.editingSettings };
|
||||||
const newTweaks = await this.plugin.$$checkAndAskUseRemoteConfiguration(trialSetting);
|
const newTweaks = await this.services.tweakValue.checkAndAskUseRemoteConfiguration(trialSetting);
|
||||||
if (newTweaks.result !== false) {
|
if (newTweaks.result !== false) {
|
||||||
this.editingSettings = { ...this.editingSettings, ...newTweaks.result };
|
this.editingSettings = { ...this.editingSettings, ...newTweaks.result };
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function paneSetup(
|
|||||||
text.setButtonText($msg("obsidianLiveSyncSettingTab.btnEnable")).onClick(async () => {
|
text.setButtonText($msg("obsidianLiveSyncSettingTab.btnEnable")).onClick(async () => {
|
||||||
this.editingSettings.isConfigured = true;
|
this.editingSettings.isConfigured = true;
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
this.plugin.$$askReload();
|
this.services.appLifecycle.askRestart();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -91,10 +91,10 @@ export function paneSetup(
|
|||||||
this.editingSettings = { ...this.editingSettings, ...DEFAULT_SETTINGS };
|
this.editingSettings = { ...this.editingSettings, ...DEFAULT_SETTINGS };
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
||||||
await this.plugin.$$saveSettingData();
|
await this.services.setting.saveSettingData();
|
||||||
await this.plugin.$$resetLocalDatabase();
|
await this.services.database.resetDatabase();
|
||||||
// await this.plugin.initializeDatabase();
|
// await this.plugin.initializeDatabase();
|
||||||
this.plugin.$$askReload();
|
this.services.appLifecycle.askRestart();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setWarning();
|
.setWarning();
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function paneSyncSettings(
|
|||||||
if (!this.editingSettings.isConfigured) {
|
if (!this.editingSettings.isConfigured) {
|
||||||
this.editingSettings.isConfigured = true;
|
this.editingSettings.isConfigured = true;
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
await this.plugin.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
await this.rebuildDB("localOnly");
|
await this.rebuildDB("localOnly");
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
if (
|
if (
|
||||||
@@ -124,13 +124,13 @@ export function paneSyncSettings(
|
|||||||
await this.confirmRebuild();
|
await this.confirmRebuild();
|
||||||
} else {
|
} else {
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
await this.plugin.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
this.plugin.$$askReload();
|
this.services.appLifecycle.askRestart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await this.saveAllDirtySettings();
|
await this.saveAllDirtySettings();
|
||||||
await this.plugin.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -169,7 +169,7 @@ export function paneSyncSettings(
|
|||||||
}
|
}
|
||||||
await this.saveSettings(["liveSync", "periodicReplication"]);
|
await this.saveSettings(["liveSync", "periodicReplication"]);
|
||||||
|
|
||||||
await this.plugin.$$realizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(paneEl)
|
new Setting(paneEl)
|
||||||
@@ -289,21 +289,21 @@ export function paneSyncSettings(
|
|||||||
button.setButtonText("Merge").onClick(async () => {
|
button.setButtonText("Merge").onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.plugin.$anyConfigureOptionalSyncFeature("MERGE");
|
await this.services.setting.enableOptionalFeature("MERGE");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Fetch").onClick(async () => {
|
button.setButtonText("Fetch").onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.plugin.$anyConfigureOptionalSyncFeature("FETCH");
|
await this.services.setting.enableOptionalFeature("FETCH");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Overwrite").onClick(async () => {
|
button.setButtonText("Overwrite").onClick(async () => {
|
||||||
this.closeSetting();
|
this.closeSetting();
|
||||||
// this.resetEditingSettings();
|
// this.resetEditingSettings();
|
||||||
await this.plugin.$anyConfigureOptionalSyncFeature("OVERWRITE");
|
await this.services.setting.enableOptionalFeature("OVERWRITE");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ import { versionNumberString2Number } from "../../lib/src/string_and_binary/conv
|
|||||||
import { cancelAllPeriodicTask, cancelAllTasks } from "octagonal-wheels/concurrency/task";
|
import { cancelAllPeriodicTask, cancelAllTasks } from "octagonal-wheels/concurrency/task";
|
||||||
import { stopAllRunningProcessors } from "octagonal-wheels/concurrency/processor";
|
import { stopAllRunningProcessors } from "octagonal-wheels/concurrency/processor";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { ICoreModule } from "../ModuleTypes.ts";
|
|
||||||
import { EVENT_PLATFORM_UNLOADED } from "../../lib/src/PlatformAPIs/base/APIBase.ts";
|
import { EVENT_PLATFORM_UNLOADED } from "../../lib/src/PlatformAPIs/base/APIBase.ts";
|
||||||
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
|
||||||
export class ModuleLiveSyncMain extends AbstractModule implements ICoreModule {
|
export class ModuleLiveSyncMain extends AbstractModule {
|
||||||
async $$onLiveSyncReady() {
|
async _onLiveSyncReady() {
|
||||||
if (!(await this.core.$everyOnLayoutReady())) return;
|
if (!(await this.core.services.appLifecycle.onLayoutReady())) return false;
|
||||||
eventHub.emitEvent(EVENT_LAYOUT_READY);
|
eventHub.emitEvent(EVENT_LAYOUT_READY);
|
||||||
if (this.settings.suspendFileWatching || this.settings.suspendParseReplicationResult) {
|
if (this.settings.suspendFileWatching || this.settings.suspendParseReplicationResult) {
|
||||||
const ANSWER_KEEP = $msg("moduleLiveSyncMain.optionKeepLiveSyncDisabled");
|
const ANSWER_KEEP = $msg("moduleLiveSyncMain.optionKeepLiveSyncDisabled");
|
||||||
@@ -36,46 +37,49 @@ export class ModuleLiveSyncMain extends AbstractModule implements ICoreModule {
|
|||||||
this.settings.suspendFileWatching = false;
|
this.settings.suspendFileWatching = false;
|
||||||
this.settings.suspendParseReplicationResult = false;
|
this.settings.suspendParseReplicationResult = false;
|
||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
await this.core.$$scheduleAppReload();
|
this.services.appLifecycle.scheduleRestart();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const isInitialized = await this.core.$$initializeDatabase(false, false);
|
const isInitialized = await this.services.databaseEvents.initialiseDatabase(false, false);
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
//TODO:stop all sync.
|
//TODO:stop all sync.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(await this.core.$everyOnFirstInitialize())) return;
|
if (!(await this.core.services.appLifecycle.onFirstInitialise())) return false;
|
||||||
await this.core.$$realizeSettingSyncMode();
|
// await this.core.$$realizeSettingSyncMode();
|
||||||
|
await this.services.setting.onRealiseSetting();
|
||||||
fireAndForget(async () => {
|
fireAndForget(async () => {
|
||||||
this._log($msg("moduleLiveSyncMain.logAdditionalSafetyScan"), LOG_LEVEL_VERBOSE);
|
this._log($msg("moduleLiveSyncMain.logAdditionalSafetyScan"), LOG_LEVEL_VERBOSE);
|
||||||
if (!(await this.core.$allScanStat())) {
|
if (!(await this.services.appLifecycle.onScanningStartupIssues())) {
|
||||||
this._log($msg("moduleLiveSyncMain.logSafetyScanFailed"), LOG_LEVEL_NOTICE);
|
this._log($msg("moduleLiveSyncMain.logSafetyScanFailed"), LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
this._log($msg("moduleLiveSyncMain.logSafetyScanCompleted"), LOG_LEVEL_VERBOSE);
|
this._log($msg("moduleLiveSyncMain.logSafetyScanCompleted"), LOG_LEVEL_VERBOSE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$wireUpEvents(): void {
|
_wireUpEvents() {
|
||||||
eventHub.onEvent(EVENT_SETTING_SAVED, (settings: ObsidianLiveSyncSettings) => {
|
eventHub.onEvent(EVENT_SETTING_SAVED, (settings: ObsidianLiveSyncSettings) => {
|
||||||
this.localDatabase.settings = settings;
|
this.localDatabase.settings = settings;
|
||||||
setLang(settings.displayLanguage);
|
setLang(settings.displayLanguage);
|
||||||
eventHub.emitEvent(EVENT_REQUEST_RELOAD_SETTING_TAB);
|
eventHub.emitEvent(EVENT_REQUEST_RELOAD_SETTING_TAB);
|
||||||
});
|
});
|
||||||
eventHub.onEvent(EVENT_SETTING_SAVED, (settings: ObsidianLiveSyncSettings) => {
|
eventHub.onEvent(EVENT_SETTING_SAVED, (settings: ObsidianLiveSyncSettings) => {
|
||||||
fireAndForget(() => this.core.$$realizeSettingSyncMode());
|
fireAndForget(() => this.core.services.setting.onRealiseSetting());
|
||||||
});
|
});
|
||||||
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$onLiveSyncLoad(): Promise<void> {
|
async _onLiveSyncLoad(): Promise<boolean> {
|
||||||
this.$$wireUpEvents();
|
await this.services.appLifecycle.onWireUpEvents();
|
||||||
// debugger;
|
// debugger;
|
||||||
eventHub.emitEvent(EVENT_PLUGIN_LOADED, this.core);
|
eventHub.emitEvent(EVENT_PLUGIN_LOADED, this.core);
|
||||||
this._log($msg("moduleLiveSyncMain.logLoadingPlugin"));
|
this._log($msg("moduleLiveSyncMain.logLoadingPlugin"));
|
||||||
if (!(await this.core.$everyOnloadStart())) {
|
if (!(await this.services.appLifecycle.onInitialise())) {
|
||||||
this._log($msg("moduleLiveSyncMain.logPluginInitCancelled"), LOG_LEVEL_NOTICE);
|
this._log($msg("moduleLiveSyncMain.logPluginInitCancelled"), LOG_LEVEL_NOTICE);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// this.addUIs();
|
// this.addUIs();
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
@@ -84,12 +88,12 @@ export class ModuleLiveSyncMain extends AbstractModule implements ICoreModule {
|
|||||||
const packageVersion: string = PACKAGE_VERSION || "0.0.0";
|
const packageVersion: string = PACKAGE_VERSION || "0.0.0";
|
||||||
|
|
||||||
this._log($msg("moduleLiveSyncMain.logPluginVersion", { manifestVersion, packageVersion }));
|
this._log($msg("moduleLiveSyncMain.logPluginVersion", { manifestVersion, packageVersion }));
|
||||||
await this.core.$$loadSettings();
|
await this.services.setting.loadSettings();
|
||||||
if (!(await this.core.$everyOnloadAfterLoadSettings())) {
|
if (!(await this.services.appLifecycle.onSettingLoaded())) {
|
||||||
this._log($msg("moduleLiveSyncMain.logPluginInitCancelled"), LOG_LEVEL_NOTICE);
|
this._log($msg("moduleLiveSyncMain.logPluginInitCancelled"), LOG_LEVEL_NOTICE);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
const lsKey = "obsidian-live-sync-ver" + this.core.$$getVaultName();
|
const lsKey = "obsidian-live-sync-ver" + this.services.vault.getVaultName();
|
||||||
const last_version = localStorage.getItem(lsKey);
|
const last_version = localStorage.getItem(lsKey);
|
||||||
|
|
||||||
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
||||||
@@ -113,22 +117,23 @@ export class ModuleLiveSyncMain extends AbstractModule implements ICoreModule {
|
|||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
}
|
}
|
||||||
localStorage.setItem(lsKey, `${VER}`);
|
localStorage.setItem(lsKey, `${VER}`);
|
||||||
await this.core.$$openDatabase();
|
await this.services.database.openDatabase();
|
||||||
this.core.$$realizeSettingSyncMode = this.core.$$realizeSettingSyncMode.bind(this);
|
// this.core.$$realizeSettingSyncMode = this.core.$$realizeSettingSyncMode.bind(this);
|
||||||
// this.$$parseReplicationResult = this.$$parseReplicationResult.bind(this);
|
// this.$$parseReplicationResult = this.$$parseReplicationResult.bind(this);
|
||||||
// this.$$replicate = this.$$replicate.bind(this);
|
// this.$$replicate = this.$$replicate.bind(this);
|
||||||
this.core.$$onLiveSyncReady = this.core.$$onLiveSyncReady.bind(this);
|
// this.core.$$onLiveSyncReady = this.core.$$onLiveSyncReady.bind(this);
|
||||||
await this.core.$everyOnload();
|
await this.core.services.appLifecycle.onLoaded();
|
||||||
await Promise.all(this.core.addOns.map((e) => e.onload()));
|
await Promise.all(this.core.addOns.map((e) => e.onload()));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$onLiveSyncUnload(): Promise<void> {
|
async _onLiveSyncUnload(): Promise<void> {
|
||||||
eventHub.emitEvent(EVENT_PLUGIN_UNLOADED);
|
eventHub.emitEvent(EVENT_PLUGIN_UNLOADED);
|
||||||
await this.core.$allStartOnUnload();
|
await this.services.appLifecycle.onBeforeUnload();
|
||||||
cancelAllPeriodicTask();
|
cancelAllPeriodicTask();
|
||||||
cancelAllTasks();
|
cancelAllTasks();
|
||||||
stopAllRunningProcessors();
|
stopAllRunningProcessors();
|
||||||
await this.core.$allOnUnload();
|
await this.services.appLifecycle.onUnload();
|
||||||
this._unloaded = true;
|
this._unloaded = true;
|
||||||
for (const addOn of this.core.addOns) {
|
for (const addOn of this.core.addOns) {
|
||||||
addOn.onunload();
|
addOn.onunload();
|
||||||
@@ -143,49 +148,68 @@ export class ModuleLiveSyncMain extends AbstractModule implements ICoreModule {
|
|||||||
eventHub.emitEvent(EVENT_PLATFORM_UNLOADED);
|
eventHub.emitEvent(EVENT_PLATFORM_UNLOADED);
|
||||||
eventHub.offAll();
|
eventHub.offAll();
|
||||||
this._log($msg("moduleLiveSyncMain.logUnloadingPlugin"));
|
this._log($msg("moduleLiveSyncMain.logUnloadingPlugin"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
async $$realizeSettingSyncMode(): Promise<void> {
|
private async _realizeSettingSyncMode(): Promise<void> {
|
||||||
await this.core.$everyBeforeSuspendProcess();
|
await this.services.appLifecycle.onSuspending();
|
||||||
await this.core.$everyBeforeRealizeSetting();
|
await this.services.setting.onBeforeRealiseSetting();
|
||||||
this.localDatabase.refreshSettings();
|
this.localDatabase.refreshSettings();
|
||||||
await this.core.$everyCommitPendingFileEvent();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
await this.core.$everyRealizeSettingSyncMode();
|
await this.services.setting.onRealiseSetting();
|
||||||
// disable all sync temporary.
|
// disable all sync temporary.
|
||||||
if (this.core.$$isSuspended()) return;
|
if (this.services.appLifecycle.isSuspended()) return;
|
||||||
await this.core.$everyOnResumeProcess();
|
await this.services.appLifecycle.onResuming();
|
||||||
await this.core.$everyAfterResumeProcess();
|
await this.services.appLifecycle.onResumed();
|
||||||
await this.core.$everyAfterRealizeSetting();
|
await this.services.setting.onSettingRealised();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$isReloadingScheduled(): boolean {
|
_isReloadingScheduled(): boolean {
|
||||||
return this.core._totalProcessingCount !== undefined;
|
return this.core._totalProcessingCount !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
isReady = false;
|
isReady = false;
|
||||||
|
|
||||||
$$isReady(): boolean {
|
_isReady(): boolean {
|
||||||
return this.isReady;
|
return this.isReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$markIsReady(): void {
|
_markIsReady(): void {
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$resetIsReady(): void {
|
_resetIsReady(): void {
|
||||||
this.isReady = false;
|
this.isReady = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_suspended = false;
|
_suspended = false;
|
||||||
$$isSuspended(): boolean {
|
_isSuspended(): boolean {
|
||||||
return this._suspended || !this.settings?.isConfigured;
|
return this._suspended || !this.settings?.isConfigured;
|
||||||
}
|
}
|
||||||
$$setSuspended(value: boolean) {
|
|
||||||
|
_setSuspended(value: boolean) {
|
||||||
this._suspended = value;
|
this._suspended = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
_unloaded = false;
|
_unloaded = false;
|
||||||
$$isUnloaded(): boolean {
|
_isUnloaded(): boolean {
|
||||||
return this._unloaded;
|
return this._unloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
|
super.onBindFunction(core, services);
|
||||||
|
services.appLifecycle.handleIsSuspended(this._isSuspended.bind(this));
|
||||||
|
services.appLifecycle.handleSetSuspended(this._setSuspended.bind(this));
|
||||||
|
services.appLifecycle.handleIsReady(this._isReady.bind(this));
|
||||||
|
services.appLifecycle.handleMarkIsReady(this._markIsReady.bind(this));
|
||||||
|
services.appLifecycle.handleResetIsReady(this._resetIsReady.bind(this));
|
||||||
|
services.appLifecycle.handleHasUnloaded(this._isUnloaded.bind(this));
|
||||||
|
services.appLifecycle.handleIsReloadingScheduled(this._isReloadingScheduled.bind(this));
|
||||||
|
services.appLifecycle.handleOnReady(this._onLiveSyncReady.bind(this));
|
||||||
|
services.appLifecycle.handleOnWireUpEvents(this._wireUpEvents.bind(this));
|
||||||
|
services.appLifecycle.handleOnLoad(this._onLiveSyncLoad.bind(this));
|
||||||
|
services.appLifecycle.handleOnAppUnload(this._onLiveSyncUnload.bind(this));
|
||||||
|
services.setting.handleRealiseSetting(this._realizeSettingSyncMode.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/modules/services/ObsidianServices.ts
Normal file
76
src/modules/services/ObsidianServices.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import {
|
||||||
|
InjectableAPIService,
|
||||||
|
InjectableAppLifecycleService,
|
||||||
|
InjectableConflictService,
|
||||||
|
InjectableDatabaseService,
|
||||||
|
InjectableFileProcessingService,
|
||||||
|
InjectablePathService,
|
||||||
|
InjectableRemoteService,
|
||||||
|
InjectableReplicationService,
|
||||||
|
InjectableReplicatorService,
|
||||||
|
InjectableSettingService,
|
||||||
|
InjectableTestService,
|
||||||
|
InjectableTweakValueService,
|
||||||
|
InjectableVaultService,
|
||||||
|
} from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
import { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
|
// All Services will be migrated to be based on Plain Services, not Injectable Services.
|
||||||
|
// This is a migration step.
|
||||||
|
|
||||||
|
export class ObsidianAPIService extends InjectableAPIService {}
|
||||||
|
export class ObsidianPathService extends InjectablePathService {}
|
||||||
|
export class ObsidianDatabaseService extends InjectableDatabaseService {}
|
||||||
|
|
||||||
|
// InjectableReplicatorService
|
||||||
|
export class ObsidianReplicatorService extends InjectableReplicatorService {}
|
||||||
|
// InjectableFileProcessingService
|
||||||
|
export class ObsidianFileProcessingService extends InjectableFileProcessingService {}
|
||||||
|
// InjectableReplicationService
|
||||||
|
export class ObsidianReplicationService extends InjectableReplicationService {}
|
||||||
|
// InjectableRemoteService
|
||||||
|
export class ObsidianRemoteService extends InjectableRemoteService {}
|
||||||
|
// InjectableConflictService
|
||||||
|
export class ObsidianConflictService extends InjectableConflictService {}
|
||||||
|
// InjectableAppLifecycleService
|
||||||
|
export class ObsidianAppLifecycleService extends InjectableAppLifecycleService {}
|
||||||
|
// InjectableSettingService
|
||||||
|
export class ObsidianSettingService extends InjectableSettingService {}
|
||||||
|
// InjectableTweakValueService
|
||||||
|
export class ObsidianTweakValueService extends InjectableTweakValueService {}
|
||||||
|
// InjectableVaultService
|
||||||
|
export class ObsidianVaultService extends InjectableVaultService {}
|
||||||
|
// InjectableTestService
|
||||||
|
export class ObsidianTestService extends InjectableTestService {}
|
||||||
|
|
||||||
|
// InjectableServiceHub
|
||||||
|
|
||||||
|
export class ObsidianServiceHub extends InjectableServiceHub {
|
||||||
|
protected _api: ObsidianAPIService = new ObsidianAPIService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _path: ObsidianPathService = new ObsidianPathService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _database: ObsidianDatabaseService = new ObsidianDatabaseService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _replicator: ObsidianReplicatorService = new ObsidianReplicatorService(
|
||||||
|
this._serviceBackend,
|
||||||
|
this._throughHole
|
||||||
|
);
|
||||||
|
protected _fileProcessing: ObsidianFileProcessingService = new ObsidianFileProcessingService(
|
||||||
|
this._serviceBackend,
|
||||||
|
this._throughHole
|
||||||
|
);
|
||||||
|
protected _replication: ObsidianReplicationService = new ObsidianReplicationService(
|
||||||
|
this._serviceBackend,
|
||||||
|
this._throughHole
|
||||||
|
);
|
||||||
|
protected _remote: ObsidianRemoteService = new ObsidianRemoteService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _conflict: ObsidianConflictService = new ObsidianConflictService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _appLifecycle: ObsidianAppLifecycleService = new ObsidianAppLifecycleService(
|
||||||
|
this._serviceBackend,
|
||||||
|
this._throughHole
|
||||||
|
);
|
||||||
|
protected _setting: ObsidianSettingService = new ObsidianSettingService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _tweakValue: ObsidianTweakValueService = new ObsidianTweakValueService(
|
||||||
|
this._serviceBackend,
|
||||||
|
this._throughHole
|
||||||
|
);
|
||||||
|
protected _vault: ObsidianVaultService = new ObsidianVaultService(this._serviceBackend, this._throughHole);
|
||||||
|
protected _test: ObsidianTestService = new ObsidianTestService(this._serviceBackend, this._throughHole);
|
||||||
|
}
|
||||||
@@ -31,12 +31,12 @@ const terserOption = {
|
|||||||
evaluate: true,
|
evaluate: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
// directives: true,
|
// directives: true,
|
||||||
inline: 3,
|
inline: false,
|
||||||
join_vars: true,
|
join_vars: true,
|
||||||
loops: true,
|
loops: true,
|
||||||
passes: 4,
|
passes: 4,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
reduce_funcs: true,
|
reduce_funcs: false,
|
||||||
arrows: true,
|
arrows: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user