Rewritten

-   Hidden File Sync is now respects the file changes on the storage. Not simply comparing modified times.
    -   This makes hidden file sync more robust and reliable.

Fixed

-   `Scan hidden files before replication` is now configurable again.
-   Some unexpected errors are now handled more gracefully.
-   Meaningless event passing during boot sequence is now prevented.
-   Error handling for non-existing files has been fixed.
-   Hidden files will not be batched to avoid the potential error.
    -   This behaviour had been causing the error in the previous versions in specific situations.
-   The log which checking automatic conflict resolution is now in verbose level.
-   Replication log (skipping non-targetting files) shows the correct information.
-   The dialogue that asking enabling optional feature during `Rebuild Everything` now prevents to show the `overwrite` option.
    -   The rebuilding device is the first, meaningless.
-   Files with different modified time but identical content are no longer processed repeatedly.
-   Some unexpected errors which caused after terminating plug-in are now avoided.
-

Improved

-   JSON files are now more transferred efficiently.
    -   Now the JSON files are transferred in more fine chunks, which makes the transfer more efficient.
This commit is contained in:
vorotamoroz
2024-11-21 11:40:15 +00:00
parent ed5cb3e043
commit 9d304b3233
19 changed files with 1659 additions and 831 deletions

View File

@@ -1,6 +1,11 @@
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import { EVENT_FILE_SAVED, eventHub } from "../../common/events";
import { getPathFromUXFileInfo, isInternalMetadata, markChangesAreSame } from "../../common/utils";
import {
getDatabasePathFromUXFileInfo,
getStoragePathFromUXFileInfo,
isInternalMetadata,
markChangesAreSame,
} from "../../common/utils";
import type {
UXFileInfoStub,
FilePathWithPrefix,
@@ -9,10 +14,11 @@ import type {
LoadedEntry,
FilePath,
SavingEntry,
DocumentID,
} from "../../lib/src/common/types";
import type { DatabaseFileAccess } from "../interfaces/DatabaseFileAccess";
import { type IObsidianModule } from "../AbstractObsidianModule.ts";
import { isPlainText, shouldBeIgnored } from "../../lib/src/string_and_binary/path";
import { isPlainText, shouldBeIgnored, stripAllPrefixes } from "../../lib/src/string_and_binary/path";
import {
createBlob,
createTextBlob,
@@ -23,6 +29,7 @@ import {
} from "../../lib/src/common/utils";
import { serialized } from "octagonal-wheels/concurrency/lock";
import { AbstractModule } from "../AbstractModule.ts";
import { ICHeader } from "../../common/types.ts";
export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidianModule, DatabaseFileAccess {
$everyOnload(): Promise<boolean> {
@@ -67,7 +74,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
}
async checkIsTargetFile(file: UXFileInfoStub | FilePathWithPrefix): Promise<boolean> {
const path = getPathFromUXFileInfo(file);
const path = getStoragePathFromUXFileInfo(file);
if (!(await this.core.$$isTargetFile(path))) {
this._log(`File is not target`, LOG_LEVEL_VERBOSE);
return false;
@@ -83,7 +90,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
if (!(await this.checkIsTargetFile(file))) {
return true;
}
const fullPath = getPathFromUXFileInfo(file);
const fullPath = getDatabasePathFromUXFileInfo(file);
try {
this._log(`deleteDB By path:${fullPath}`);
return await this.deleteFromDBbyPath(fullPath, rev);
@@ -104,6 +111,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
async storeContent(path: FilePathWithPrefix, content: string): Promise<boolean> {
const blob = createTextBlob(content);
const bytes = (await blob.arrayBuffer()).byteLength;
const isInternal = path.startsWith(".") ? true : undefined;
const dummyUXFileInfo: UXFileInfo = {
name: path.split("/").pop() as string,
path: path,
@@ -114,6 +122,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
type: "file",
},
body: blob,
isInternal,
};
return await this._store(dummyUXFileInfo, true, false, false);
}
@@ -133,18 +142,47 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
this._log("File seems bad", LOG_LEVEL_VERBOSE);
return false;
}
const path = getPathFromUXFileInfo(file);
// const path = getPathFromUXFileInfo(file);
const isPlain = isPlainText(file.name);
const possiblyLarge = !isPlain;
const content = file.body;
if (possiblyLarge) this._log(`Processing: ${path}`, LOG_LEVEL_VERBOSE);
const datatype = determineTypeFromBlob(content);
const fullPath = file.path;
const id = await this.core.$$path2id(fullPath);
const idPrefix = file.isInternal ? ICHeader : "";
const fullPath = getStoragePathFromUXFileInfo(file);
const fullPathOnDB = getDatabasePathFromUXFileInfo(file);
if (possiblyLarge) this._log(`Processing: ${fullPath}`, LOG_LEVEL_VERBOSE);
// if (isInternalMetadata(fullPath)) {
// this._log(`Internal file: ${fullPath}`, LOG_LEVEL_VERBOSE);
// return false;
// }
if (file.isInternal) {
if (file.deleted) {
file.stat = {
size: 0,
ctime: Date.now(),
mtime: Date.now(),
type: "file",
};
} else if (file.stat == undefined) {
const stat = await this.core.storageAccess.statHidden(file.path);
if (!stat) {
// We stored actually deleted or not since here, so this is an unexpected case. we should raise an error.
this._log(`Internal file not found: ${fullPath}`, LOG_LEVEL_VERBOSE);
return false;
}
file.stat = stat;
}
}
const idMain = await this.core.$$path2id(fullPath);
const id = (idPrefix + idMain) as DocumentID;
const d: SavingEntry = {
_id: id,
path: file.path,
path: fullPathOnDB,
data: content,
ctime: file.stat.ctime,
mtime: file.stat.mtime,
@@ -166,7 +204,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
// return true;
// }
try {
const old = await this.localDatabase.getDBEntry(fullPath, undefined, false, true, false);
const old = await this.localDatabase.getDBEntry(d.path, undefined, false, true, false);
if (old !== false) {
const oldData = { data: old.data, deleted: old._deleted || old.deleted };
const newData = { data: d.data, deleted: d._deleted || d.deleted };
@@ -181,24 +219,14 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
// d._rev = old._rev;
}
} catch (ex) {
if (force) {
this._log(
msg +
"Error, Could not check the diff for the old one." +
(force ? "force writing." : "") +
fullPath +
(d._deleted || d.deleted ? " (deleted)" : ""),
LOG_LEVEL_VERBOSE
);
} else {
this._log(
msg +
"Error, Could not check the diff for the old one." +
fullPath +
(d._deleted || d.deleted ? " (deleted)" : ""),
LOG_LEVEL_VERBOSE
);
}
this._log(
msg +
"Error, Could not check the diff for the old one." +
(force ? "force writing." : "") +
fullPath +
(d._deleted || d.deleted ? " (deleted)" : ""),
LOG_LEVEL_VERBOSE
);
this._log(ex, LOG_LEVEL_VERBOSE);
return !force;
}
@@ -220,7 +248,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
if (!(await this.checkIsTargetFile(file))) {
return [];
}
const filename = getPathFromUXFileInfo(file);
const filename = getDatabasePathFromUXFileInfo(file);
const doc = await this.localDatabase.getDBEntryMeta(filename, { conflicts: true }, true);
if (doc === false) {
return [];
@@ -243,9 +271,10 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
return false;
}
const data = createBlob(readContent(entry));
const path = stripAllPrefixes(entry.path);
const fileInfo: UXFileInfo = {
name: entry.path.split("/").pop() as string,
path: entry.path,
name: path.split("/").pop() as string,
path: path,
stat: {
size: entry.size,
ctime: entry.ctime,
@@ -265,12 +294,12 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements IObsidia
rev?: string,
skipCheck = false
): Promise<MetaEntry | false> {
const filename = getPathFromUXFileInfo(file);
const dbFileName = getDatabasePathFromUXFileInfo(file);
if (skipCheck && !(await this.checkIsTargetFile(file))) {
return false;
}
const doc = await this.localDatabase.getDBEntryMeta(filename, rev ? { rev: rev } : undefined, true);
const doc = await this.localDatabase.getDBEntryMeta(dbFileName, rev ? { rev: rev } : undefined, true);
if (doc === false) {
return false;
}

View File

@@ -14,8 +14,8 @@ import {
compareFileFreshness,
EVEN,
getPath,
getPathFromUXFileInfo,
getPathWithoutPrefix,
getStoragePathFromUXFileInfo,
markChangesAreSame,
} from "../../common/utils";
import { getDocDataAsArray, isDocContentSame, readContent } from "../../lib/src/common/utils";
@@ -94,11 +94,9 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
if (!shouldApplied) {
readFile = await this.readFileFromStub(file);
if (await isDocContentSame(getDocDataAsArray(entry.data), readFile.body)) {
if (shouldApplied) {
// Timestamp is different but the content is same. therefore, two timestamps should be handled as same.
// So, mark the changes are same.
markChangesAreSame(file, file.stat.mtime, entry.mtime);
}
// Timestamp is different but the content is same. therefore, two timestamps should be handled as same.
// So, mark the changes are same.
markChangesAreSame(file, file.stat.mtime, entry.mtime);
} else {
shouldApplied = true;
}
@@ -170,18 +168,13 @@ export class ModuleFileHandler extends AbstractModule implements ICoreModule {
info: UXFileInfoStub | FilePath,
rev: string
): Promise<boolean | undefined> {
const path = getStoragePathFromUXFileInfo(info);
if (!(await this.deleteRevisionFromDB(info, rev))) {
this._log(
`Failed to delete the conflicted revision ${rev} of ${getPathFromUXFileInfo(info)}`,
LOG_LEVEL_VERBOSE
);
this._log(`Failed to delete the conflicted revision ${rev} of ${path}`, LOG_LEVEL_VERBOSE);
return false;
}
if (!(await this.dbToStorageWithSpecificRev(info, rev, true))) {
this._log(
`Failed to apply the resolved revision ${rev} of ${getPathFromUXFileInfo(info)} to the storage`,
LOG_LEVEL_VERBOSE
);
this._log(`Failed to apply the resolved revision ${rev} of ${path} to the storage`, LOG_LEVEL_VERBOSE);
return false;
}
}

View File

@@ -77,7 +77,8 @@ export class ModuleRebuilder extends AbstractModule implements ICoreModule, Rebu
await this.core.$$tryResetRemoteDatabase();
await this.core.$$markRemoteLocked();
await delay(500);
await this.askUsingOptionalFeature({ enableOverwrite: true });
// We do not have any other devices' data, so we do not need to ask for overwriting.
await this.askUsingOptionalFeature({ enableOverwrite: false });
await delay(1000);
await this.core.$$replicateAllToServer(true);
await delay(1000);

View File

@@ -329,7 +329,7 @@ Or if you are sure know what had been happened, we can unlock the database from
} else if (isValidPath(getPath(doc))) {
this.storageApplyingProcessor.enqueue(doc as MetaEntry);
} else {
Logger(`Skipped: ${doc._id.substring(0, 8)}`, LOG_LEVEL_VERBOSE);
Logger(`Skipped: ${path} (${doc._id.substring(0, 8)})`, LOG_LEVEL_VERBOSE);
}
return;
},

View File

@@ -1,6 +1,6 @@
import { LRUCache } from "octagonal-wheels/memory/LRUCache";
import {
getPathFromUXFileInfo,
getStoragePathFromUXFileInfo,
id2path,
isInternalMetadata,
path2id,
@@ -16,7 +16,7 @@ import {
type ObsidianLiveSyncSettings,
type UXFileInfoStub,
} from "../../lib/src/common/types";
import { addPrefix, isAcceptedAll, stripAllPrefixes } from "../../lib/src/string_and_binary/path";
import { addPrefix, isAcceptedAll } from "../../lib/src/string_and_binary/path";
import { AbstractModule } from "../AbstractModule";
import type { ICoreModule } from "../ModuleTypes";
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
@@ -107,14 +107,14 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
}
);
const filepath = getPathFromUXFileInfo(file);
const filepath = getStoragePathFromUXFileInfo(file);
const lc = filepath.toLowerCase();
if (this.core.$$shouldCheckCaseInsensitive()) {
if (lc in fileCount && fileCount[lc] > 1) {
return false;
}
}
const fileNameLC = getPathFromUXFileInfo(file).split("/").pop()?.toLowerCase();
const fileNameLC = getStoragePathFromUXFileInfo(file).split("/").pop()?.toLowerCase();
if (this.settings.useIgnoreFiles) {
if (this.ignoreFiles.some((e) => e.toLowerCase() == fileNameLC)) {
// We must reload ignore files due to the its change.
@@ -154,16 +154,12 @@ export class ModuleTargetFilter extends AbstractModule implements ICoreModule {
if (!this.settings.useIgnoreFiles) {
return false;
}
const filepath = getPathFromUXFileInfo(file);
const filepath = getStoragePathFromUXFileInfo(file);
if (this.ignoreFileCache.has(filepath)) {
// Renew
await this.readIgnoreFile(filepath);
}
if (
!(await isAcceptedAll(stripAllPrefixes(filepath), this.ignoreFiles, (filename) =>
this.getIgnoreFile(filename)
))
) {
if (!(await isAcceptedAll(filepath, this.ignoreFiles, (filename) => this.getIgnoreFile(filename)))) {
return true;
}
return false;

View File

@@ -5,6 +5,7 @@ import {
CANCELLED,
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
MISSING_OR_ERROR,
NOT_CONFLICTED,
type diff_check_result,
@@ -114,7 +115,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
conflictCheckResult === CANCELLED
) {
// nothing to do.
this._log(`conflict:Nothing to do:${filename}`);
this._log(`[conflict] Not conflicted or cancelled: ${filename}`, LOG_LEVEL_VERBOSE);
return;
}
if (conflictCheckResult === AUTO_MERGED) {
@@ -123,7 +124,7 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
//Wait for the running replication, if not running replication, run it once.
await this.core.$$waitForReplicationOnce();
}
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);
return;
}
@@ -131,13 +132,13 @@ export class ModuleConflictResolver extends AbstractModule implements ICoreModul
const af = this.core.$$getActiveFilePath();
if (af && af != filename) {
this._log(
`${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.`,
LOG_LEVEL_NOTICE
);
return;
}
}
this._log("conflict:Manual merge required!");
this._log("[conflict] Manual merge required!");
await this.core.$anyResolveConflictByUI(filename, conflictCheckResult);
});
}

View File

@@ -120,12 +120,12 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
}
}
statHidden(path: string): Promise<UXStat | null> {
return this.vaultAccess.adapterStat(path);
return this.vaultAccess.tryAdapterStat(path);
}
async removeHidden(path: string): Promise<boolean> {
try {
await this.vaultAccess.adapterRemove(path);
if (this.vaultAccess.adapterStat(path) !== null) {
if (this.vaultAccess.tryAdapterStat(path) !== null) {
return false;
}
return true;
@@ -145,7 +145,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
return await this.vaultAccess.adapterReadBinary(path);
}
async isExistsIncludeHidden(path: string): Promise<boolean> {
return (await this.vaultAccess.adapterStat(path)) !== null;
return (await this.vaultAccess.tryAdapterStat(path)) !== null;
}
async ensureDir(path: string): Promise<boolean> {
try {

View File

@@ -42,6 +42,13 @@ export class SerializedFileAccess {
this.plugin = plugin;
}
async tryAdapterStat(file: TFile | string) {
const path = file instanceof TFile ? file.path : file;
return await processReadFile(file, async () => {
if (!(await this.app.vault.adapter.exists(path))) return null;
return this.app.vault.adapter.stat(path);
});
}
async adapterStat(file: TFile | string) {
const path = file instanceof TFile ? file.path : file;
return await processReadFile(file, () => this.app.vault.adapter.stat(path));

View File

@@ -171,11 +171,13 @@ export class StorageEventManagerObsidian extends StorageEventManager {
// Folder
return;
}
void this.appendQueue(
[
{
type: "INTERNAL",
file: InternalFileToUXFileInfoStub(path),
skipBatchWait: true, // Internal files should be processed immediately.
},
],
null
@@ -212,11 +214,14 @@ export class StorageEventManagerObsidian extends StorageEventManager {
// Stop cache using to prevent the corruption;
// let cache: null | string | ArrayBuffer;
// new file or something changed, cache the changes.
if (file instanceof TFile && (type == "CREATE" || type == "CHANGED")) {
// Wait for a bit while to let the writer has marked `touched` at the file.
await delay(10);
if (this.core.storageAccess.recentlyTouched(file)) {
continue;
// if (file instanceof TFile && (type == "CREATE" || type == "CHANGED")) {
if (file instanceof TFile || !file.isFolder) {
if (type == "CREATE" || type == "CHANGED") {
// Wait for a bit while to let the writer has marked `touched` at the file.
await delay(10);
if (this.core.storageAccess.recentlyTouched(file.path)) {
continue;
}
}
}
@@ -380,13 +385,11 @@ export class StorageEventManagerObsidian extends StorageEventManager {
const file = queue.args.file;
const lockKey = `handleFile:${file.path}`;
return await serialized(lockKey, async () => {
// TODO CHECK
const key = `file-last-proc-${queue.type}-${file.path}`;
const last = Number((await this.core.kvDB.get(key)) || 0);
if (queue.type == "INTERNAL" || file.isInternal) {
await this.core.$anyProcessOptionalFileEvent(file.path as unknown as FilePath);
} else {
// let mtime = file.stat.mtime;
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);
} else {

View File

@@ -55,7 +55,7 @@ export async function InternalFileToUXFileInfo(
prefix: string = ICHeader
): Promise<UXFileInfo> {
const name = fullPath.split("/").pop() as string;
const stat = await vaultAccess.adapterStat(fullPath);
const stat = await vaultAccess.tryAdapterStat(fullPath);
if (stat == null) throw new Error(`File not found: ${fullPath}`);
if (stat.type == "folder") throw new Error(`File not found: ${fullPath}`);
const file = await vaultAccess.adapterReadAuto(fullPath);

View File

@@ -238,10 +238,10 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
if (!this.core.$$isFileSizeExceeded(file.stat.size) && !this.core.$$isFileSizeExceeded(doc.size)) {
await this.syncFileBetweenDBandStorage(file, doc);
// fireAndForget(() => this.checkAndApplySettingFromMarkdown(getPath(doc), true));
eventHub.emitEvent("event-file-changed", {
file: getPath(doc),
automated: true,
});
// eventHub.emitEvent("event-file-changed", {
// file: getPath(doc),
// automated: true,
// });
} else {
this._log(
`SYNC DATABASE AND STORAGE: ${getPath(doc)} has been skipped due to file size exceeding the limit`,
@@ -282,10 +282,6 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
if (!this.core.$$isFileSizeExceeded(file.stat.size)) {
this._log("STORAGE -> DB :" + file.path);
await this.core.fileHandler.storeFileToDB(file);
eventHub.emitEvent("event-file-changed", {
file: file.path,
automated: true,
});
} else {
this._log(
`STORAGE -> DB : ${file.path} has been skipped due to file size exceeding the limit`,
@@ -296,7 +292,12 @@ export class ModuleInitializerFile extends AbstractModule implements ICoreModule
case TARGET_IS_NEW:
if (!this.core.$$isFileSizeExceeded(doc.size)) {
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", {
file: file.path,
automated: true,
});
} else {
this._log(`STORAGE <- DB : Cloud not read ${file.path}, possibly deleted`, LOG_LEVEL_NOTICE);
}
return caches;

View File

@@ -12,31 +12,34 @@ export class ModuleDev extends AbstractObsidianModule implements IObsidianModule
__onMissingTranslation(() => {});
return Promise.resolve(true);
}
async onMissingTranslation(key: string): Promise<void> {
const now = new Date();
const filename = `missing-translation-`;
const time = now.toISOString().split("T")[0];
const outFile = `${filename}${time}.jsonl`;
const piece = JSON.stringify({
[key]: {},
});
const writePiece = piece.substring(1, piece.length - 1) + ",";
try {
await this.core.storageAccess.ensureDir(this.app.vault.configDir + "/ls-debug/");
await this.core.storageAccess.appendHiddenFile(
this.app.vault.configDir + "/ls-debug/" + outFile,
writePiece + "\n"
);
} catch (ex) {
this._log(`Could not write ${outFile}`, LOG_LEVEL_VERBOSE);
this._log(`Missing translation: ${writePiece}`, LOG_LEVEL_VERBOSE);
this._log(ex, LOG_LEVEL_VERBOSE);
}
}
$everyOnloadAfterLoadSettings(): Promise<boolean> {
if (!this.settings.enableDebugTools) return Promise.resolve(true);
// eslint-disable-next-line no-unused-labels
this.onMissingTranslation = this.onMissingTranslation.bind(this);
__onMissingTranslation((key) => {
const now = new Date();
const filename = `missing-translation-`;
const time = now.toISOString().split("T")[0];
const outFile = `${filename}${time}.jsonl`;
const piece = JSON.stringify({
[key]: {},
});
const writePiece = piece.substring(1, piece.length - 1) + ",";
fireAndForget(async () => {
try {
await this.core.storageAccess.ensureDir(this.app.vault.configDir + "/ls-debug/");
await this.core.storageAccess.appendHiddenFile(
this.app.vault.configDir + "/ls-debug/" + outFile,
writePiece + "\n"
);
} catch (ex) {
this._log(`Could not write ${outFile}`, LOG_LEVEL_VERBOSE);
this._log(`Missing translation: ${writePiece}`, LOG_LEVEL_VERBOSE);
this._log(ex, LOG_LEVEL_VERBOSE);
}
});
void this.onMissingTranslation(key);
});
type STUB = {
toc: Set<string>;

View File

@@ -46,6 +46,8 @@ const recentLogProcessor = new QueueProcessor(
).resumePipeLine();
// logStore.intercept(e => e.slice(Math.min(e.length - 200, 0)));
const showDebugLog = false;
export const MARK_DONE = "\u{2009}\u{2009}";
export class ModuleLog extends AbstractObsidianModule implements IObsidianModule {
registerView = this.plugin.registerView.bind(this.plugin);
@@ -89,7 +91,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
const labelChunkCount = padLeftSpComputed(collectingChunks, `🧩`);
const labelPluginScanCount = padLeftSpComputed(pluginScanningCount, `🔌`);
const labelConflictProcessCount = padLeftSpComputed(this.core.conflictProcessQueueCount, `🔩`);
const hiddenFilesCount = reactive(() => hiddenFilesEventCount.value + hiddenFilesProcessingCount.value);
const hiddenFilesCount = reactive(() => hiddenFilesEventCount.value - hiddenFilesProcessingCount.value);
const labelHiddenFilesCount = padLeftSpComputed(hiddenFilesCount, `⚙️`);
const queueCountLabelX = reactive(() => {
return `${labelReplication()}${labelDBCount()}${labelStorageCount()}${labelChunkCount()}${labelPluginScanCount()}${labelHiddenFilesCount()}${labelConflictProcessCount()}`;
@@ -355,7 +357,7 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
);
}
$$addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
if (level == LOG_LEVEL_DEBUG) {
if (level == LOG_LEVEL_DEBUG && !showDebugLog) {
return;
}
if (level < LOG_LEVEL_INFO && this.settings && this.settings.lessInformationInLog) {
@@ -412,15 +414,17 @@ export class ModuleLog extends AbstractObsidianModule implements IObsidianModule
};
}
const timeout = 5000;
scheduleTask(`notify-${key}`, timeout, () => {
const notify = this.notifies[key].notice;
delete this.notifies[key];
try {
notify.hide();
} catch {
// NO OP
}
});
if (!key.startsWith("keepalive-") || messageContent.indexOf(MARK_DONE) !== -1) {
scheduleTask(`notify-${key}`, timeout, () => {
const notify = this.notifies[key].notice;
delete this.notifies[key];
try {
notify.hide();
} catch {
// NO OP
}
});
}
}
}
}

View File

@@ -1905,7 +1905,7 @@ However, your report is needed to stabilise this. I appreciate you for your grea
}
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("syncInternalFilesBeforeReplication", {
onUpdate: visibleOnly(() => this.isConfiguredAs("watchInternalFileChanges", false)),
onUpdate: visibleOnly(() => this.isConfiguredAs("watchInternalFileChanges", true)),
});
new Setting(paneEl).setClass("wizardHidden").autoWireNumeric("syncInternalFilesInterval", {