diff --git a/src/apps/webpeer/package.json b/src/apps/webpeer/package.json index dd12898..990666f 100644 --- a/src/apps/webpeer/package.json +++ b/src/apps/webpeer/package.json @@ -20,6 +20,7 @@ "vite": "^7.3.0" }, "imports": { - "../../src/worker/bgWorker.ts": "../../src/worker/bgWorker.mock.ts" + "../../src/worker/bgWorker.ts": "../../src/worker/bgWorker.mock.ts", + "@lib/worker/bgWorker.ts": "@lib/worker/bgWorker.mock.ts" } } diff --git a/src/apps/webpeer/src/P2PReplicatorShim.ts b/src/apps/webpeer/src/P2PReplicatorShim.ts index c548fd1..65b8759 100644 --- a/src/apps/webpeer/src/P2PReplicatorShim.ts +++ b/src/apps/webpeer/src/P2PReplicatorShim.ts @@ -35,6 +35,7 @@ import { SETTING_KEY_P2P_DEVICE_NAME } from "@lib/common/types"; import { ServiceContext } from "@lib/services/base/ServiceBase"; import type { InjectableServiceHub } from "@lib/services/InjectableServices"; import { Menu } from "@/lib/src/services/implements/browser/Menu"; +import type { InjectableVaultServiceCompat } from "@/lib/src/services/implements/injectable/InjectableVaultService"; function addToList(item: string, list: string) { return unique( @@ -79,7 +80,13 @@ export class P2PReplicatorShim implements P2PReplicatorBase, CommandShim { constructor() { const browserServiceHub = new BrowserServiceHub(); this.services = browserServiceHub; - this.services.vault.getVaultName.setHandler(() => "p2p-livesync-web-peer"); + (this.services.vault as InjectableVaultServiceCompat).vaultName.setHandler( + () => "p2p-livesync-web-peer" + ); + + this.services.setting.currentSettings.setHandler(() => { + return this.settings as any; + }); } async init() { // const { simpleStoreAPI } = await getWrappedSynchromesh(); diff --git a/src/common/types.ts b/src/common/types.ts index 51f877e..c7b903c 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -49,21 +49,16 @@ export type queueItem = { warned?: boolean; }; -// Hidden items (Now means `chunk`) -export const CHeader = "h:"; - -// Plug-in Stored Container (Obsolete) -export const PSCHeader = "ps:"; -export const PSCHeaderEnd = "ps;"; - -// Internal data Container -export const ICHeader = "i:"; -export const ICHeaderEnd = "i;"; -export const ICHeaderLength = ICHeader.length; - -// Internal data Container (eXtended) -export const ICXHeader = "ix:"; - export const FileWatchEventQueueMax = 10; export { configURIBase, configURIBaseQR } from "../lib/src/common/types.ts"; + +export { + CHeader, + PSCHeader, + PSCHeaderEnd, + ICHeader, + ICHeaderEnd, + ICHeaderLength, + ICXHeader, +} from "../lib/src/common/models/fileaccess.const.ts"; diff --git a/src/common/utils.ts b/src/common/utils.ts index 75f6546..254a419 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -23,7 +23,7 @@ import { type UXFileInfo, type UXFileInfoStub, } from "../lib/src/common/types.ts"; -import { CHeader, ICHeader, ICHeaderLength, ICXHeader, PSCHeader } from "./types.ts"; +import { ICHeader, ICXHeader } from "./types.ts"; import type ObsidianLiveSyncPlugin from "../main.ts"; import { writeString } from "../lib/src/string_and_binary/convert.ts"; import { fireAndForget } from "../lib/src/common/utils.ts"; @@ -63,23 +63,12 @@ export function id2path(id: DocumentID, entry?: EntryHasPath): FilePathWithPrefi const fixedPath = temp.join(":") as FilePathWithPrefix; return fixedPath; } -export function getPath(entry: AnyEntry) { - return id2path(entry._id, entry); -} -export function getPathWithoutPrefix(entry: AnyEntry) { - const f = getPath(entry); - return stripAllPrefixes(f); -} export function getPathFromTFile(file: TAbstractFile) { return file.path as FilePath; } -export function isInternalFile(file: UXFileInfoStub | string | FilePathWithPrefix) { - if (typeof file == "string") return file.startsWith(ICHeader); - if (file.isInternal) return true; - return false; -} +import { isInternalFile } from "@lib/common/typeUtils.ts"; export function getPathFromUXFileInfo(file: UXFileInfoStub | string | FilePathWithPrefix) { if (typeof file == "string") return file as FilePathWithPrefix; return file.path; @@ -137,32 +126,14 @@ export function trimPrefix(target: string, prefix: string) { return target.startsWith(prefix) ? target.substring(prefix.length) : target; } -/** - * returns is internal chunk of file - * @param id ID - * @returns - */ -export function isInternalMetadata(id: FilePath | FilePathWithPrefix | DocumentID): boolean { - return id.startsWith(ICHeader); -} -export function stripInternalMetadataPrefix(id: T): T { - return id.substring(ICHeaderLength) as T; -} -export function id2InternalMetadataId(id: DocumentID): DocumentID { - return (ICHeader + id) as DocumentID; -} - -// const CHeaderLength = CHeader.length; -export function isChunk(str: string): boolean { - return str.startsWith(CHeader); -} - -export function isPluginMetadata(str: string): boolean { - return str.startsWith(PSCHeader); -} -export function isCustomisationSyncMetadata(str: string): boolean { - return str.startsWith(ICXHeader); -} +export { + isInternalMetadata, + id2InternalMetadataId, + isChunk, + isCustomisationSyncMetadata, + isPluginMetadata, + stripInternalMetadataPrefix, +} from "@lib/common/typeUtils.ts"; export class PeriodicProcessor { _process: () => Promise; @@ -430,29 +401,6 @@ export function displayRev(rev: string) { return `${number}-${hash.substring(0, 6)}`; } -type DocumentProps = { - id: DocumentID; - rev?: string; - prefixedPath: FilePathWithPrefix; - path: FilePath; - isDeleted: boolean; - revDisplay: string; - shortenedId: string; - shortenedPath: string; -}; - -export function getDocProps(doc: AnyEntry): DocumentProps { - const id = doc._id; - const shortenedId = id.substring(0, 10); - const prefixedPath = getPath(doc); - const path = stripAllPrefixes(prefixedPath); - const rev = doc._rev; - const revDisplay = rev ? displayRev(rev) : "0-NOREVS"; - // const prefix = prefixedPath.substring(0, prefixedPath.length - path.length); - const shortenedPath = path.substring(0, 10); - const isDeleted = doc._deleted || doc.deleted || false; - return { id, rev, revDisplay, prefixedPath, path, isDeleted, shortenedId, shortenedPath }; -} export function getLogLevel(showNotice: boolean) { return showNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO; diff --git a/src/features/HiddenFileSync/CmdHiddenFileSync.ts b/src/features/HiddenFileSync/CmdHiddenFileSync.ts index dd7a323..8d50d74 100644 --- a/src/features/HiddenFileSync/CmdHiddenFileSync.ts +++ b/src/features/HiddenFileSync/CmdHiddenFileSync.ts @@ -30,19 +30,18 @@ import { import { compareMTime, unmarkChanges, - getPath, isInternalMetadata, markChangesAreSame, PeriodicProcessor, TARGET_IS_NEW, scheduleTask, - getDocProps, getLogLevel, autosaveCache, type MapLike, onlyInNTimes, BASE_IS_NEW, EVEN, + displayRev, } from "../../common/utils.ts"; import { serialized, skipIfDuplicated } from "octagonal-wheels/concurrency/lock"; import { JsonResolveModal } from "../HiddenFileCommon/JsonResolveModal.ts"; @@ -139,6 +138,7 @@ export class HiddenFileSync extends LiveSyncCommands { this.updateSettingCache(); }); } + // We cannot initialise autosaveCache because kvDB is not ready yet // async _everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise { // this._fileInfoLastProcessed = await autosaveCache(this.kvDB, "hidden-file-lastProcessed"); @@ -243,7 +243,7 @@ export class HiddenFileSync extends LiveSyncCommands { if (isInternalMetadata(doc._id)) { if (this.isThisModuleEnabled()) { //system file - const filename = getPath(doc); + const filename = this.getPath(doc); if (await this.services.vault.isTargetFile(filename)) { // this.procInternalFile(filename); await this.processReplicationResult(doc); @@ -843,9 +843,32 @@ Offline Changed files: ${processFiles.length}`; // <-- Conflict processing // --> Event Source Handler (Database) - + getDocProps(doc: LoadedEntry) { + /* + type DocumentProps = { + id: DocumentID; + rev?: string; + prefixedPath: FilePathWithPrefix; + path: FilePath; + isDeleted: boolean; + revDisplay: string; + shortenedId: string; + shortenedPath: string; + }; + */ + const id = doc._id; + const shortenedId = id.substring(0, 10); + const prefixedPath = this.getPath(doc); + const path = stripAllPrefixes(prefixedPath); + const rev = doc._rev; + const revDisplay = rev ? displayRev(rev) : "0-NOREVS"; + // const prefix = prefixedPath.substring(0, prefixedPath.length - path.length); + const shortenedPath = path.substring(0, 10); + const isDeleted = doc._deleted || doc.deleted || false; + return { id, rev, revDisplay, prefixedPath, path, isDeleted, shortenedId, shortenedPath }; + } async processReplicationResult(doc: LoadedEntry): Promise { - const info = getDocProps(doc); + const info = this.getDocProps(doc); const path = info.path; const headerLine = `Tracking DB ${info.path} (${info.revDisplay}) :`; const ret = await this.trackDatabaseFileModification(path, headerLine); @@ -1007,7 +1030,7 @@ Offline Changed files: ${processFiles.length}`; p.log("Enumerating database files..."); const currentDatabaseFiles = await this.getAllDatabaseFiles(); const allDatabaseMap = Object.fromEntries( - currentDatabaseFiles.map((e) => [stripAllPrefixes(getPath(e)), e]) + currentDatabaseFiles.map((e) => [stripAllPrefixes(this.getPath(e)), e]) ); const currentDatabaseFileNames = [...Object.keys(allDatabaseMap)] as FilePath[]; const untrackedLocal = currentStorageFiles.filter((e) => !this._fileInfoLastProcessed.has(e)); @@ -1250,14 +1273,14 @@ Offline Changed files: ${files.length}`; : currentStorageFilesAll; p.log("Enumerating database files..."); const allDatabaseFiles = await this.getAllDatabaseFiles(); - const allDatabaseMap = new Map(allDatabaseFiles.map((e) => [stripAllPrefixes(getPath(e)), e])); + const allDatabaseMap = new Map(allDatabaseFiles.map((e) => [stripAllPrefixes(this.getPath(e)), e])); const currentDatabaseFiles = targetFiles - ? allDatabaseFiles.filter((e) => targetFiles.some((f) => f == stripAllPrefixes(getPath(e)))) + ? allDatabaseFiles.filter((e) => targetFiles.some((f) => f == stripAllPrefixes(this.getPath(e)))) : allDatabaseFiles; const allFileNames = new Set([ ...currentStorageFiles, - ...currentDatabaseFiles.map((e) => stripAllPrefixes(getPath(e))), + ...currentDatabaseFiles.map((e) => stripAllPrefixes(this.getPath(e))), ]); const storageToDatabase = [] as FilePath[]; const databaseToStorage = [] as MetaEntry[]; @@ -1340,7 +1363,7 @@ Offline Changed files: ${files.length}`; // However, in perspective of performance and future-proofing, I feel somewhat justified in doing it here. const currentFiles = targetFiles - ? allFiles.filter((e) => targetFiles.some((f) => f == stripAllPrefixes(getPath(e)))) + ? allFiles.filter((e) => targetFiles.some((f) => f == stripAllPrefixes(this.getPath(e)))) : allFiles; p.once(`Database to Storage: ${currentFiles.length} files.`); @@ -1383,7 +1406,7 @@ Offline Changed files: ${files.length}`; const onlyNew = direction == "pull"; p.log(`Started: Database --> Storage ${onlyNew ? "(Only New)" : ""}`); const updatedEntries = await this.rebuildFromDatabase(showMessage, targetFiles, onlyNew); - const updatedFiles = updatedEntries.map((e) => stripAllPrefixes(getPath(e))); + const updatedFiles = updatedEntries.map((e) => stripAllPrefixes(this.getPath(e))); // making doubly sure, No more losing files. await this.adoptCurrentStorageFilesAsProcessed(updatedFiles); await this.adoptCurrentDatabaseFilesAsProcessed(updatedFiles); diff --git a/src/features/LiveSyncCommands.ts b/src/features/LiveSyncCommands.ts index 9732d94..e7db590 100644 --- a/src/features/LiveSyncCommands.ts +++ b/src/features/LiveSyncCommands.ts @@ -1,5 +1,4 @@ import { LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger"; -import { getPath } from "../common/utils.ts"; import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, @@ -36,8 +35,9 @@ export abstract class LiveSyncCommands { async path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise { return await this.services.path.path2id(filename, prefix); } + getPath(entry: AnyEntry): FilePathWithPrefix { - return getPath(entry); + return this.services.path.getPath(entry); } constructor(plugin: ObsidianLiveSyncPlugin) { diff --git a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte index c1322f0..a0382bb 100644 --- a/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte +++ b/src/features/P2PSync/P2PReplicator/P2PReplicatorPane.svelte @@ -33,18 +33,15 @@ const initialSettings = { ...plugin.settings }; let settings = $state(initialSettings); - // const vaultName = service.vault.getVaultName(); - // const dbKey = `${vaultName}-p2p-device-name`; - const initialDeviceName = cmdSync.getConfig(SETTING_KEY_P2P_DEVICE_NAME) ?? plugin.services.vault.getVaultName(); - let deviceName = $state(initialDeviceName); + let deviceName = $state(""); let eP2PEnabled = $state(initialSettings.P2P_Enabled); let eRelay = $state(initialSettings.P2P_relays); let eRoomId = $state(initialSettings.P2P_roomID); let ePassword = $state(initialSettings.P2P_passphrase); let eAppId = $state(initialSettings.P2P_AppID); - let eDeviceName = $state(initialDeviceName); + let eDeviceName = $state(""); let eAutoAccept = $state(initialSettings.P2P_AutoAccepting == AutoAccepting.ALL); let eAutoStart = $state(initialSettings.P2P_AutoStart); let eAutoBroadcast = $state(initialSettings.P2P_AutoBroadcast); @@ -103,6 +100,11 @@ let serverInfo = $state(undefined); let replicatorInfo = $state(undefined); const applyLoadSettings = (d: P2PSyncSetting, force: boolean) => { + if(force){ + const initDeviceName = cmdSync.getConfig(SETTING_KEY_P2P_DEVICE_NAME) ?? plugin.services.vault.getVaultName(); + deviceName = initDeviceName; + eDeviceName = initDeviceName; + } const { P2P_relays, P2P_roomID, P2P_passphrase, P2P_AppID, P2P_AutoAccepting } = d; if (force || !isP2PEnabledModified) eP2PEnabled = d.P2P_Enabled; if (force || !isRelayModified) eRelay = P2P_relays; diff --git a/src/lib b/src/lib index 750ddbb..af01893 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 750ddbb082157fa4c52953becaacc8ee8048f2b9 +Subproject commit af0189376f6379d404e99ddb201d1a9019eb3471 diff --git a/src/modules/AbstractModule.ts b/src/modules/AbstractModule.ts index b49d155..33916b2 100644 --- a/src/modules/AbstractModule.ts +++ b/src/modules/AbstractModule.ts @@ -1,7 +1,8 @@ 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 { LiveSyncCore } from "../main"; -import { __$checkInstanceBinding } from "../lib/src/dev/checks"; +import type { AnyEntry, FilePathWithPrefix, LOG_LEVEL } from "@lib/common/types"; +import type { LiveSyncCore } from "@/main"; +import { __$checkInstanceBinding } from "@lib/dev/checks"; +import { stripAllPrefixes } from "@lib/string_and_binary/path"; export abstract class AbstractModule { _log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => { @@ -22,6 +23,14 @@ export abstract class AbstractModule { this.core.settings = value; } + getPath(entry: AnyEntry): FilePathWithPrefix { + return this.services.path.getPath(entry); + } + + getPathWithoutPrefix(entry: AnyEntry): FilePathWithPrefix { + return stripAllPrefixes(this.services.path.getPath(entry)); + } + onBindFunction(core: LiveSyncCore, services: typeof core.services) { // Override if needed. } diff --git a/src/modules/core/ModuleFileHandler.ts b/src/modules/core/ModuleFileHandler.ts index 2699004..8094fd6 100644 --- a/src/modules/core/ModuleFileHandler.ts +++ b/src/modules/core/ModuleFileHandler.ts @@ -10,14 +10,7 @@ import type { UXInternalFileInfoStub, } from "../../lib/src/common/types"; import { AbstractModule } from "../AbstractModule.ts"; -import { - compareFileFreshness, - EVEN, - getPath, - getPathWithoutPrefix, - getStoragePathFromUXFileInfo, - markChangesAreSame, -} from "../../common/utils"; +import { compareFileFreshness, EVEN, getStoragePathFromUXFileInfo, markChangesAreSame } from "../../common/utils"; import { getDocDataAsArray, isDocContentSame, readAsBlob, readContent } from "../../lib/src/common/utils"; import { shouldBeIgnored } from "../../lib/src/string_and_binary/path"; import { Semaphore } from "octagonal-wheels/concurrency/semaphore"; @@ -209,13 +202,13 @@ export class ModuleFileHandler extends AbstractModule { ): Promise { const file = typeof info === "string" ? this.storage.getFileStub(info) : info; const mode = file == null ? "create" : "modify"; - const pathFromEntryInfo = typeof entryInfo === "string" ? entryInfo : getPath(entryInfo); + const pathFromEntryInfo = typeof entryInfo === "string" ? entryInfo : this.getPath(entryInfo); const docEntry = await this.db.fetchEntryMeta(pathFromEntryInfo, undefined, true); if (!docEntry) { this._log(`File ${pathFromEntryInfo} is not exist on the database`, LOG_LEVEL_VERBOSE); return false; } - const path = getPath(docEntry); + const path = this.getPath(docEntry); // 1. Check if it already conflicted. const revs = await this.db.getConflictedRevs(path); @@ -364,11 +357,11 @@ export class ModuleFileHandler extends AbstractModule { this._log(`File ${entry.path} should be ignored`, LOG_LEVEL_VERBOSE); return false; } - const path = getPath(entry); + const path = this.getPath(entry); - const targetFile = this.storage.getStub(getPathWithoutPrefix(entry)); + const targetFile = this.storage.getStub(this.getPathWithoutPrefix(entry)); if (targetFile && targetFile.isFolder) { - this._log(`${getPath(entry)} is already exist as the folder`); + this._log(`${path} is already exist as the folder`); // Nothing to do and other modules should also nothing to do. return true; } else { diff --git a/src/modules/core/ModuleLocalDatabaseObsidian.ts b/src/modules/core/ModuleLocalDatabaseObsidian.ts index 5b74a2a..412cadc 100644 --- a/src/modules/core/ModuleLocalDatabaseObsidian.ts +++ b/src/modules/core/ModuleLocalDatabaseObsidian.ts @@ -22,9 +22,9 @@ export class ModuleLocalDatabaseObsidian extends AbstractModule { return getDB(); }, getActiveReplicator: () => this.core.replicator, - id2path: this.services.path.id2path, + id2path: this.services.path.id2path.bind(this.services.path), // path2id: this.core.$$path2id.bind(this.core), - path2id: this.services.path.path2id, + path2id: this.services.path.path2id.bind(this.services.path), get settings() { return getSettings(); }, diff --git a/src/modules/core/ModuleTargetFilter.ts b/src/modules/core/ModuleTargetFilter.ts index 6e266ef..93816ab 100644 --- a/src/modules/core/ModuleTargetFilter.ts +++ b/src/modules/core/ModuleTargetFilter.ts @@ -1,22 +1,12 @@ import { LRUCache } from "octagonal-wheels/memory/LRUCache"; -import { - getStoragePathFromUXFileInfo, - id2path, - isInternalMetadata, - path2id, - stripInternalMetadataPrefix, - useMemo, -} from "../../common/utils"; +import { getStoragePathFromUXFileInfo, useMemo } from "../../common/utils"; import { LOG_LEVEL_VERBOSE, - type DocumentID, - type EntryHasPath, - type FilePath, type FilePathWithPrefix, type ObsidianLiveSyncSettings, type UXFileInfoStub, } from "../../lib/src/common/types"; -import { addPrefix, isAcceptedAll } from "../../lib/src/string_and_binary/path"; +import { isAcceptedAll } from "../../lib/src/string_and_binary/path"; import { AbstractModule } from "../AbstractModule"; import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events"; import { isDirty } from "../../lib/src/common/utils"; @@ -36,23 +26,6 @@ export class ModuleTargetFilter extends AbstractModule { return Promise.resolve(true); } - _id2path(id: DocumentID, entry?: EntryHasPath, stripPrefix?: boolean): FilePathWithPrefix { - const tempId = id2path(id, entry); - if (stripPrefix && isInternalMetadata(tempId)) { - const out = stripInternalMetadataPrefix(tempId); - return out; - } - return tempId; - } - async _path2id(filename: FilePathWithPrefix | FilePath, prefix?: string): Promise { - const destPath = addPrefix(filename, prefix ?? ""); - return await path2id( - destPath, - this.settings.usePathObfuscation ? this.settings.passphrase : "", - !this.settings.handleFilenameCaseSensitive - ); - } - _markFileListPossiblyChanged(): void { this.totalFileEventCount++; } @@ -166,8 +139,6 @@ export class ModuleTargetFilter extends AbstractModule { onBindFunction(core: LiveSyncCore, services: typeof core.services): void { services.vault.markFileListPossiblyChanged.setHandler(this._markFileListPossiblyChanged.bind(this)); - services.path.id2path.setHandler(this._id2path.bind(this)); - services.path.path2id.setHandler(this._path2id.bind(this)); services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this)); services.vault.isIgnoredByIgnoreFile.setHandler(this._isIgnoredByIgnoreFiles.bind(this)); services.vault.isTargetFile.setHandler(this._isTargetFile.bind(this)); diff --git a/src/modules/core/ReplicateResultProcessor.ts b/src/modules/core/ReplicateResultProcessor.ts index 6aa1acd..6b77a88 100644 --- a/src/modules/core/ReplicateResultProcessor.ts +++ b/src/modules/core/ReplicateResultProcessor.ts @@ -8,7 +8,7 @@ import { type MetaEntry, } from "@/lib/src/common/types"; import type { ModuleReplicator } from "./ModuleReplicator"; -import { getPath, isChunk, isValidPath } from "@/common/utils"; +import { isChunk, isValidPath } from "@/common/utils"; import type { LiveSyncCore } from "@/main"; import { LOG_LEVEL_DEBUG, @@ -58,6 +58,10 @@ export class ReplicateResultProcessor { return this.replicator.core; } + getPath(entry: AnyEntry): string { + return this.services.path.getPath(entry); + } + public suspend() { this._suspended = true; } @@ -230,7 +234,7 @@ export class ReplicateResultProcessor { */ protected enqueueChange(doc: PouchDB.Core.ExistingDocument) { const old = this._queuedChanges.find((e) => e._id == doc._id); - const path = "path" in doc ? getPath(doc) : ""; + const path = "path" in doc ? this.getPath(doc) : ""; const docNote = `${path} (${shortenId(doc._id)}, ${shortenRev(doc._rev)})`; if (old) { if (old._rev == doc._rev) { @@ -322,7 +326,7 @@ export class ReplicateResultProcessor { const docMtime = change.mtime ?? 0; const maxMTime = this.replicator.settings.maxMTimeForReflectEvents; if (maxMTime > 0 && docMtime > maxMTime) { - const docPath = getPath(change); + const docPath = this.getPath(change); this.log( `Processing ${docPath} has been skipped due to modification time (${new Date( docMtime * 1000 @@ -336,7 +340,7 @@ export class ReplicateResultProcessor { if (await this.services.replication.processVirtualDocument(change)) return; // If the document is version info, check compatibility and return. if (isAnyNote(change)) { - const docPath = getPath(change); + const docPath = this.getPath(change); if (!(await this.services.vault.isTargetFile(docPath))) { this.log(`Skipped: ${docPath}`, LOG_LEVEL_VERBOSE); return; @@ -383,7 +387,7 @@ export class ReplicateResultProcessor { // This function is serialized per document to avoid race-condition for the same document. private _applyToDatabase(doc_: PouchDB.Core.ExistingDocument) { const dbDoc = doc_ as LoadedEntry; // It has no `data` - const path = getPath(dbDoc); + const path = this.getPath(dbDoc); return serialized(`replication-process:${dbDoc._id}`, async () => { const docNote = `${path} (${shortenId(dbDoc._id)}, ${shortenRev(dbDoc._rev)})`; const isRequired = await this.checkIsChangeRequiredForDatabaseProcessing(dbDoc); @@ -409,7 +413,7 @@ export class ReplicateResultProcessor { if (await this.services.replication.processOptionalSynchroniseResult(dbDoc)) { // Already processed this.log(`Processed by other processor: ${docNote}`, LOG_LEVEL_DEBUG); - } else if (isValidPath(getPath(doc))) { + } else if (isValidPath(this.getPath(doc))) { // Apply to storage if the path is valid await this.applyToStorage(doc as MetaEntry); this.log(`Processed: ${docNote}`, LOG_LEVEL_DEBUG); @@ -437,7 +441,7 @@ export class ReplicateResultProcessor { * @returns True if processing is required; false otherwise */ protected async checkIsChangeRequiredForDatabaseProcessing(dbDoc: LoadedEntry): Promise { - const path = getPath(dbDoc); + const path = this.getPath(dbDoc); try { const savedDoc = await this.localDatabase.getRaw(dbDoc._id, { conflicts: true, diff --git a/src/modules/essential/ModuleInitializerFile.ts b/src/modules/essential/ModuleInitializerFile.ts index 78e3c4b..d170a01 100644 --- a/src/modules/essential/ModuleInitializerFile.ts +++ b/src/modules/essential/ModuleInitializerFile.ts @@ -1,7 +1,7 @@ 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, compareFileFreshness, EVEN, getPath, isValidPath, TARGET_IS_NEW } from "../../common/utils.ts"; +import { BASE_IS_NEW, compareFileFreshness, EVEN, isValidPath, TARGET_IS_NEW } from "../../common/utils.ts"; import { type FilePathWithPrefixLC, type FilePathWithPrefix, @@ -120,7 +120,7 @@ export class ModuleInitializerFile extends AbstractModule { showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll" ); - const path = getPath(doc); + const path = this.getPath(doc); if (isValidPath(path) && (await this.services.vault.isTargetFile(path, true))) { if (!isMetaEntry(doc)) { @@ -132,7 +132,7 @@ export class ModuleInitializerFile extends AbstractModule { } const databaseFileNameMap = Object.fromEntries( - _DBEntries.map((e) => [getPath(e), e] as [FilePathWithPrefix, MetaEntry]) + _DBEntries.map((e) => [this.getPath(e), e] as [FilePathWithPrefix, MetaEntry]) ); const databaseFileNames = Object.keys(databaseFileNameMap) as FilePathWithPrefix[]; const databaseFileNameCapsPair = databaseFileNames.map( @@ -224,7 +224,7 @@ export class ModuleInitializerFile extends AbstractModule { runAll("UPDATE STORAGE", filesExistOnlyInDatabase, async (e) => { const w = databaseFileNameMap[databaseFileNameCI2CS[e]]; // Exists in database but not in storage. - const path = getPath(w) ?? e; + 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. @@ -275,7 +275,7 @@ export class ModuleInitializerFile extends AbstractModule { await this.syncFileBetweenDBandStorage(file, doc); } else { this._log( - `SYNC DATABASE AND STORAGE: ${getPath(doc)} has been skipped due to file size exceeding the limit`, + `SYNC DATABASE AND STORAGE: ${this.getPath(doc)} has been skipped due to file size exceeding the limit`, logLevel ); } @@ -365,7 +365,7 @@ export class ModuleInitializerFile extends AbstractModule { if (isAnyNote(doc)) { if (doc.deleted && doc.mtime - limit < 0) { notes.push({ - path: getPath(doc), + path: this.getPath(doc), mtime: doc.mtime, ttl: (doc.mtime - limit) / 1000 / 86400, doc: doc, diff --git a/src/modules/essential/ModuleMigration.ts b/src/modules/essential/ModuleMigration.ts index a50d25c..90aca81 100644 --- a/src/modules/essential/ModuleMigration.ts +++ b/src/modules/essential/ModuleMigration.ts @@ -10,7 +10,7 @@ import { import { AbstractModule } from "../AbstractModule.ts"; import { $msg } from "src/lib/src/common/i18n.ts"; import { performDoctorConsultation, RebuildOptions } from "../../lib/src/common/configForDoc.ts"; -import { getPath, isValidPath } from "../../common/utils.ts"; +import { isValidPath } from "../../common/utils.ts"; import { isMetaEntry } from "../../lib/src/common/types.ts"; import { isDeletedEntry, isDocContentSame, isLoadedEntry, readAsBlob } from "../../lib/src/common/utils.ts"; import { countCompromisedChunks } from "../../lib/src/pouchdb/negotiation.ts"; @@ -128,7 +128,7 @@ export class ModuleMigration extends AbstractModule { const errorFiles = [] as ErrorInfo[]; for await (const metaDoc of this.localDatabase.findAllNormalDocs({ conflicts: true })) { - const path = getPath(metaDoc); + const path = this.getPath(metaDoc); if (!isValidPath(path)) { continue; diff --git a/src/modules/features/GlobalHistory/GlobalHistory.svelte b/src/modules/features/GlobalHistory/GlobalHistory.svelte index b6ed9a5..5e815e0 100644 --- a/src/modules/features/GlobalHistory/GlobalHistory.svelte +++ b/src/modules/features/GlobalHistory/GlobalHistory.svelte @@ -6,7 +6,6 @@ import { diff_match_patch } from "../../../deps.ts"; import { DocumentHistoryModal } from "../DocumentHistory/DocumentHistoryModal.ts"; import { isPlainText, stripAllPrefixes } from "../../../lib/src/string_and_binary/path.ts"; - import { getPath } from "../../../common/utils.ts"; export let plugin: ObsidianLiveSyncPlugin; let showDiffInfo = false; @@ -44,6 +43,9 @@ }; let history = [] as HistoryData[]; let loading = false; + function getPath(entry: AnyEntry): FilePathWithPrefix { + return plugin.services.path.getPath(entry); + } async function fetchChanges(): Promise { try { @@ -219,69 +221,69 @@ {/if} - - - - - - {#if showChunkCorrected} - - {/if} - - - - - {#each history as entry} - + + + + {#if showChunkCorrected} + + {/if} + + + - - + {#each history as entry} + + + - - {#if showChunkCorrected} - - {/if} - - {/each} - - + + {#if showChunkCorrected} + + {/if} + + {/each} + + - + {:else} +
+ {/if} + +
Date Path Rev Stat Chunks
- {#if loading} -
- {:else} -
- {/if} -
- {entry.mtimeDisp} + Date Path Rev Stat Chunks
+ {#if loading} +
+ {:else} +
+ {/if}
-
- /{entry.dirname.split("/").join(`​/`)} - - - - openFile(entry.path)}>{entry.filename} -
-
- - {#if entry.isPlain} +
+ {entry.mtimeDisp} + +
+ /{entry.dirname.split("/").join(`​/`)} - showHistory(entry.path, entry?.rev || "")}>{entry.rev} - {:else} - {entry.rev} - {/if} - -
- {entry.changes} - - {entry.chunks} + openFile(entry.path)}>{entry.filename} +
- {#if loading} + + + {#if entry.isPlain} + + + + showHistory(entry.path, entry?.rev || "")}>{entry.rev} + {:else} + {entry.rev} + {/if} + + + {entry.changes} + + {entry.chunks} +
+ {#if loading}
- {:else} -
- {/if} -
diff --git a/src/modules/features/ModuleInteractiveConflictResolver.ts b/src/modules/features/ModuleInteractiveConflictResolver.ts index aebd806..aea1fdf 100644 --- a/src/modules/features/ModuleInteractiveConflictResolver.ts +++ b/src/modules/features/ModuleInteractiveConflictResolver.ts @@ -11,7 +11,7 @@ import { } from "../../lib/src/common/types.ts"; import { ConflictResolveModal } from "./InteractiveConflictResolving/ConflictResolveModal.ts"; import { AbstractObsidianModule } from "../AbstractObsidianModule.ts"; -import { displayRev, getPath, getPathWithoutPrefix } from "../../common/utils.ts"; +import { displayRev } from "../../common/utils.ts"; import { fireAndForget } from "octagonal-wheels/promises"; import { serialized } from "octagonal-wheels/concurrency/lock"; import type { LiveSyncCore } from "../../main.ts"; @@ -110,7 +110,12 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule { const notes: { id: DocumentID; path: FilePathWithPrefix; dispPath: string; mtime: number }[] = []; for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { if (!("_conflicts" in doc)) continue; - notes.push({ id: doc._id, path: getPath(doc), dispPath: getPathWithoutPrefix(doc), mtime: doc.mtime }); + notes.push({ + id: doc._id, + path: this.getPath(doc), + dispPath: this.getPathWithoutPrefix(doc), + mtime: doc.mtime, + }); } notes.sort((a, b) => b.mtime - a.mtime); const notesList = notes.map((e) => e.dispPath); @@ -134,7 +139,7 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule { try { for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { if (!("_conflicts" in doc)) continue; - notes.push({ path: getPath(doc), mtime: doc.mtime }); + notes.push({ path: this.getPath(doc), mtime: doc.mtime }); } if (notes.length > 0) { this.core.confirm.askInPopup( diff --git a/src/modules/features/ModuleObsidianDocumentHistory.ts b/src/modules/features/ModuleObsidianDocumentHistory.ts index 2b89490..7a49dd7 100644 --- a/src/modules/features/ModuleObsidianDocumentHistory.ts +++ b/src/modules/features/ModuleObsidianDocumentHistory.ts @@ -4,7 +4,6 @@ import { EVENT_REQUEST_SHOW_HISTORY } from "../../common/obsidianEvents.ts"; import type { FilePathWithPrefix, LoadedEntry, DocumentID } from "../../lib/src/common/types.ts"; import { AbstractObsidianModule } from "../AbstractObsidianModule.ts"; import { DocumentHistoryModal } from "./DocumentHistory/DocumentHistoryModal.ts"; -import { getPath } from "../../common/utils.ts"; import { fireAndForget } from "octagonal-wheels/promises"; export class ModuleObsidianDocumentHistory extends AbstractObsidianModule { @@ -41,7 +40,7 @@ export class ModuleObsidianDocumentHistory extends AbstractObsidianModule { async fileHistory() { const notes: { id: DocumentID; path: FilePathWithPrefix; dispPath: string; mtime: number }[] = []; for await (const doc of this.localDatabase.findAllDocs()) { - notes.push({ id: doc._id, path: getPath(doc), dispPath: getPath(doc), mtime: doc.mtime }); + notes.push({ id: doc._id, path: this.getPath(doc), dispPath: this.getPath(doc), mtime: doc.mtime }); } notes.sort((a, b) => b.mtime - a.mtime); const notesList = notes.map((e) => e.dispPath); diff --git a/src/modules/features/SettingDialogue/PaneHatch.ts b/src/modules/features/SettingDialogue/PaneHatch.ts index 441f742..3796de1 100644 --- a/src/modules/features/SettingDialogue/PaneHatch.ts +++ b/src/modules/features/SettingDialogue/PaneHatch.ts @@ -21,7 +21,7 @@ import { } from "../../../lib/src/common/utils.ts"; import { Logger } from "../../../lib/src/common/logger.ts"; import { isCloudantURI } from "../../../lib/src/pouchdb/utils_couchdb.ts"; -import { getPath, requestToCouchDBWithCredentials } from "../../../common/utils.ts"; +import { requestToCouchDBWithCredentials } from "../../../common/utils.ts"; import { addPrefix, shouldBeIgnored, stripAllPrefixes } from "../../../lib/src/string_and_binary/path.ts"; import { $msg } from "../../../lib/src/common/i18n.ts"; import { Semaphore } from "octagonal-wheels/concurrency/semaphore"; @@ -388,7 +388,7 @@ ${stringifyYaml({ const adn = this.plugin.localDatabase.findAllDocs(); for await (const i of adn) { - const path = getPath(i); + const path = this.services.path.getPath(i); if (path.startsWith(ICXHeader)) continue; if (path.startsWith(PSCHeader)) continue; if (!this.plugin.settings.syncInternalFiles && path.startsWith(ICHeader)) continue; diff --git a/src/modules/main/ModuleLiveSyncMain.ts b/src/modules/main/ModuleLiveSyncMain.ts index bc7f95a..84550a5 100644 --- a/src/modules/main/ModuleLiveSyncMain.ts +++ b/src/modules/main/ModuleLiveSyncMain.ts @@ -16,7 +16,7 @@ import { AbstractModule } from "../AbstractModule.ts"; import { EVENT_PLATFORM_UNLOADED } from "@lib/events/coreEvents"; import type { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts"; import type { LiveSyncCore } from "../../main.ts"; -import { initialiseWorkerModule } from "@/lib/src/worker/bgWorker.ts"; +import { initialiseWorkerModule } from "@lib/worker/bgWorker.ts"; export class ModuleLiveSyncMain extends AbstractModule { async _onLiveSyncReady() { diff --git a/src/modules/services/ObsidianPathService.ts b/src/modules/services/ObsidianPathService.ts new file mode 100644 index 0000000..72e5532 --- /dev/null +++ b/src/modules/services/ObsidianPathService.ts @@ -0,0 +1,8 @@ +import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; +import { normalizePath } from "@/deps"; +import { PathService } from "@/lib/src/services/base/PathService"; +export class ObsidianPathService extends PathService { + protected normalizePath(path: string): string { + return normalizePath(path); + } +} diff --git a/src/modules/services/ObsidianServiceHub.ts b/src/modules/services/ObsidianServiceHub.ts index 83465eb..81319eb 100644 --- a/src/modules/services/ObsidianServiceHub.ts +++ b/src/modules/services/ObsidianServiceHub.ts @@ -15,9 +15,9 @@ import { ObsidianTweakValueService, ObsidianTestService, ObsidianDatabaseEventService, - ObsidianPathService, ObsidianConfigService, } from "./ObsidianServices"; +import { ObsidianPathService } from "./ObsidianPathService"; import { ObsidianVaultService } from "./ObsidianVaultService"; import { ObsidianUIService } from "./ObsidianUIService"; @@ -42,7 +42,9 @@ export class ObsidianServiceHub extends InjectableServiceHub {} export class ObsidianDatabaseService extends InjectableDatabaseService { openSimpleStore = handlers().binder("openSimpleStore") as (( kind: string diff --git a/src/modules/services/ObsidianUIService.ts b/src/modules/services/ObsidianUIService.ts index 7c0bd43..37b7230 100644 --- a/src/modules/services/ObsidianUIService.ts +++ b/src/modules/services/ObsidianUIService.ts @@ -5,7 +5,7 @@ import { UIService } from "@lib/services//implements/base/UIService"; import { ObsidianServiceContext } from "@/lib/src/services/implements/obsidian/ObsidianServiceContext"; import { ObsidianSvelteDialogManager } from "./SvelteDialogObsidian"; import { ObsidianConfirm } from "./ObsidianConfirm"; - +import DialogToCopy from "@/lib/src/UI/dialogues/DialogueToCopy.svelte"; export type ObsidianUIServiceDependencies = { appLifecycle: AppLifecycleService; config: ConfigService; @@ -13,6 +13,9 @@ export type ObsidianUIServiceDependencies { + override get dialogToCopy() { + return DialogToCopy; + } constructor(context: ObsidianServiceContext, dependents: ObsidianUIServiceDependencies) { const obsidianConfirm = new ObsidianConfirm(context); const obsidianSvelteDialogManager = new ObsidianSvelteDialogManager(context, { diff --git a/src/modules/services/SvelteDialogObsidian.ts b/src/modules/services/SvelteDialogObsidian.ts index c57d8f1..b40418b 100644 --- a/src/modules/services/SvelteDialogObsidian.ts +++ b/src/modules/services/SvelteDialogObsidian.ts @@ -7,8 +7,8 @@ import { type SvelteDialogManagerDependencies, } from "@lib/services/implements/base/SvelteDialog"; import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext"; - -export const SvelteDialogBase = SvelteDialogMixIn(Modal); +import DialogHost from "@/lib/src/UI/DialogHost.svelte"; +export const SvelteDialogBase = SvelteDialogMixIn(Modal, DialogHost); export class SvelteDialogObsidian< T, U,