diff --git a/package-lock.json b/package-lock.json index bebba61..151b8fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "diff-match-patch": "^1.0.5", + "fflate": "^0.8.2", "idb": "^8.0.0", "minimatch": "^9.0.3", "xxhash-wasm": "0.4.2", @@ -2307,6 +2308,11 @@ "node": ">=8" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6418,6 +6424,11 @@ "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" } }, + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", diff --git a/package.json b/package.json index 0bdeba6..b615812 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ }, "dependencies": { "diff-match-patch": "^1.0.5", + "fflate": "^0.8.2", "idb": "^8.0.0", "minimatch": "^9.0.3", "xxhash-wasm": "0.4.2", diff --git a/src/ObsidianLiveSyncSettingTab.ts b/src/ObsidianLiveSyncSettingTab.ts index c0f820e..f7ced4e 100644 --- a/src/ObsidianLiveSyncSettingTab.ts +++ b/src/ObsidianLiveSyncSettingTab.ts @@ -544,6 +544,19 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { text: "", }); + + containerRemoteDatabaseEl.createEl("h4", { text: "Effective Storage Using" }); + new Setting(containerRemoteDatabaseEl) + .setName("Data Compression (Experimental)") + .setDesc("Compresses data during transfer, saving space in the remote database. Note: Please ensure that all devices have v0.22.18 and connected tools are also supported compression.") + .addToggle((toggle) => + toggle.setValue(this.plugin.settings.enableCompression).onChange(async (value) => { + this.plugin.settings.enableCompression = value; + await this.plugin.saveSettings(); + this.display(); + }) + ); + containerRemoteDatabaseEl.createEl("h4", { text: "Confidentiality" }); const e2e = new Setting(containerRemoteDatabaseEl) diff --git a/src/lib b/src/lib index 0d21724..297ea7e 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 0d217242a8dbc2d052c687c6a5031b5cd638676f +Subproject commit 297ea7e932d9f8242f9244543992b1cbdeca0840 diff --git a/src/main.ts b/src/main.ts index 3ee8033..e92d69b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,7 @@ import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab"; import { DocumentHistoryModal } from "./DocumentHistoryModal"; import { applyPatch, cancelAllPeriodicTask, cancelAllTasks, cancelTask, generatePatchObj, id2path, isObjectMargeApplicable, isSensibleMargeApplicable, flattenObject, path2id, scheduleTask, tryParseJSON, isValidPath, isInternalMetadata, isPluginMetadata, stripInternalMetadataPrefix, isChunk, askSelectString, askYesNo, askString, PeriodicProcessor, getPath, getPathWithoutPrefix, getPathFromTFile, performRebuildDB, memoIfNotExist, memoObject, retrieveMemoObject, disposeMemoObject, isCustomisationSyncMetadata, compareFileFreshness, BASE_IS_NEW, TARGET_IS_NEW, EVEN, compareMTime, markChangesAreSame } from "./utils"; import { encrypt, tryDecrypt } from "./lib/src/e2ee_v2"; -import { balanceChunkPurgedDBs, enableEncryption, isCloudantURI, isErrorOfMissingDoc, isValidRemoteCouchDBURI, purgeUnreferencedChunks } from "./lib/src/utils_couchdb"; +import { balanceChunkPurgedDBs, enableCompression, enableEncryption, isCloudantURI, isErrorOfMissingDoc, isValidRemoteCouchDBURI, purgeUnreferencedChunks } from "./lib/src/utils_couchdb"; import { logStore, type LogEntry, collectingChunks, pluginScanningCount, hiddenFilesProcessingCount, hiddenFilesEventCount, logMessages } from "./lib/src/stores"; import { setNoticeClass } from "./lib/src/wrapper"; import { versionNumberString2Number, writeString, decodeBinary, readString } from "./lib/src/strbin"; @@ -119,7 +119,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin requestCount = reactiveSource(0); responseCount = reactiveSource(0); processReplication = (e: PouchDB.Core.ExistingDocument[]) => this.parseReplicationResult(e); - async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean, performSetup: boolean, skipInfo: boolean): Promise; info: PouchDB.Core.DatabaseInfo }> { + async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean, performSetup: boolean, skipInfo: boolean, compression: boolean): Promise; info: PouchDB.Core.DatabaseInfo }> { if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid"; if (uri.toLowerCase() != uri) return "Remote URI and database name could not contain capital letters."; if (uri.indexOf(" ") !== -1) return "Remote URI and database name could not contain spaces."; @@ -237,6 +237,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin }; const db: PouchDB.Database = new PouchDB(uri, conf); + enableCompression(db, compression); if (passphrase !== "false" && typeof passphrase === "string") { enableEncryption(db, passphrase, useDynamicIterationCount, false); }