From e80cdc2daed1218cdf1d0bde5134ead87d61763a Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Mon, 18 May 2026 08:47:03 +0100 Subject: [PATCH] remove unused files --- src/modules/core/ModuleReplicatorP2P.ts | 25 - src/modules/coreFeatures/ModuleRedFlag.ts | 331 -------------- .../essential/ModuleInitializerFile.ts | 429 ------------------ .../ModuleCheckRemoteSize_obsolete.ts | 135 ------ 4 files changed, 920 deletions(-) delete mode 100644 src/modules/core/ModuleReplicatorP2P.ts delete mode 100644 src/modules/coreFeatures/ModuleRedFlag.ts delete mode 100644 src/modules/essential/ModuleInitializerFile.ts delete mode 100644 src/modules/essentialObsidian/ModuleCheckRemoteSize_obsolete.ts diff --git a/src/modules/core/ModuleReplicatorP2P.ts b/src/modules/core/ModuleReplicatorP2P.ts deleted file mode 100644 index 7f59794..0000000 --- a/src/modules/core/ModuleReplicatorP2P.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { REMOTE_P2P, type RemoteDBSettings } from "../../lib/src/common/types"; -import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator"; -import { AbstractModule } from "../AbstractModule"; -import { LiveSyncTrysteroReplicator } from "../../lib/src/replication/trystero/LiveSyncTrysteroReplicator"; -import type { LiveSyncCore } from "../../main"; - -// Note: -// This module registers only the `getNewReplicator` handler for the P2P replicator. -// `useP2PReplicator` (see P2PReplicatorCore.ts) already registers the same `getNewReplicator` -// handler internally, so this module is redundant in environments that call `useP2PReplicator`. -// Register this module only in environments that do NOT use `useP2PReplicator` (e.g. CLI). -// In other words: just resolving `getNewReplicator` via this module is all that is needed -// to satisfy what `useP2PReplicator` requires from the replicator service. -export class ModuleReplicatorP2P extends AbstractModule { - _anyNewReplicator(settingOverride: Partial = {}): Promise { - const settings = { ...this.settings, ...settingOverride }; - if (settings.remoteType == REMOTE_P2P) { - return Promise.resolve(new LiveSyncTrysteroReplicator(this.core)); - } - return Promise.resolve(false); - } - override onBindFunction(core: LiveSyncCore, services: typeof core.services): void { - services.replicator.getNewReplicator.addHandler(this._anyNewReplicator.bind(this)); - } -} diff --git a/src/modules/coreFeatures/ModuleRedFlag.ts b/src/modules/coreFeatures/ModuleRedFlag.ts deleted file mode 100644 index d57cb0f..0000000 --- a/src/modules/coreFeatures/ModuleRedFlag.ts +++ /dev/null @@ -1,331 +0,0 @@ -import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger"; -import { normalizePath } from "../../deps.ts"; -import { - FlagFilesHumanReadable, - FlagFilesOriginal, - REMOTE_MINIO, - TweakValuesShouldMatchedTemplate, - type ObsidianLiveSyncSettings, -} from "../../lib/src/common/types.ts"; -import { AbstractModule } from "../AbstractModule.ts"; -import type { LiveSyncCore } from "../../main.ts"; -import FetchEverything from "../features/SetupWizard/dialogs/FetchEverything.svelte"; -import RebuildEverything from "../features/SetupWizard/dialogs/RebuildEverything.svelte"; -import { extractObject } from "octagonal-wheels/object"; -import { SvelteDialogManagerBase } from "@lib/UI/svelteDialog.ts"; -import type { ServiceContext } from "@lib/services/base/ServiceBase.ts"; - -export class ModuleRedFlag extends AbstractModule { - async isFlagFileExist(path: string) { - const redflag = await this.core.storageAccess.isExists(normalizePath(path)); - if (redflag) { - return true; - } - return false; - } - - async deleteFlagFile(path: string) { - try { - const isFlagged = await this.core.storageAccess.isExists(normalizePath(path)); - if (isFlagged) { - await this.core.storageAccess.delete(path, true); - } - } catch (ex) { - this._log(`Could not delete ${path}`); - this._log(ex, LOG_LEVEL_VERBOSE); - } - } - - isSuspendFlagActive = async () => await this.isFlagFileExist(FlagFilesOriginal.SUSPEND_ALL); - isRebuildFlagActive = async () => - (await this.isFlagFileExist(FlagFilesOriginal.REBUILD_ALL)) || - (await this.isFlagFileExist(FlagFilesHumanReadable.REBUILD_ALL)); - isFetchAllFlagActive = async () => - (await this.isFlagFileExist(FlagFilesOriginal.FETCH_ALL)) || - (await this.isFlagFileExist(FlagFilesHumanReadable.FETCH_ALL)); - - async cleanupRebuildFlag() { - await this.deleteFlagFile(FlagFilesOriginal.REBUILD_ALL); - await this.deleteFlagFile(FlagFilesHumanReadable.REBUILD_ALL); - } - - async cleanupFetchAllFlag() { - await this.deleteFlagFile(FlagFilesOriginal.FETCH_ALL); - await this.deleteFlagFile(FlagFilesHumanReadable.FETCH_ALL); - } - // dialogManager = new SvelteDialogManagerBase(this.core); - get dialogManager(): SvelteDialogManagerBase { - return this.core.services.UI.dialogManager; - } - - /** - * Adjust setting to remote if needed. - * @param extra result of dialogues that may contain preventFetchingConfig flag (e.g, from FetchEverything or RebuildEverything) - * @param config current configuration to retrieve remote preferred config - */ - async adjustSettingToRemoteIfNeeded(extra: { preventFetchingConfig: boolean }, config: ObsidianLiveSyncSettings) { - if (extra && extra.preventFetchingConfig) { - return; - } - - // Remote configuration fetched and applied. - if (await this.adjustSettingToRemote(config)) { - config = this.core.settings; - } else { - this._log("Remote configuration not applied.", LOG_LEVEL_NOTICE); - } - console.debug(config); - } - - /** - * Adjust setting to remote configuration. - * @param config current configuration to retrieve remote preferred config - * @returns updated configuration if applied, otherwise null. - */ - async adjustSettingToRemote(config: ObsidianLiveSyncSettings) { - // Fetch remote configuration unless prevented. - const SKIP_FETCH = "Skip and proceed"; - const RETRY_FETCH = "Retry (recommended)"; - let canProceed = false; - do { - const remoteTweaks = await this.services.tweakValue.fetchRemotePreferred(config); - if (!remoteTweaks) { - const choice = await this.core.confirm.askSelectStringDialogue( - "Could not fetch configuration from remote. If you are new to the Self-hosted LiveSync, this might be expected. If not, you should check your network or server settings.", - [SKIP_FETCH, RETRY_FETCH] as const, - { - defaultAction: RETRY_FETCH, - timeout: 0, - title: "Fetch Remote Configuration Failed", - } - ); - if (choice === SKIP_FETCH) { - canProceed = true; - } - } else { - const necessary = extractObject(TweakValuesShouldMatchedTemplate, remoteTweaks); - // Check if any necessary tweak value is different from current config. - const differentItems = Object.entries(necessary).filter(([key, value]) => { - return (config as any)[key] !== value; - }); - if (differentItems.length === 0) { - this._log( - "Remote configuration matches local configuration. No changes applied.", - LOG_LEVEL_NOTICE - ); - } else { - await this.core.confirm.askSelectStringDialogue( - "Your settings differed slightly from the server's. The plug-in has supplemented the incompatible parts with the server settings!", - ["OK"] as const, - { - defaultAction: "OK", - timeout: 0, - } - ); - } - - config = { - ...config, - ...Object.fromEntries(differentItems), - } satisfies ObsidianLiveSyncSettings; - this.core.settings = config; - await this.core.services.setting.saveSettingData(); - this._log("Remote configuration applied.", LOG_LEVEL_NOTICE); - canProceed = true; - return this.core.settings; - } - } while (!canProceed); - } - - /** - * Process vault initialisation with suspending file watching and sync. - * @param proc process to be executed during initialisation, should return true if can be continued, false if app is unable to continue the process. - * @param keepSuspending whether to keep suspending file watching after the process. - * @returns result of the process, or false if error occurs. - */ - async processVaultInitialisation(proc: () => Promise, keepSuspending = false) { - try { - // Disable batch saving and file watching during initialisation. - this.settings.batchSave = false; - await this.services.setting.suspendAllSync(); - await this.services.setting.suspendExtraSync(); - this.settings.suspendFileWatching = true; - await this.saveSettings(); - try { - const result = await proc(); - return result; - } catch (ex) { - this._log("Error during vault initialisation process.", LOG_LEVEL_NOTICE); - this._log(ex, LOG_LEVEL_VERBOSE); - return false; - } - } catch (ex) { - this._log("Error during vault initialisation.", LOG_LEVEL_NOTICE); - this._log(ex, LOG_LEVEL_VERBOSE); - return false; - } finally { - if (!keepSuspending) { - // Re-enable file watching after initialisation. - this.settings.suspendFileWatching = false; - await this.saveSettings(); - } - } - } - - /** - * Handle the rebuild everything scheduled operation. - * @returns true if can be continued, false if app restart is needed. - */ - async onRebuildEverythingScheduled() { - const method = await this.dialogManager.openWithExplicitCancel(RebuildEverything); - if (method === "cancelled") { - // Clean up the flag file and restart the app. - this._log("Rebuild everything cancelled by user.", LOG_LEVEL_NOTICE); - await this.cleanupRebuildFlag(); - this.services.appLifecycle.performRestart(); - return false; - } - const { extra } = method; - await this.adjustSettingToRemoteIfNeeded(extra, this.settings); - return await this.processVaultInitialisation(async () => { - await this.core.rebuilder.$rebuildEverything(); - await this.cleanupRebuildFlag(); - this._log("Rebuild everything operation completed.", LOG_LEVEL_NOTICE); - return true; - }); - } - /** - * Handle the fetch all scheduled operation. - * @returns true if can be continued, false if app restart is needed. - */ - async onFetchAllScheduled() { - const method = await this.dialogManager.openWithExplicitCancel(FetchEverything); - if (method === "cancelled") { - this._log("Fetch everything cancelled by user.", LOG_LEVEL_NOTICE); - // Clean up the flag file and restart the app. - await this.cleanupFetchAllFlag(); - this.services.appLifecycle.performRestart(); - return false; - } - const { vault, extra } = method; - // If remote is MinIO, makeLocalChunkBeforeSync is not available. (because no-deduplication on sending). - const makeLocalChunkBeforeSyncAvailable = this.settings.remoteType !== REMOTE_MINIO; - const mapVaultStateToAction = { - identical: { - // If both are identical, no need to make local files/chunks before sync, - // Just for the efficiency, chunks should be made before sync. - makeLocalChunkBeforeSync: makeLocalChunkBeforeSyncAvailable, - makeLocalFilesBeforeSync: false, - }, - independent: { - // If both are independent, nothing needs to be made before sync. - // Respect the remote state. - makeLocalChunkBeforeSync: false, - makeLocalFilesBeforeSync: false, - }, - unbalanced: { - // If both are unbalanced, local files should be made before sync to avoid data loss. - // Then, chunks should be made before sync for the efficiency, but also the metadata made and should be detected as conflicting. - makeLocalChunkBeforeSync: false, - makeLocalFilesBeforeSync: true, - }, - cancelled: { - // Cancelled case, not actually used. - makeLocalChunkBeforeSync: false, - makeLocalFilesBeforeSync: false, - }, - } as const; - - return await this.processVaultInitialisation(async () => { - await this.adjustSettingToRemoteIfNeeded(extra, this.settings); - // Okay, proceed to fetch everything. - const { makeLocalChunkBeforeSync, makeLocalFilesBeforeSync } = mapVaultStateToAction[vault]; - this._log( - `Fetching everything with settings: makeLocalChunkBeforeSync=${makeLocalChunkBeforeSync}, makeLocalFilesBeforeSync=${makeLocalFilesBeforeSync}`, - LOG_LEVEL_INFO - ); - await this.core.rebuilder.$fetchLocal(makeLocalChunkBeforeSync, !makeLocalFilesBeforeSync); - await this.cleanupFetchAllFlag(); - this._log("Fetch everything operation completed. Vault files will be gradually synced.", LOG_LEVEL_NOTICE); - return true; - }); - } - - async onSuspendAllScheduled() { - this._log("SCRAM is detected. All operations are suspended.", LOG_LEVEL_NOTICE); - return await this.processVaultInitialisation(async () => { - this._log( - "All operations are suspended as per SCRAM.\nLogs will be written to the file. This might be a performance impact.", - LOG_LEVEL_NOTICE - ); - this.settings.writeLogToTheFile = true; - await this.core.services.setting.saveSettingData(); - return Promise.resolve(false); - }, true); - } - - async verifyAndUnlockSuspension() { - if (!this.settings.suspendFileWatching) { - return true; - } - if ( - (await this.core.confirm.askYesNoDialog( - "Do you want to resume file and database processing, and restart obsidian now?", - { defaultOption: "Yes", timeout: 15 } - )) != "yes" - ) { - // TODO: Confirm actually proceed to next process. - return true; - } - this.settings.suspendFileWatching = false; - await this.saveSettings(); - this.services.appLifecycle.performRestart(); - return false; - } - - private async processFlagFilesOnStartup(): Promise { - const isFlagSuspensionActive = await this.isSuspendFlagActive(); - const isFlagRebuildActive = await this.isRebuildFlagActive(); - const isFlagFetchAllActive = await this.isFetchAllFlagActive(); - // TODO: Address the case when both flags are active (very unlikely though). - // if(isFlagFetchAllActive && isFlagRebuildActive) { - // const message = "Rebuild everything and Fetch everything flags are both detected."; - // await this.core.confirm.askSelectStringDialogue( - // "Both Rebuild Everything and Fetch Everything flags are detected. Please remove one of them and restart the app.", - // ["OK"] as const,) - if (isFlagFetchAllActive) { - const res = await this.onFetchAllScheduled(); - if (res) { - return await this.verifyAndUnlockSuspension(); - } - return false; - } - if (isFlagRebuildActive) { - const res = await this.onRebuildEverythingScheduled(); - if (res) { - return await this.verifyAndUnlockSuspension(); - } - return false; - } - if (isFlagSuspensionActive) { - const res = await this.onSuspendAllScheduled(); - return res; - } - return true; - } - - async _everyOnLayoutReady(): Promise { - try { - const flagProcessResult = await this.processFlagFilesOnStartup(); - return flagProcessResult; - } catch (ex) { - this._log("Something went wrong on FlagFile Handling", LOG_LEVEL_NOTICE); - this._log(ex, LOG_LEVEL_VERBOSE); - } - return true; - } - override onBindFunction(core: LiveSyncCore, services: typeof core.services): void { - super.onBindFunction(core, services); - services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this)); - } -} diff --git a/src/modules/essential/ModuleInitializerFile.ts b/src/modules/essential/ModuleInitializerFile.ts deleted file mode 100644 index b26ac88..0000000 --- a/src/modules/essential/ModuleInitializerFile.ts +++ /dev/null @@ -1,429 +0,0 @@ -import { unique } from "octagonal-wheels/collection"; -import { throttle } from "octagonal-wheels/function"; -import { EVENT_ON_UNRESOLVED_ERROR, eventHub } from "../../common/events.ts"; -import { BASE_IS_NEW, EVEN, isValidPath, TARGET_IS_NEW } from "../../common/utils.ts"; -import { - type FilePathWithPrefixLC, - type FilePathWithPrefix, - type MetaEntry, - isMetaEntry, - type EntryDoc, - LOG_LEVEL_VERBOSE, - LOG_LEVEL_NOTICE, - LOG_LEVEL_INFO, - LOG_LEVEL_DEBUG, - type UXFileInfoStub, - type LOG_LEVEL, -} from "../../lib/src/common/types.ts"; -import { isAnyNote } from "../../lib/src/common/utils.ts"; -import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts"; -import { AbstractModule } from "../AbstractModule.ts"; -import { withConcurrency } from "octagonal-wheels/iterable/map"; -import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts"; -import type { LiveSyncCore } from "../../main.ts"; -export class ModuleInitializerFile extends AbstractModule { - private _detectedErrors = new Set(); - - private logDetectedError(message: string, logLevel: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) { - this._detectedErrors.add(message); - eventHub.emitEvent(EVENT_ON_UNRESOLVED_ERROR); - this._log(message, logLevel, key); - } - private resetDetectedError(message: string) { - eventHub.emitEvent(EVENT_ON_UNRESOLVED_ERROR); - this._detectedErrors.delete(message); - } - private async _performFullScan(showingNotice?: boolean, ignoreSuspending: boolean = false): Promise { - this._log("Opening the key-value database", LOG_LEVEL_VERBOSE); - const isInitialized = (await this.core.kvDB.get("initialized")) || false; - // synchronize all files between database and storage. - - const ERR_NOT_CONFIGURED = - "LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented."; - if (!this.settings.isConfigured) { - this.logDetectedError(ERR_NOT_CONFIGURED, showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll"); - return false; - } - this.resetDetectedError(ERR_NOT_CONFIGURED); - - const ERR_SUSPENDING = - "Now suspending file watching. Synchronising between the storage and the local database is now prevented."; - if (!ignoreSuspending && this.settings.suspendFileWatching) { - this.logDetectedError(ERR_SUSPENDING, showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll"); - return false; - } - const MSG_IN_REMEDIATION = `Started in remediation Mode! (Max mtime for reflect events is set). Synchronising between the storage and the local database is now prevented.`; - this.resetDetectedError(ERR_SUSPENDING); - if (this.settings.maxMTimeForReflectEvents > 0) { - this.logDetectedError(MSG_IN_REMEDIATION, LOG_LEVEL_NOTICE, "syncAll"); - return false; - } - this.resetDetectedError(MSG_IN_REMEDIATION); - - if (showingNotice) { - this._log("Initializing", LOG_LEVEL_NOTICE, "syncAll"); - } - if (isInitialized) { - this._log("Restoring storage state", LOG_LEVEL_VERBOSE); - await this.core.storageAccess.restoreState(); - } - - this._log("Initialize and checking database files"); - this._log("Checking deleted files"); - await this.collectDeletedFiles(); - - this._log("Collecting local files on the storage", LOG_LEVEL_VERBOSE); - const filesStorageSrc = await this.core.storageAccess.getFiles(); - - const _filesStorage = [] as typeof filesStorageSrc; - - for (const f of filesStorageSrc) { - if (await this.services.vault.isTargetFile(f.path)) { - _filesStorage.push(f); - } - } - - const convertCase = (path: FilePathWithPrefix): FilePathWithPrefixLC => { - if (this.settings.handleFilenameCaseSensitive) { - return path as FilePathWithPrefixLC; - } - return (path as string).toLowerCase() as FilePathWithPrefixLC; - }; - - // If handleFilenameCaseSensitive is enabled, `FilePathWithPrefixLC` is the same as `FilePathWithPrefix`. - - const storageFileNameMap = Object.fromEntries( - _filesStorage.map((e) => [e.path, e] as [FilePathWithPrefix, UXFileInfoStub]) - ); - - const storageFileNames = Object.keys(storageFileNameMap) as FilePathWithPrefix[]; - - const storageFileNameCapsPair = storageFileNames.map( - (e) => [e, convertCase(e)] as [FilePathWithPrefix, FilePathWithPrefixLC] - ); - - // const storageFileNameCS2CI = Object.fromEntries(storageFileNameCapsPair) as Record; - const storageFileNameCI2CS = Object.fromEntries(storageFileNameCapsPair.map((e) => [e[1], e[0]])) as Record< - FilePathWithPrefixLC, - FilePathWithPrefix - >; - - this._log("Collecting local files on the DB", LOG_LEVEL_VERBOSE); - const _DBEntries = [] as MetaEntry[]; - let count = 0; - // Fetch all documents from the database (including conflicts to prevent overwriting). - for await (const doc of this.localDatabase.findAllNormalDocs({ conflicts: true })) { - count++; - if (count % 25 == 0) - this._log( - `Collecting local files on the DB: ${count}`, - showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, - "syncAll" - ); - const path = this.getPath(doc); - - if (isValidPath(path) && (await this.services.vault.isTargetFile(path))) { - if (!isMetaEntry(doc)) { - this._log(`Invalid entry: ${path}`, LOG_LEVEL_INFO); - continue; - } - _DBEntries.push(doc); - } - } - - const databaseFileNameMap = Object.fromEntries( - _DBEntries.map((e) => [this.getPath(e), e] as [FilePathWithPrefix, MetaEntry]) - ); - const databaseFileNames = Object.keys(databaseFileNameMap) as FilePathWithPrefix[]; - const databaseFileNameCapsPair = databaseFileNames.map( - (e) => [e, convertCase(e)] as [FilePathWithPrefix, FilePathWithPrefixLC] - ); - // const databaseFileNameCS2CI = Object.fromEntries(databaseFileNameCapsPair) as Record; - const databaseFileNameCI2CS = Object.fromEntries(databaseFileNameCapsPair.map((e) => [e[1], e[0]])) as Record< - FilePathWithPrefix, - FilePathWithPrefixLC - >; - - const allFiles = unique([ - ...Object.keys(databaseFileNameCI2CS), - ...Object.keys(storageFileNameCI2CS), - ]) as FilePathWithPrefixLC[]; - - 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: ${allFiles.length}`, LOG_LEVEL_VERBOSE, "syncAll"); - const filesExistOnlyInStorage = allFiles.filter((e) => !databaseFileNameCI2CS[e]); - const filesExistOnlyInDatabase = allFiles.filter((e) => !storageFileNameCI2CS[e]); - const filesExistBoth = allFiles.filter((e) => databaseFileNameCI2CS[e] && storageFileNameCI2CS[e]); - - this._log(`Files exist only in storage: ${filesExistOnlyInStorage.length}`, LOG_LEVEL_VERBOSE, "syncAll"); - this._log(`Files exist only in database: ${filesExistOnlyInDatabase.length}`, LOG_LEVEL_VERBOSE, "syncAll"); - this._log(`Files exist both in storage and database: ${filesExistBoth.length}`, LOG_LEVEL_VERBOSE, "syncAll"); - - this._log("Synchronising..."); - const processStatus = {} as Record; - const logLevel = showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO; - const updateLog = throttle((key: string, msg: string) => { - processStatus[key] = msg; - const log = Object.values(processStatus).join("\n"); - this._log(log, logLevel, "syncAll"); - }, 25); - - const initProcess = []; - const runAll = async (procedureName: string, objects: T[], callback: (arg: T) => Promise) => { - if (objects.length == 0) { - this._log(`${procedureName}: Nothing to do`); - return; - } - this._log(procedureName); - if (!this.localDatabase.isReady) throw Error("Database is not ready!"); - let success = 0; - let failed = 0; - let total = 0; - for await (const result of withConcurrency( - objects, - async (e) => { - try { - await callback(e); - return true; - } catch (ex) { - this._log(`Error while ${procedureName}`, LOG_LEVEL_NOTICE); - this._log(ex, LOG_LEVEL_VERBOSE); - return false; - } - }, - 10 - )) { - if (result) { - success++; - } else { - failed++; - } - total++; - const msg = `${procedureName}: DONE:${success}, FAILED:${failed}, LAST:${objects.length - total}`; - updateLog(procedureName, msg); - } - const msg = `${procedureName} All done: DONE:${success}, FAILED:${failed}`; - updateLog(procedureName, msg); - }; - initProcess.push( - runAll("UPDATE DATABASE", filesExistOnlyInStorage, async (e) => { - // Exists in storage but not in database. - const file = storageFileNameMap[storageFileNameCI2CS[e]]; - if (!this.services.vault.isFileSizeTooLarge(file.stat.size)) { - const path = file.path; - await this.core.fileHandler.storeFileToDB(file); - // fireAndForget(() => this.checkAndApplySettingFromMarkdown(path, true)); - eventHub.emitEvent("event-file-changed", { file: path, automated: true }); - } else { - this._log(`UPDATE DATABASE: ${e} has been skipped due to file size exceeding the limit`, logLevel); - } - }) - ); - initProcess.push( - runAll("UPDATE STORAGE", filesExistOnlyInDatabase, async (e) => { - const w = databaseFileNameMap[databaseFileNameCI2CS[e]]; - // Exists in database but not in storage. - const path = this.getPath(w) ?? e; - if (w && !(w.deleted || w._deleted)) { - if (!this.services.vault.isFileSizeTooLarge(w.size)) { - // Prevent applying the conflicted state to the storage. - if (w._conflicts?.length ?? 0 > 0) { - this._log(`UPDATE STORAGE: ${path} has conflicts. skipped (x)`, LOG_LEVEL_INFO); - return; - } - // await this.pullFile(path, undefined, false, undefined, false); - // Memo: No need to force - await this.core.fileHandler.dbToStorage(path, null, true); - // fireAndForget(() => this.checkAndApplySettingFromMarkdown(e, true)); - eventHub.emitEvent("event-file-changed", { - file: e, - automated: true, - }); - this._log(`Check or pull from db:${path} OK`); - } else { - this._log( - `UPDATE STORAGE: ${path} has been skipped due to file size exceeding the limit`, - logLevel - ); - } - } else if (w) { - this._log(`Deletion history skipped: ${path}`, LOG_LEVEL_VERBOSE); - } else { - this._log(`entry not found: ${path}`); - } - }) - ); - - const fileMap = filesExistBoth.map((path) => { - const file = storageFileNameMap[storageFileNameCI2CS[path]]; - const doc = databaseFileNameMap[databaseFileNameCI2CS[path]]; - return { file, doc }; - }); - initProcess.push( - runAll("SYNC DATABASE AND STORAGE", fileMap, async (e) => { - const { file, doc } = e; - // Prevent applying the conflicted state to the storage. - if (doc._conflicts?.length ?? 0 > 0) { - this._log(`SYNC DATABASE AND STORAGE: ${file.path} has conflicts. skipped`, LOG_LEVEL_INFO); - return; - } - if ( - !this.services.vault.isFileSizeTooLarge(file.stat.size) && - !this.services.vault.isFileSizeTooLarge(doc.size) - ) { - await this.syncFileBetweenDBandStorage(file, doc); - } else { - this._log( - `SYNC DATABASE AND STORAGE: ${this.getPath(doc)} has been skipped due to file size exceeding the limit`, - logLevel - ); - } - }) - ); - - await Promise.all(initProcess); - - // this.setStatusBarText(`NOW TRACKING!`); - this._log("Initialized, NOW TRACKING!"); - if (!isInitialized) { - await this.core.kvDB.set("initialized", true); - } - if (showingNotice) { - this._log("Initialize done!", LOG_LEVEL_NOTICE, "syncAll"); - } - return true; - } - - async syncFileBetweenDBandStorage(file: UXFileInfoStub, doc: MetaEntry) { - if (!doc) { - throw new Error(`Missing doc:${(file as any).path}`); - } - if ("path" in file) { - const w = await this.core.storageAccess.getFileStub((file as any).path); - if (w) { - file = w; - } else { - throw new Error(`Missing file:${(file as any).path}`); - } - } - - const compareResult = this.services.path.compareFileFreshness(file, doc); - switch (compareResult) { - case BASE_IS_NEW: - if (!this.services.vault.isFileSizeTooLarge(file.stat.size)) { - this._log("STORAGE -> DB :" + file.path); - await this.core.fileHandler.storeFileToDB(file); - } else { - this._log( - `STORAGE -> DB : ${file.path} has been skipped due to file size exceeding the limit`, - LOG_LEVEL_NOTICE - ); - } - break; - case TARGET_IS_NEW: - if (!this.services.vault.isFileSizeTooLarge(doc.size)) { - this._log("STORAGE <- DB :" + file.path); - if (await this.core.fileHandler.dbToStorage(doc, stripAllPrefixes(file.path), true)) { - eventHub.emitEvent("event-file-changed", { - file: file.path, - automated: true, - }); - } else { - this._log(`STORAGE <- DB : Cloud not read ${file.path}, possibly deleted`, LOG_LEVEL_NOTICE); - } - return caches; - } else { - this._log( - `STORAGE <- DB : ${file.path} has been skipped due to file size exceeding the limit`, - LOG_LEVEL_NOTICE - ); - } - break; - case EVEN: - this._log("STORAGE == DB :" + file.path + "", LOG_LEVEL_DEBUG); - break; - default: - this._log("STORAGE ?? DB :" + file.path + " Something got weird"); - } - } - - // This method uses an old version of database accessor, which is not recommended. - // TODO: Fix - async collectDeletedFiles() { - const limitDays = this.settings.automaticallyDeleteMetadataOfDeletedFiles; - if (limitDays <= 0) return; - this._log(`Checking expired file history`); - const limit = Date.now() - 86400 * 1000 * limitDays; - const notes: { - path: string; - mtime: number; - ttl: number; - doc: PouchDB.Core.ExistingDocument; - }[] = []; - for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { - if (isAnyNote(doc)) { - if (doc.deleted && doc.mtime - limit < 0) { - notes.push({ - path: this.getPath(doc), - mtime: doc.mtime, - ttl: (doc.mtime - limit) / 1000 / 86400, - doc: doc, - }); - } - } - } - if (notes.length == 0) { - this._log("There are no old documents"); - this._log(`Checking expired file history done`); - return; - } - for (const v of notes) { - this._log(`Deletion history expired: ${v.path}`); - const delDoc = v.doc; - delDoc._deleted = true; - await this.localDatabase.putRaw(delDoc); - } - this._log(`Checking expired file history done`); - } - - private async _initializeDatabase( - showingNotice: boolean = false, - reopenDatabase = true, - ignoreSuspending: boolean = false - ): Promise { - this.services.appLifecycle.resetIsReady(); - if ( - !reopenDatabase || - (await this.services.database.openDatabase({ - databaseEvents: this.services.databaseEvents, - replicator: this.services.replicator, - })) - ) { - if (this.localDatabase.isReady) { - await this.services.vault.scanVault(showingNotice, ignoreSuspending); - } - const ERR_INITIALISATION_FAILED = `Initializing database has been failed on some module!`; - if (!(await this.services.databaseEvents.onDatabaseInitialised(showingNotice))) { - this.logDetectedError(ERR_INITIALISATION_FAILED, LOG_LEVEL_NOTICE); - return false; - } - this.resetDetectedError(ERR_INITIALISATION_FAILED); - this.services.appLifecycle.markIsReady(); - // run queued event once. - await this.services.fileProcessing.commitPendingFileEvents(); - return true; - } else { - this.services.appLifecycle.resetIsReady(); - return false; - } - } - private _reportDetectedErrors(): Promise { - return Promise.resolve(Array.from(this._detectedErrors)); - } - override onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void { - services.appLifecycle.getUnresolvedMessages.addHandler(this._reportDetectedErrors.bind(this)); - services.databaseEvents.initialiseDatabase.addHandler(this._initializeDatabase.bind(this)); - services.vault.scanVault.addHandler(this._performFullScan.bind(this)); - } -} diff --git a/src/modules/essentialObsidian/ModuleCheckRemoteSize_obsolete.ts b/src/modules/essentialObsidian/ModuleCheckRemoteSize_obsolete.ts deleted file mode 100644 index 7d1c9a3..0000000 --- a/src/modules/essentialObsidian/ModuleCheckRemoteSize_obsolete.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger"; -import { sizeToHumanReadable } from "octagonal-wheels/number"; -import { $msg } from "src/lib/src/common/i18n.ts"; -import type { LiveSyncCore } from "../../main.ts"; -import { EVENT_REQUEST_CHECK_REMOTE_SIZE, eventHub } from "@/common/events.ts"; -import { AbstractModule } from "../AbstractModule.ts"; - -export class ModuleCheckRemoteSize extends AbstractModule { - checkRemoteSize(): Promise { - this.settings.notifyThresholdOfRemoteStorageSize = 1; - return this._allScanStat(); - } - - private async _allScanStat(): Promise { - if (this.services.API.isOnline === false) { - this._log("Network is offline, skipping remote size check.", LOG_LEVEL_INFO); - return true; - } - this._log($msg("moduleCheckRemoteSize.logCheckingStorageSizes"), LOG_LEVEL_VERBOSE); - if (this.settings.notifyThresholdOfRemoteStorageSize < 0) { - const message = $msg("moduleCheckRemoteSize.msgSetDBCapacity"); - const ANSWER_0 = $msg("moduleCheckRemoteSize.optionNoWarn"); - const ANSWER_800 = $msg("moduleCheckRemoteSize.option800MB"); - const ANSWER_2000 = $msg("moduleCheckRemoteSize.option2GB"); - const ASK_ME_NEXT_TIME = $msg("moduleCheckRemoteSize.optionAskMeLater"); - - const ret = await this.core.confirm.askSelectStringDialogue( - message, - [ANSWER_0, ANSWER_800, ANSWER_2000, ASK_ME_NEXT_TIME], - { - defaultAction: ASK_ME_NEXT_TIME, - title: $msg("moduleCheckRemoteSize.titleDatabaseSizeNotify"), - timeout: 40, - } - ); - if (ret == ANSWER_0) { - this.settings.notifyThresholdOfRemoteStorageSize = 0; - await this.saveSettings(); - } else if (ret == ANSWER_800) { - this.settings.notifyThresholdOfRemoteStorageSize = 800; - await this.saveSettings(); - } else if (ret == ANSWER_2000) { - this.settings.notifyThresholdOfRemoteStorageSize = 2000; - await this.saveSettings(); - } - } - if (this.settings.notifyThresholdOfRemoteStorageSize > 0) { - const remoteStat = await this.core.replicator?.getRemoteStatus(this.settings); - if (remoteStat) { - const estimatedSize = remoteStat.estimatedSize; - if (estimatedSize) { - const maxSize = this.settings.notifyThresholdOfRemoteStorageSize * 1024 * 1024; - if (estimatedSize > maxSize) { - const message = $msg("moduleCheckRemoteSize.msgDatabaseGrowing", { - estimatedSize: sizeToHumanReadable(estimatedSize), - maxSize: sizeToHumanReadable(maxSize), - }); - const newMax = ~~(estimatedSize / 1024 / 1024) + 100; - const ANSWER_ENLARGE_LIMIT = $msg("moduleCheckRemoteSize.optionIncreaseLimit", { - newMax: newMax.toString(), - }); - const ANSWER_REBUILD = $msg("moduleCheckRemoteSize.optionRebuildAll"); - const ANSWER_IGNORE = $msg("moduleCheckRemoteSize.optionDismiss"); - const ret = await this.core.confirm.askSelectStringDialogue( - message, - [ANSWER_ENLARGE_LIMIT, ANSWER_REBUILD, ANSWER_IGNORE], - { - defaultAction: ANSWER_IGNORE, - title: $msg("moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded"), - timeout: 60, - } - ); - if (ret == ANSWER_REBUILD) { - const ret = await this.core.confirm.askYesNoDialog( - $msg("moduleCheckRemoteSize.msgConfirmRebuild"), - { defaultOption: "No" } - ); - if (ret == "yes") { - this.core.settings.notifyThresholdOfRemoteStorageSize = -1; - await this.saveSettings(); - await this.core.rebuilder.scheduleRebuild(); - } - } else if (ret == ANSWER_ENLARGE_LIMIT) { - this.settings.notifyThresholdOfRemoteStorageSize = ~~(estimatedSize / 1024 / 1024) + 100; - this._log( - $msg("moduleCheckRemoteSize.logThresholdEnlarged", { - size: this.settings.notifyThresholdOfRemoteStorageSize.toString(), - }), - LOG_LEVEL_NOTICE - ); - // await this.core.saveSettings(); - await this.core.services.setting.saveSettingData(); - } else { - // Dismiss or Close the dialog - } - - this._log( - $msg("moduleCheckRemoteSize.logExceededWarning", { - measuredSize: sizeToHumanReadable(estimatedSize), - notifySize: sizeToHumanReadable( - this.settings.notifyThresholdOfRemoteStorageSize * 1024 * 1024 - ), - }), - LOG_LEVEL_INFO - ); - } else { - this._log( - $msg("moduleCheckRemoteSize.logCurrentStorageSize", { - measuredSize: sizeToHumanReadable(estimatedSize), - }), - LOG_LEVEL_INFO - ); - } - } - } - } - return true; - } - - private _everyOnloadStart(): Promise { - this.addCommand({ - id: "livesync-reset-remote-size-threshold-and-check", - name: "Reset notification threshold and check the remote database usage", - callback: async () => { - await this.checkRemoteSize(); - }, - }); - eventHub.onEvent(EVENT_REQUEST_CHECK_REMOTE_SIZE, () => this.checkRemoteSize()); - return Promise.resolve(true); - } - override onBindFunction(core: LiveSyncCore, services: typeof core.services): void { - services.appLifecycle.onScanningStartupIssues.addHandler(this._allScanStat.bind(this)); - services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this)); - } -}