mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-03-06 18:08:48 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a75d41cbb | ||
|
|
5252cc0372 | ||
|
|
5022155317 | ||
|
|
d36f925c65 | ||
|
|
3ae33e0500 | ||
|
|
13e442a0c7 |
@@ -12,10 +12,10 @@ max_document_size = 50000000
|
||||
|
||||
[chttpd]
|
||||
require_valid_user = true
|
||||
max_http_request_size = 4294967296
|
||||
|
||||
[chttpd_auth]
|
||||
require_valid_user = true
|
||||
max_http_request_size = 4294967296
|
||||
authentication_redirect = /_utils/session.html
|
||||
|
||||
[httpd]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-livesync",
|
||||
"name": "Self-hosted LiveSync",
|
||||
"version": "0.19.10",
|
||||
"version": "0.19.12",
|
||||
"minAppVersion": "0.9.12",
|
||||
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"author": "vorotamoroz",
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,17 +1,18 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.19.10",
|
||||
"version": "0.19.12",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.19.10",
|
||||
"version": "0.19.12",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"idb": "^7.1.1",
|
||||
"xxhash-wasm": "^0.4.2"
|
||||
"xxhash-wasm": "^0.4.2",
|
||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/svelte": "^4.0.1",
|
||||
@@ -4076,6 +4077,12 @@
|
||||
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
|
||||
"integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA=="
|
||||
},
|
||||
"node_modules/xxhash-wasm-102": {
|
||||
"name": "xxhash-wasm",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz",
|
||||
"integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A=="
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
@@ -7032,6 +7039,11 @@
|
||||
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
|
||||
"integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA=="
|
||||
},
|
||||
"xxhash-wasm-102": {
|
||||
"version": "npm:xxhash-wasm@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz",
|
||||
"integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.19.10",
|
||||
"version": "0.19.12",
|
||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"main": "main.js",
|
||||
"type": "module",
|
||||
@@ -47,6 +47,7 @@
|
||||
"dependencies": {
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"idb": "^7.1.1",
|
||||
"xxhash-wasm": "^0.4.2"
|
||||
"xxhash-wasm": "^0.4.2",
|
||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "./types";
|
||||
import { Parallels, delay, getDocData } from "./lib/src/utils";
|
||||
import { Logger } from "./lib/src/logger";
|
||||
import { WrappedNotice } from "./lib/src/wrapper";
|
||||
import { base64ToArrayBuffer, arrayBufferToBase64, readString, uint8ArrayToHexString } from "./lib/src/strbin";
|
||||
import { base64ToArrayBuffer, arrayBufferToBase64, readString, crc32CKHash } from "./lib/src/strbin";
|
||||
import { runWithLock } from "./lib/src/lock";
|
||||
import { LiveSyncCommands } from "./LiveSyncCommands";
|
||||
import { stripAllPrefixes } from "./lib/src/path";
|
||||
import { PeriodicProcessor, askYesNo, disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask } from "./utils";
|
||||
import { PluginDialogModal } from "./dialogs";
|
||||
import { JsonResolveModal } from "./JsonResolveModal";
|
||||
import { pipeGeneratorToGenerator, processAllGeneratorTasksWithConcurrencyLimit } from './lib/src/task';
|
||||
|
||||
|
||||
function serialize<T>(obj: T): string {
|
||||
@@ -35,14 +36,6 @@ function deserialize<T>(str: string, def: T) {
|
||||
export const pluginList = writable([] as PluginDataExDisplay[]);
|
||||
export const pluginIsEnumerating = writable(false);
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const hashString = (async (key: string) => {
|
||||
// const buff = writeString(key);
|
||||
const buff = encoder.encode(key);
|
||||
const digest = await crypto.subtle.digest('SHA-256', buff);
|
||||
return uint8ArrayToHexString(new Uint8Array(digest));
|
||||
})
|
||||
|
||||
export type PluginDataExFile = {
|
||||
filename: string,
|
||||
data?: string[],
|
||||
@@ -181,63 +174,60 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
}
|
||||
scheduleTask("update-plugin-list-task", 200, async () => {
|
||||
await runWithLock("update-plugin-list", false, async () => {
|
||||
const entries = [] as PluginDataExDisplay[]
|
||||
const plugins = this.localDatabase.findEntries(ICXHeader + "", `${ICXHeader}\u{10ffff}`, { include_docs: true });
|
||||
const para = Parallels();
|
||||
let count = 0;
|
||||
pluginIsEnumerating.set(true);
|
||||
let processed = false;
|
||||
try {
|
||||
for await (const plugin of plugins) {
|
||||
const updatedDocumentId = updatedDocumentPath ? await this.path2id(updatedDocumentPath) : "";
|
||||
const plugins = updatedDocumentPath ?
|
||||
this.localDatabase.findEntries(updatedDocumentId, updatedDocumentId + "\u{10ffff}", { include_docs: true, key: updatedDocumentId, limit: 1 }) :
|
||||
this.localDatabase.findEntries(ICXHeader + "", `${ICXHeader}\u{10ffff}`, { include_docs: true });
|
||||
let count = 0;
|
||||
pluginIsEnumerating.set(true);
|
||||
for await (const v of processAllGeneratorTasksWithConcurrencyLimit(20, pipeGeneratorToGenerator(plugins, async plugin => {
|
||||
const path = plugin.path || this.getPath(plugin);
|
||||
if (updatedDocumentPath && updatedDocumentPath != path) {
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
processed = true;
|
||||
const oldEntry = (this.pluginList.find(e => e.documentPath == path));
|
||||
if (oldEntry && oldEntry.mtime == plugin.mtime) continue;
|
||||
await para.wait(15);
|
||||
para.add((async (v) => {
|
||||
try {
|
||||
count++;
|
||||
if (count % 10 == 0) Logger(`Enumerating files... ${count}`, logLevel, "get-plugins");
|
||||
Logger(`plugin-${path}`, LOG_LEVEL.VERBOSE);
|
||||
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
||||
if (wx) {
|
||||
const data = deserialize(getDocData(wx.data), {}) as PluginDataEx;
|
||||
const xFiles = [] as PluginDataExFile[];
|
||||
for (const file of data.files) {
|
||||
const work = { ...file };
|
||||
const tempStr = getDocData(work.data);
|
||||
work.data = [await hashString(tempStr)];
|
||||
xFiles.push(work);
|
||||
}
|
||||
entries.push({
|
||||
...data,
|
||||
documentPath: this.getPath(wx),
|
||||
files: xFiles
|
||||
});
|
||||
if (oldEntry && oldEntry.mtime == plugin.mtime) return false;
|
||||
try {
|
||||
count++;
|
||||
if (count % 10 == 0) Logger(`Enumerating files... ${count}`, logLevel, "get-plugins");
|
||||
Logger(`plugin-${path}`, LOG_LEVEL.VERBOSE);
|
||||
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
||||
if (wx) {
|
||||
const data = deserialize(getDocData(wx.data), {}) as PluginDataEx;
|
||||
const xFiles = [] as PluginDataExFile[];
|
||||
for (const file of data.files) {
|
||||
const work = { ...file };
|
||||
const tempStr = getDocData(work.data);
|
||||
work.data = [crc32CKHash(tempStr)];
|
||||
xFiles.push(work);
|
||||
}
|
||||
} catch (ex) {
|
||||
//TODO
|
||||
Logger(`Something happened at enumerating customization :${v.path}`, LOG_LEVEL.NOTICE);
|
||||
console.warn(ex);
|
||||
return ({
|
||||
...data,
|
||||
documentPath: this.getPath(wx),
|
||||
files: xFiles
|
||||
});
|
||||
}
|
||||
// return entries;
|
||||
} catch (ex) {
|
||||
//TODO
|
||||
Logger(`Something happened at enumerating customization :${path}`, LOG_LEVEL.NOTICE);
|
||||
console.warn(ex);
|
||||
}
|
||||
return false;
|
||||
}))) {
|
||||
if ("ok" in v) {
|
||||
if (v.ok != false) {
|
||||
let newList = [...this.pluginList];
|
||||
const item = v.ok;
|
||||
newList = newList.filter(x => x.documentPath != item.documentPath);
|
||||
newList.push(item)
|
||||
if (updatedDocumentPath != "") newList = newList.filter(e => e.documentPath != updatedDocumentPath);
|
||||
this.pluginList = newList;
|
||||
pluginList.set(newList);
|
||||
}
|
||||
}
|
||||
)(plugin));
|
||||
}
|
||||
await para.all();
|
||||
let newList = [...this.pluginList];
|
||||
for (const item of entries) {
|
||||
newList = newList.filter(x => x.documentPath != item.documentPath);
|
||||
newList.push(item)
|
||||
}
|
||||
if (updatedDocumentPath != "" && !processed) newList = newList.filter(e => e.documentPath != updatedDocumentPath);
|
||||
|
||||
this.pluginList = newList;
|
||||
pluginList.set(newList);
|
||||
|
||||
|
||||
Logger(`All files enumerated`, logLevel, "get-plugins");
|
||||
} finally {
|
||||
pluginIsEnumerating.set(false);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Notice, normalizePath, PluginManifest } from "./deps";
|
||||
import { EntryDoc, LoadedEntry, LOG_LEVEL, InternalFileEntry, FilePathWithPrefix, FilePath } from "./lib/src/types";
|
||||
import { InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
||||
import { Notice, normalizePath, type PluginManifest } from "./deps";
|
||||
import { type EntryDoc, type LoadedEntry, LOG_LEVEL, type InternalFileEntry, type FilePathWithPrefix, type FilePath } from "./lib/src/types";
|
||||
import { type InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
||||
import { Parallels, delay, isDocContentSame } from "./lib/src/utils";
|
||||
import { Logger } from "./lib/src/logger";
|
||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { TFile, Modal, App } from "./deps";
|
||||
import { TFile, Modal, App, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "./deps";
|
||||
import { getPathFromTFile, isValidPath } from "./utils";
|
||||
import { base64ToArrayBuffer, base64ToString, escapeStringToHTML } from "./lib/src/strbin";
|
||||
import ObsidianLiveSyncPlugin from "./main";
|
||||
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||
import { type DocumentID, type FilePathWithPrefix, type LoadedEntry, LOG_LEVEL } from "./lib/src/types";
|
||||
import { Logger } from "./lib/src/logger";
|
||||
import { isErrorOfMissingDoc } from "./lib/src/utils_couchdb";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import type { AnyEntry, FilePathWithPrefix } from "./lib/src/types";
|
||||
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
||||
import { diff_match_patch } from "diff-match-patch";
|
||||
import { diff_match_patch } from "./deps";
|
||||
import { DocumentHistoryModal } from "./DocumentHistoryModal";
|
||||
import { isPlainText, stripAllPrefixes } from "./lib/src/path";
|
||||
import { TFile } from "./deps";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { type Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||
import { type Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "./deps";
|
||||
import type { FilePath, LoadedEntry } from "./lib/src/types";
|
||||
import { base64ToString } from "./lib/src/strbin";
|
||||
import { getDocData } from "./lib/src/utils";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { App, PluginSettingTab, Setting, sanitizeHTMLToDom, TextAreaComponent, MarkdownRenderer, stringifyYaml } from "./deps";
|
||||
import { DEFAULT_SETTINGS, LOG_LEVEL, type ObsidianLiveSyncSettings, type ConfigPassphraseStore, type RemoteDBSettings, type FilePathWithPrefix, type DocumentID } from "./lib/src/types";
|
||||
import { DEFAULT_SETTINGS, LOG_LEVEL, type ObsidianLiveSyncSettings, type ConfigPassphraseStore, type RemoteDBSettings, type FilePathWithPrefix, type HashAlgorithm, type DocumentID } from "./lib/src/types";
|
||||
import { delay } from "./lib/src/utils";
|
||||
import { Semaphore } from "./lib/src/semaphore";
|
||||
import { versionNumberString2Number } from "./lib/src/strbin";
|
||||
@@ -7,8 +7,7 @@ import { Logger } from "./lib/src/logger";
|
||||
import { checkSyncInfo, isCloudantURI } from "./lib/src/utils_couchdb.js";
|
||||
import { testCrypt } from "./lib/src/e2ee_v2";
|
||||
import ObsidianLiveSyncPlugin from "./main";
|
||||
import { balanceChunks, isChunk, localDatabaseCleanUp, performRebuildDB, remoteDatabaseCleanup, requestToCouchDB } from "./utils";
|
||||
import { stripAllPrefixes } from "./lib/src/path";
|
||||
import { balanceChunks, localDatabaseCleanUp, performRebuildDB, remoteDatabaseCleanup, requestToCouchDB } from "./utils";
|
||||
|
||||
|
||||
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
@@ -1716,6 +1715,22 @@ ${stringifyYaml(pluginConfig)}`;
|
||||
await this.plugin.initializeDatabase();
|
||||
})
|
||||
})
|
||||
|
||||
new Setting(containerHatchEl)
|
||||
.setName("The Hash algorithm for chunk IDs")
|
||||
.setDesc("xxhash64 is the current default.")
|
||||
.setClass("wizardHidden")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions({ "": "Old Algorithm", "xxhash32": "xxhash32 (Fast)", "xxhash64": "xxhash64 (Fastest)" } as Record<HashAlgorithm, string>)
|
||||
.setValue(this.plugin.settings.hashAlg)
|
||||
.onChange(async (value: HashAlgorithm) => {
|
||||
this.plugin.settings.hashAlg = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
.setClass("wizardHidden");
|
||||
|
||||
addScreenElement("50", containerHatchEl);
|
||||
|
||||
|
||||
|
||||
@@ -10,3 +10,4 @@ import {
|
||||
} from "obsidian";
|
||||
const normalizePath = normalizePath_ as <T extends string | FilePath>(from: T) => T;
|
||||
export { normalizePath }
|
||||
export { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||
2
src/lib
2
src/lib
Submodule src/lib updated: 63fa0074fe...aacf942453
71
src/main.ts
71
src/main.ts
@@ -1,11 +1,11 @@
|
||||
const isDebug = false;
|
||||
|
||||
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "./deps";
|
||||
import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl } from "./deps";
|
||||
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry } from "./lib/src/types";
|
||||
import { type InternalFileInfo, type queueItem, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./types";
|
||||
import { getDocData, isDocContentSame, Parallels } from "./lib/src/utils";
|
||||
import { Logger } from "./lib/src/logger";
|
||||
import { arrayToChunkedArray, getDocData, isDocContentSame } from "./lib/src/utils";
|
||||
import { Logger, setGlobalLogFunction } from "./lib/src/logger";
|
||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||
import { ConflictResolveModal } from "./ConflictResolveModal";
|
||||
import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab";
|
||||
@@ -14,7 +14,7 @@ import { applyPatch, cancelAllPeriodicTask, cancelAllTasks, cancelTask, generate
|
||||
import { encrypt, tryDecrypt } from "./lib/src/e2ee_v2";
|
||||
import { enableEncryption, isCloudantURI, isErrorOfMissingDoc, isValidRemoteCouchDBURI } from "./lib/src/utils_couchdb";
|
||||
import { getGlobalStore, ObservableStore, observeStores } from "./lib/src/store";
|
||||
import { lockStore, logMessageStore, logStore } from "./lib/src/stores";
|
||||
import { lockStore, logMessageStore, logStore, type LogEntry } from "./lib/src/stores";
|
||||
import { setNoticeClass } from "./lib/src/wrapper";
|
||||
import { base64ToString, versionNumberString2Number, base64ToArrayBuffer, arrayBufferToBase64 } from "./lib/src/strbin";
|
||||
import { addPrefix, isPlainText, shouldBeIgnored, stripAllPrefixes } from "./lib/src/path";
|
||||
@@ -31,9 +31,17 @@ import { ConfigSync } from "./CmdConfigSync";
|
||||
import { confirmWithMessage } from "./dialogs";
|
||||
import { GlobalHistoryView, VIEW_TYPE_GLOBAL_HISTORY } from "./GlobalHistoryView";
|
||||
import { LogPaneView, VIEW_TYPE_LOG } from "./LogPaneView";
|
||||
import { mapAllTasksWithConcurrencyLimit, processAllTasksWithConcurrencyLimit } from "./lib/src/task";
|
||||
|
||||
setNoticeClass(Notice);
|
||||
|
||||
// DI the log again.
|
||||
setGlobalLogFunction((message: any, level?: LOG_LEVEL, key?: string) => {
|
||||
const entry = { message, level, key } as LogEntry;
|
||||
logStore.push(entry);
|
||||
});
|
||||
logStore.intercept(e => e.slice(Math.min(e.length - 200, 0)));
|
||||
|
||||
export default class ObsidianLiveSyncPlugin extends Plugin
|
||||
implements LiveSyncLocalDBEnv, LiveSyncReplicatorEnv {
|
||||
|
||||
@@ -1710,21 +1718,27 @@ Or if you are sure know what had been happened, we can unlock the database from
|
||||
const runAll = async<T>(procedureName: string, objects: T[], callback: (arg: T) => Promise<void>) => {
|
||||
Logger(procedureName);
|
||||
if (!this.localDatabase.isReady) throw Error("Database is not ready!");
|
||||
const para = Parallels();
|
||||
for (const v of objects) {
|
||||
await para.wait(10);
|
||||
para.add((async (v) => {
|
||||
try {
|
||||
await callback(v);
|
||||
} catch (ex) {
|
||||
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
|
||||
Logger(ex);
|
||||
}
|
||||
})(v));
|
||||
const procs = objects.map(e => async () => {
|
||||
try {
|
||||
await callback(e);
|
||||
return true;
|
||||
} catch (ex) {
|
||||
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
|
||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
let success = 0;
|
||||
let failed = 0;
|
||||
for await (const v of processAllTasksWithConcurrencyLimit(10, procs)) {
|
||||
if ("ok" in v && v.ok) {
|
||||
success++;
|
||||
} else {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
await para.all();
|
||||
Logger(`${procedureName} done.`);
|
||||
Logger(`${procedureName}: PASS:${success}, FAILED:${failed}`);
|
||||
}
|
||||
|
||||
await runAll("UPDATE DATABASE", onlyInStorage, async (e) => {
|
||||
@@ -1748,22 +1762,19 @@ Or if you are sure know what had been happened, we can unlock the database from
|
||||
if (!initialScan) {
|
||||
let caches: { [key: string]: { storageMtime: number; docMtime: number } } = {};
|
||||
caches = await this.kvDB.get<{ [key: string]: { storageMtime: number; docMtime: number } }>("diff-caches") || {};
|
||||
const docsCount = syncFiles.length;
|
||||
do {
|
||||
const syncFilesXSrc = syncFiles.splice(0, 100);
|
||||
const syncFilesX = [] as { file: TFile, id: DocumentID }[];
|
||||
for (const file of syncFilesXSrc) {
|
||||
const id = await this.path2id(getPathFromTFile(file));
|
||||
syncFilesX.push({ file: file, id: id });
|
||||
}
|
||||
const docs = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: syncFilesX.map(e => e.id), include_docs: true })
|
||||
const docsMap = docs.rows.reduce((p, c) => ({ ...p, [c.id]: c.doc }), {} as Record<DocumentID, EntryDoc>)
|
||||
|
||||
const syncFilesToSync = syncFilesX.map((e) => ({ file: e.file, doc: docsMap[e.id] as LoadedEntry }));
|
||||
await runAll(`CHECK FILE STATUS:${syncFiles.length}/${docsCount}`, syncFilesToSync, async (e) => {
|
||||
const syncFilesBatch = [...arrayToChunkedArray(syncFiles, 100)];
|
||||
const processes = syncFilesBatch.map((files, idx, total) => async () => {
|
||||
const dbEntries = await mapAllTasksWithConcurrencyLimit(10, files.map(file => async () => ({ file: file, id: await this.path2id(getPathFromTFile(file)) })));
|
||||
const dbEntriesOk = dbEntries.map(e => "ok" in e ? e.ok : undefined).filter(e => e);
|
||||
const docs = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: dbEntriesOk.map(e => e.id), include_docs: true });
|
||||
const docsMap = docs.rows.reduce((p, c) => ({ ...p, [c.id]: c.doc }), {} as Record<DocumentID, EntryDoc>);
|
||||
const syncFilesToSync = dbEntriesOk.map((e) => ({ file: e.file, doc: docsMap[e.id] as LoadedEntry }));
|
||||
await runAll(`CHECK FILE STATUS:${idx + 1}/${total.length}`, syncFilesToSync, async (e) => {
|
||||
caches = await this.syncFileBetweenDBandStorage(e.file, e.doc, initialScan, caches);
|
||||
});
|
||||
} while (syncFiles.length > 0);
|
||||
})
|
||||
await mapAllTasksWithConcurrencyLimit(2, processes);
|
||||
await this.kvDB.set("diff-caches", caches);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7",
|
||||
"es2019.array"
|
||||
"es2019.array",
|
||||
"ES2020.BigInt",
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
|
||||
51
updates.md
51
updates.md
@@ -14,50 +14,7 @@ I hope you will give it a try.
|
||||
|
||||
#### Minors
|
||||
|
||||
- 0.19.1
|
||||
- Fixed: Fixed hidden file handling on Linux
|
||||
- Improved: Now customization sync works more smoothly.
|
||||
- 0.19.2
|
||||
- Fixed:
|
||||
- Fixed garbage collection error while unreferenced chunks exist many.
|
||||
- Fixed filename validation on Linux.
|
||||
- Improved:
|
||||
- Showing status is now thinned for performance.
|
||||
- Enhance caching while collecting chunks.
|
||||
- 0.19.3
|
||||
- Improved:
|
||||
- Now replication will be paced by collecting chunks. If synchronisation has been deadlocked, please enable `Do not pace synchronization` once.
|
||||
- 0.19.4
|
||||
- Improved:
|
||||
- Reduced remote database checking to improve speed and reduce bandwidth.
|
||||
- Fixed:
|
||||
- Chunks which previously misinterpreted are now interpreted correctly.
|
||||
- No more missing chunks which not be found forever, except if it has been actually missing.
|
||||
- Deleted file detection on hidden file synchronising now works fine.
|
||||
- Now the Customisation sync is surely quiet while it has been disabled.
|
||||
- 0.19.5
|
||||
- Fixed:
|
||||
- Now hidden file synchronisation would not be hanged, even if so many files exist.
|
||||
- Improved:
|
||||
- Customisation sync works more smoothly.
|
||||
- Note: Concurrent processing has been rollbacked into the original implementation. As a result, the total number of processes is no longer shown next to the hourglass icon. However, only the processes that are running concurrently are shown.
|
||||
- 0.19.6
|
||||
- Fixed:
|
||||
- Logging has been tweaked.
|
||||
- No more too many planes and rockets.
|
||||
- The batch database update now surely only works in non-live mode.
|
||||
- Internal things:
|
||||
- Some frameworks has been upgraded.
|
||||
- Import declaration has been fixed.
|
||||
- Improved:
|
||||
- The plug-in now asks to enable a new adaptor, when rebuilding, if it is not enabled yet.
|
||||
- The setting dialogue refined.
|
||||
- Configurations for compatibilities have been moved under the hatch.
|
||||
- Made it clear that disabled is the default.
|
||||
- Ambiguous names configuration have been renamed.
|
||||
- Items that have no meaning in the settings are no longer displayed.
|
||||
- Some items have been reordered for clarity.
|
||||
- Each configuration has been grouped.
|
||||
- 0.19.1 to 0.19.6 has been moved into the updates_old.md
|
||||
- 0.19.7
|
||||
- Fixed:
|
||||
- The initial pane of Setting dialogue is now changed to General Settings.
|
||||
@@ -78,5 +35,11 @@ I hope you will give it a try.
|
||||
- 0.19.10
|
||||
- Fixed
|
||||
- Fixed the issue about fixing the database.
|
||||
- 0.19.11
|
||||
- Improvements:
|
||||
- Hashing ChunkID has been improved.
|
||||
- Logging keeps 400 lines now.
|
||||
- Refactored:
|
||||
- Import statement has been fixed about types.
|
||||
|
||||
... To continue on to `updates_old.md`.
|
||||
|
||||
@@ -1,3 +1,61 @@
|
||||
### 0.19.0
|
||||
|
||||
#### Customization sync
|
||||
|
||||
Since `Plugin and their settings` have been broken, so I tried to fix it, not just fix it, but fix it the way it should be.
|
||||
|
||||
Now, we have `Customization sync`.
|
||||
|
||||
It is a real shame that the compatibility between these features has been broken. However, this new feature is surely useful and I believe that worth getting over the pain.
|
||||
We can use the new feature with the same configuration. Only the menu on the command palette has been changed. The dialog can be opened by `Show customization sync dialog`.
|
||||
|
||||
I hope you will give it a try.
|
||||
|
||||
#### Minors
|
||||
- 0.19.1
|
||||
- Fixed: Fixed hidden file handling on Linux
|
||||
- Improved: Now customization sync works more smoothly.
|
||||
- 0.19.2
|
||||
- Fixed:
|
||||
- Fixed garbage collection error while unreferenced chunks exist many.
|
||||
- Fixed filename validation on Linux.
|
||||
- Improved:
|
||||
- Showing status is now thinned for performance.
|
||||
- Enhance caching while collecting chunks.
|
||||
- 0.19.3
|
||||
- Improved:
|
||||
- Now replication will be paced by collecting chunks. If synchronisation has been deadlocked, please enable `Do not pace synchronization` once.
|
||||
- 0.19.4
|
||||
- Improved:
|
||||
- Reduced remote database checking to improve speed and reduce bandwidth.
|
||||
- Fixed:
|
||||
- Chunks which previously misinterpreted are now interpreted correctly.
|
||||
- No more missing chunks which not be found forever, except if it has been actually missing.
|
||||
- Deleted file detection on hidden file synchronising now works fine.
|
||||
- Now the Customisation sync is surely quiet while it has been disabled.
|
||||
- 0.19.5
|
||||
- Fixed:
|
||||
- Now hidden file synchronisation would not be hanged, even if so many files exist.
|
||||
- Improved:
|
||||
- Customisation sync works more smoothly.
|
||||
- Note: Concurrent processing has been rollbacked into the original implementation. As a result, the total number of processes is no longer shown next to the hourglass icon. However, only the processes that are running concurrently are shown.
|
||||
- 0.19.6
|
||||
- Fixed:
|
||||
- Logging has been tweaked.
|
||||
- No more too many planes and rockets.
|
||||
- The batch database update now surely only works in non-live mode.
|
||||
- Internal things:
|
||||
- Some frameworks has been upgraded.
|
||||
- Import declaration has been fixed.
|
||||
- Improved:
|
||||
- The plug-in now asks to enable a new adaptor, when rebuilding, if it is not enabled yet.
|
||||
- The setting dialogue refined.
|
||||
- Configurations for compatibilities have been moved under the hatch.
|
||||
- Made it clear that disabled is the default.
|
||||
- Ambiguous names configuration have been renamed.
|
||||
- Items that have no meaning in the settings are no longer displayed.
|
||||
- Some items have been reordered for clarity.
|
||||
- Each configuration has been grouped.
|
||||
|
||||
### 0.18.0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user