mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-04-15 13:38:33 +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,6 +1,6 @@
|
||||
import { TFile, TFolder, type ListedFiles } from "obsidian";
|
||||
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 type {
|
||||
FilePath,
|
||||
@@ -16,10 +16,13 @@ import { StorageEventManagerObsidian, type StorageEventManager } from "./storage
|
||||
import type { StorageAccess } from "../interfaces/StorageAccess";
|
||||
import { createBlob, type CustomRegExp } from "../../lib/src/common/utils";
|
||||
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:";
|
||||
|
||||
export class ModuleFileAccessObsidian extends AbstractObsidianModule implements IObsidianModule, StorageAccess {
|
||||
export class ModuleFileAccessObsidian extends AbstractObsidianModule implements StorageAccess {
|
||||
processingFiles: Set<FilePathWithPrefix> = new Set();
|
||||
processWriteFile<T>(file: UXFileInfoStub | FilePathWithPrefix, proc: () => Promise<T>): Promise<T> {
|
||||
const path = typeof file === "string" ? file : file.path;
|
||||
@@ -49,39 +52,35 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
||||
}
|
||||
vaultAccess!: SerializedFileAccess;
|
||||
vaultManager: StorageEventManager = new StorageEventManagerObsidian(this.plugin, this.core, this);
|
||||
$everyOnload(): Promise<boolean> {
|
||||
private _everyOnload(): Promise<boolean> {
|
||||
this.core.storageAccess = this;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
$everyOnFirstInitialize(): Promise<boolean> {
|
||||
_everyOnFirstInitialize(): Promise<boolean> {
|
||||
this.vaultManager.beginWatch();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
$allOnUnload(): Promise<boolean> {
|
||||
// this.vaultManager.
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
// $$flushFileEventQueue(): void {
|
||||
// this.vaultManager.flushQueue();
|
||||
// }
|
||||
|
||||
$everyCommitPendingFileEvent(): Promise<boolean> {
|
||||
_everyCommitPendingFileEvent(): Promise<boolean> {
|
||||
this.vaultManager.flushQueue();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
$everyOnloadStart(): Promise<boolean> {
|
||||
_everyOnloadStart(): Promise<boolean> {
|
||||
this.vaultAccess = new SerializedFileAccess(this.app, this.plugin, this);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
$$isStorageInsensitive(): boolean {
|
||||
_isStorageInsensitive(): boolean {
|
||||
return this.vaultAccess.isStorageInsensitive();
|
||||
}
|
||||
|
||||
$$shouldCheckCaseInsensitive(): boolean {
|
||||
if (this.$$isStorageInsensitive()) return false;
|
||||
_shouldCheckCaseInsensitive(): boolean {
|
||||
if (this.services.vault.isStorageInsensitive()) return false;
|
||||
return !this.settings.handleFilenameCaseSensitive;
|
||||
}
|
||||
|
||||
@@ -275,7 +274,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
||||
if (excludeFilter && excludeFilter.some((ee) => ee.test(file))) {
|
||||
continue;
|
||||
}
|
||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(file)) continue;
|
||||
if (await this.services.vault.isIgnoredByIgnoreFile(file)) continue;
|
||||
files.push(file);
|
||||
}
|
||||
|
||||
@@ -288,7 +287,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
||||
if (excludeFilter && excludeFilter.some((e) => e.test(v))) {
|
||||
continue;
|
||||
}
|
||||
if (await this.plugin.$$isIgnoredByIgnoreFiles(v)) {
|
||||
if (await this.services.vault.isIgnoredByIgnoreFile(v)) {
|
||||
continue;
|
||||
}
|
||||
// OK, deep dive!
|
||||
@@ -346,7 +345,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
||||
|
||||
async _deleteVaultItem(file: TFile | TFolder) {
|
||||
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;
|
||||
if (this.settings.trashInsteadDelete) {
|
||||
@@ -376,4 +375,16 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
||||
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
|
||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
||||
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
||||
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject } from "../../common/utils.ts";
|
||||
import {
|
||||
@@ -13,12 +13,13 @@ import { Notice } from "../../deps.ts";
|
||||
import type { Confirm } from "../../lib/src/interfaces/Confirm.ts";
|
||||
import { setConfirmInstance } from "../../lib/src/PlatformAPIs/obsidian/Confirm.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.
|
||||
// However, we have to make compatible one for other platform.
|
||||
|
||||
export class ModuleInputUIObsidian extends AbstractObsidianModule implements IObsidianModule, Confirm {
|
||||
$everyOnload(): Promise<boolean> {
|
||||
export class ModuleInputUIObsidian extends AbstractObsidianModule implements Confirm {
|
||||
private _everyOnload(): Promise<boolean> {
|
||||
this.core.confirm = this;
|
||||
setConfirmInstance(this);
|
||||
return Promise.resolve(true);
|
||||
@@ -110,4 +111,8 @@ export class ModuleInputUIObsidian extends AbstractObsidianModule implements IOb
|
||||
): Promise<(typeof buttons)[number] | false> {
|
||||
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_NOTICE,
|
||||
LOG_LEVEL_VERBOSE,
|
||||
type FileEventType,
|
||||
type FilePath,
|
||||
type FilePathWithPrefix,
|
||||
type UXFileInfoStub,
|
||||
type UXInternalFileInfoStub,
|
||||
} from "../../../lib/src/common/types.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 {
|
||||
finishAllWaitingForTimeout,
|
||||
@@ -48,6 +49,9 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
||||
plugin: ObsidianLiveSyncPlugin;
|
||||
core: LiveSyncCore;
|
||||
storageAccess: StorageAccess;
|
||||
get services() {
|
||||
return this.core.services;
|
||||
}
|
||||
|
||||
get shouldBatchSave() {
|
||||
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 it is one of ignore files, refresh the cached one.
|
||||
// (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 {
|
||||
this._watchVaultRawEvents(path);
|
||||
}
|
||||
@@ -209,7 +213,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
||||
async appendQueue(params: FileEvent[], ctx?: any) {
|
||||
if (!this.core.settings.isConfigured) return;
|
||||
if (this.core.settings.suspendFileWatching) return;
|
||||
this.core.$$markFileListPossiblyChanged();
|
||||
this.core.services.vault.markFileListPossiblyChanged();
|
||||
// Flag up to be reload
|
||||
const processFiles = new Set<FilePath>();
|
||||
for (const param of params) {
|
||||
@@ -222,7 +226,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
||||
const oldPath = param.oldPath;
|
||||
if (type !== "INTERNAL") {
|
||||
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(
|
||||
`The storage file has been changed but exceeds the maximum size. Skipping: ${param.file.path}`,
|
||||
LOG_LEVEL_NOTICE
|
||||
@@ -234,7 +238,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
||||
// TODO: Confirm why only the TFolder skipping
|
||||
// Possibly following line is needed...
|
||||
// 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;
|
||||
// let cache: null | string | ArrayBuffer;
|
||||
@@ -411,12 +415,12 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
||||
const lockKey = `handleFile:${file.path}`;
|
||||
return await serialized(lockKey, async () => {
|
||||
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 {
|
||||
const key = `file-last-proc-${queue.type}-${file.path}`;
|
||||
const last = Number((await this.core.kvDB.get(key)) || 0);
|
||||
if (queue.type == "DELETE") {
|
||||
await this.core.$anyHandlerProcessesFileEvent(queue);
|
||||
await this.core.services.fileProcessing.processFileEvent(queue);
|
||||
} else {
|
||||
if (file.stat.mtime == last) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
if (!(await this.core.$anyHandlerProcessesFileEvent(queue))) {
|
||||
if (!(await this.core.services.fileProcessing.processFileEvent(queue))) {
|
||||
Logger(
|
||||
`STORAGE -> DB: Handler failed, cancel the relative operations: ${file.path}`,
|
||||
LOG_LEVEL_INFO
|
||||
|
||||
Reference in New Issue
Block a user