@vrtmrz/livesync-commonlib 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/API/DirectFileManipulator.d.ts +2 -0
- package/dist/API/DirectFileManipulator.js +4 -0
- package/dist/API/DirectFileManipulatorV2.d.ts +150 -0
- package/dist/API/DirectFileManipulatorV2.js +424 -0
- package/dist/API/processSetting.d.ts +41 -0
- package/dist/API/processSetting.js +140 -0
- package/dist/ContentSplitter/ContentSplitter.d.ts +28 -0
- package/dist/ContentSplitter/ContentSplitter.js +5 -0
- package/dist/ContentSplitter/ContentSplitterBase.d.ts +51 -0
- package/dist/ContentSplitter/ContentSplitterBase.js +83 -0
- package/dist/ContentSplitter/ContentSplitterRabinKarp.d.ts +9 -0
- package/dist/ContentSplitter/ContentSplitterRabinKarp.js +32 -0
- package/dist/ContentSplitter/ContentSplitterV1.d.ts +9 -0
- package/dist/ContentSplitter/ContentSplitterV1.js +34 -0
- package/dist/ContentSplitter/ContentSplitterV2.d.ts +9 -0
- package/dist/ContentSplitter/ContentSplitterV2.js +34 -0
- package/dist/ContentSplitter/ContentSplitters.d.ts +12 -0
- package/dist/ContentSplitter/ContentSplitters.js +29 -0
- package/dist/bureau/bureau.d.ts +7 -0
- package/dist/bureau/bureau.js +5 -0
- package/dist/common/ConnectionString.d.ts +30 -0
- package/dist/common/ConnectionString.js +179 -0
- package/dist/common/LSError.d.ts +48 -0
- package/dist/common/LSError.js +112 -0
- package/dist/common/configForDoc.d.ts +79 -0
- package/dist/common/configForDoc.js +312 -0
- package/dist/common/coreEnvFunctions.d.ts +21 -0
- package/dist/common/coreEnvFunctions.js +22 -0
- package/dist/common/coreEnvVars.d.ts +3 -0
- package/dist/common/coreEnvVars.js +6 -0
- package/dist/common/i18n.d.ts +18 -0
- package/dist/common/i18n.js +7193 -0
- package/dist/common/logger.d.ts +2 -0
- package/dist/common/logger.js +1 -0
- package/dist/common/messages/combinedMessages.dev.d.ts +7 -0
- package/dist/common/messages/combinedMessages.dev.js +44 -0
- package/dist/common/messages/combinedMessages.prod.d.ts +9264 -0
- package/dist/common/messages/combinedMessages.prod.js +9271 -0
- package/dist/common/messages/de.d.ts +297 -0
- package/dist/common/messages/de.js +7 -0
- package/dist/common/messages/def.d.ts +1119 -0
- package/dist/common/messages/def.js +7 -0
- package/dist/common/messages/es.d.ts +689 -0
- package/dist/common/messages/es.js +7 -0
- package/dist/common/messages/fr.d.ts +582 -0
- package/dist/common/messages/fr.js +7 -0
- package/dist/common/messages/he.d.ts +583 -0
- package/dist/common/messages/he.js +7 -0
- package/dist/common/messages/ja.d.ts +838 -0
- package/dist/common/messages/ja.js +7 -0
- package/dist/common/messages/ko.d.ts +800 -0
- package/dist/common/messages/ko.js +7 -0
- package/dist/common/messages/ru.d.ts +858 -0
- package/dist/common/messages/ru.js +7 -0
- package/dist/common/messages/zh-tw.d.ts +384 -0
- package/dist/common/messages/zh-tw.js +7 -0
- package/dist/common/messages/zh.d.ts +1093 -0
- package/dist/common/messages/zh.js +7 -0
- package/dist/common/messagesJson/de.json +295 -0
- package/dist/common/messagesJson/en.json +1117 -0
- package/dist/common/messagesJson/es.json +687 -0
- package/dist/common/messagesJson/fr.json +580 -0
- package/dist/common/messagesJson/he.json +581 -0
- package/dist/common/messagesJson/ja.json +836 -0
- package/dist/common/messagesJson/ko.json +798 -0
- package/dist/common/messagesJson/ru.json +856 -0
- package/dist/common/messagesJson/zh-tw.json +382 -0
- package/dist/common/messagesJson/zh.json +1091 -0
- package/dist/common/models/auth.type.d.ts +41 -0
- package/dist/common/models/auth.type.js +0 -0
- package/dist/common/models/db.const.d.ts +20 -0
- package/dist/common/models/db.const.js +28 -0
- package/dist/common/models/db.definition.d.ts +56 -0
- package/dist/common/models/db.definition.js +6 -0
- package/dist/common/models/db.type.d.ts +142 -0
- package/dist/common/models/db.type.js +0 -0
- package/dist/common/models/diff.definition.d.ts +16 -0
- package/dist/common/models/diff.definition.js +0 -0
- package/dist/common/models/fileaccess.const.d.ts +7 -0
- package/dist/common/models/fileaccess.const.js +16 -0
- package/dist/common/models/fileaccess.type.d.ts +72 -0
- package/dist/common/models/fileaccess.type.js +0 -0
- package/dist/common/models/redflag.const.d.ts +32 -0
- package/dist/common/models/redflag.const.js +27 -0
- package/dist/common/models/setting.const.d.ts +49 -0
- package/dist/common/models/setting.const.defaults.d.ts +3 -0
- package/dist/common/models/setting.const.defaults.js +185 -0
- package/dist/common/models/setting.const.js +68 -0
- package/dist/common/models/setting.const.preferred.d.ts +5 -0
- package/dist/common/models/setting.const.preferred.js +35 -0
- package/dist/common/models/setting.const.qr.d.ts +2 -0
- package/dist/common/models/setting.const.qr.js +174 -0
- package/dist/common/models/setting.type.d.ts +900 -0
- package/dist/common/models/setting.type.js +8 -0
- package/dist/common/models/shared.const.behabiour.d.ts +28 -0
- package/dist/common/models/shared.const.behabiour.js +36 -0
- package/dist/common/models/shared.const.d.ts +5 -0
- package/dist/common/models/shared.const.js +12 -0
- package/dist/common/models/shared.const.symbols.d.ts +9 -0
- package/dist/common/models/shared.const.symbols.js +20 -0
- package/dist/common/models/shared.definition.configNames.d.ts +36 -0
- package/dist/common/models/shared.definition.configNames.js +203 -0
- package/dist/common/models/shared.definition.d.ts +22 -0
- package/dist/common/models/shared.definition.js +24 -0
- package/dist/common/models/shared.type.util.d.ts +8 -0
- package/dist/common/models/shared.type.util.js +0 -0
- package/dist/common/models/sync.definition.d.ts +18 -0
- package/dist/common/models/sync.definition.js +20 -0
- package/dist/common/models/tweak.definition.d.ts +191 -0
- package/dist/common/models/tweak.definition.js +77 -0
- package/dist/common/rosetta.d.ts +42 -0
- package/dist/common/rosetta.js +57 -0
- package/dist/common/settingConstants.d.ts +216 -0
- package/dist/common/settingConstants.js +434 -0
- package/dist/common/typeUtils.d.ts +17 -0
- package/dist/common/typeUtils.js +51 -0
- package/dist/common/types.d.ts +107 -0
- package/dist/common/types.js +212 -0
- package/dist/common/utils.d.ts +129 -0
- package/dist/common/utils.doc.d.ts +11 -0
- package/dist/common/utils.doc.js +35 -0
- package/dist/common/utils.js +583 -0
- package/dist/common/utils.object.d.ts +2 -0
- package/dist/common/utils.object.js +14 -0
- package/dist/common/utils.patch.d.ts +8 -0
- package/dist/common/utils.patch.js +178 -0
- package/dist/common/utils.type.d.ts +1 -0
- package/dist/common/utils.type.js +0 -0
- package/dist/context.d.ts +8 -0
- package/dist/context.js +14 -0
- package/dist/databases/IndexedDBKeyValueDatabase.d.ts +26 -0
- package/dist/databases/IndexedDBKeyValueDatabase.js +130 -0
- package/dist/dataobject/StoredMap.d.ts +12 -0
- package/dist/dataobject/StoredMap.js +47 -0
- package/dist/dev/checks.d.ts +5 -0
- package/dist/dev/checks.js +38 -0
- package/dist/encryption/encryptHKDF.d.ts +3 -0
- package/dist/encryption/encryptHKDF.js +7 -0
- package/dist/encryption/stringEncryption.d.ts +27 -0
- package/dist/encryption/stringEncryption.js +59 -0
- package/dist/events/coreEvents.d.ts +54 -0
- package/dist/events/coreEvents.js +46 -0
- package/dist/hub/hub.d.ts +11 -0
- package/dist/hub/hub.js +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/interfaces/AsyncActivityRunner.d.ts +18 -0
- package/dist/interfaces/AsyncActivityRunner.js +7 -0
- package/dist/interfaces/Confirm.d.ts +17 -0
- package/dist/interfaces/Confirm.js +0 -0
- package/dist/interfaces/DatabaseFileAccess.d.ts +14 -0
- package/dist/interfaces/DatabaseFileAccess.js +0 -0
- package/dist/interfaces/DatabaseRebuilder.d.ts +13 -0
- package/dist/interfaces/DatabaseRebuilder.js +0 -0
- package/dist/interfaces/FileHandler.d.ts +13 -0
- package/dist/interfaces/FileHandler.js +0 -0
- package/dist/interfaces/KeyValueDatabase.d.ts +11 -0
- package/dist/interfaces/KeyValueDatabase.js +0 -0
- package/dist/interfaces/ServiceModule.d.ts +59 -0
- package/dist/interfaces/ServiceModule.js +19 -0
- package/dist/interfaces/StorageAccess.d.ts +44 -0
- package/dist/interfaces/StorageAccess.js +0 -0
- package/dist/interfaces/StorageEventManager.d.ts +16 -0
- package/dist/interfaces/StorageEventManager.js +5 -0
- package/dist/managers/ChangeManager.d.ts +61 -0
- package/dist/managers/ChangeManager.js +104 -0
- package/dist/managers/ChunkDeliveryCoordinator.d.ts +51 -0
- package/dist/managers/ChunkDeliveryCoordinator.js +136 -0
- package/dist/managers/ChunkFetcher.d.ts +44 -0
- package/dist/managers/ChunkFetcher.js +251 -0
- package/dist/managers/ChunkManager.d.ts +2 -0
- package/dist/managers/ChunkManager.js +4 -0
- package/dist/managers/ConflictManager.d.ts +37 -0
- package/dist/managers/ConflictManager.js +322 -0
- package/dist/managers/EntryManager/EntryManager.d.ts +37 -0
- package/dist/managers/EntryManager/EntryManager.js +73 -0
- package/dist/managers/EntryManager/EntryManagerImpls.d.ts +74 -0
- package/dist/managers/EntryManager/EntryManagerImpls.js +499 -0
- package/dist/managers/HashManager/HashManager.d.ts +60 -0
- package/dist/managers/HashManager/HashManager.js +97 -0
- package/dist/managers/HashManager/HashManagerCore.d.ts +114 -0
- package/dist/managers/HashManager/HashManagerCore.js +99 -0
- package/dist/managers/HashManager/PureJSHashManager.d.ts +77 -0
- package/dist/managers/HashManager/PureJSHashManager.js +84 -0
- package/dist/managers/HashManager/XXHashHashManager.d.ts +96 -0
- package/dist/managers/HashManager/XXHashHashManager.js +111 -0
- package/dist/managers/LayeredChunkManager/ArrivalWaitLayer.d.ts +30 -0
- package/dist/managers/LayeredChunkManager/ArrivalWaitLayer.js +115 -0
- package/dist/managers/LayeredChunkManager/CacheLayer.d.ts +59 -0
- package/dist/managers/LayeredChunkManager/CacheLayer.js +161 -0
- package/dist/managers/LayeredChunkManager/ChunkLayerInterfaces.d.ts +37 -0
- package/dist/managers/LayeredChunkManager/ChunkLayerInterfaces.js +0 -0
- package/dist/managers/LayeredChunkManager/DatabaseReadLayer.d.ts +14 -0
- package/dist/managers/LayeredChunkManager/DatabaseReadLayer.js +78 -0
- package/dist/managers/LayeredChunkManager/DatabaseWriteLayer.d.ts +11 -0
- package/dist/managers/LayeredChunkManager/DatabaseWriteLayer.js +43 -0
- package/dist/managers/LayeredChunkManager/HotPackLayer.d.ts +9 -0
- package/dist/managers/LayeredChunkManager/HotPackLayer.js +8 -0
- package/dist/managers/LayeredChunkManager/types.d.ts +39 -0
- package/dist/managers/LayeredChunkManager/types.js +0 -0
- package/dist/managers/LayeredChunkManager.d.ts +53 -0
- package/dist/managers/LayeredChunkManager.js +240 -0
- package/dist/managers/LiveSyncManagers.d.ts +48 -0
- package/dist/managers/LiveSyncManagers.js +136 -0
- package/dist/managers/StorageEventManager.d.ts +135 -0
- package/dist/managers/StorageEventManager.js +564 -0
- package/dist/managers/StorageProcessingManager.d.ts +14 -0
- package/dist/managers/StorageProcessingManager.js +48 -0
- package/dist/managers/adapters/IStorageEventConverterAdapter.d.ts +16 -0
- package/dist/managers/adapters/IStorageEventConverterAdapter.js +0 -0
- package/dist/managers/adapters/IStorageEventManagerAdapter.d.ts +18 -0
- package/dist/managers/adapters/IStorageEventManagerAdapter.js +0 -0
- package/dist/managers/adapters/IStorageEventPersistenceAdapter.d.ts +15 -0
- package/dist/managers/adapters/IStorageEventPersistenceAdapter.js +0 -0
- package/dist/managers/adapters/IStorageEventStatusAdapter.d.ts +13 -0
- package/dist/managers/adapters/IStorageEventStatusAdapter.js +0 -0
- package/dist/managers/adapters/IStorageEventTypeGuardAdapter.d.ts +16 -0
- package/dist/managers/adapters/IStorageEventTypeGuardAdapter.js +0 -0
- package/dist/managers/adapters/IStorageEventWatchAdapter.d.ts +21 -0
- package/dist/managers/adapters/IStorageEventWatchAdapter.js +0 -0
- package/dist/managers/adapters/index.d.ts +6 -0
- package/dist/managers/adapters/index.js +0 -0
- package/dist/mock_and_interop/stores.d.ts +21 -0
- package/dist/mock_and_interop/stores.js +15 -0
- package/dist/mock_and_interop/wrapper.d.ts +7 -0
- package/dist/mock_and_interop/wrapper.js +37 -0
- package/dist/mods.d.ts +1 -0
- package/dist/mods.js +18 -0
- package/dist/platform/browser/index.d.ts +1 -0
- package/dist/platform/browser/index.js +10 -0
- package/dist/platform/browser/storage.d.ts +35 -0
- package/dist/platform/browser/storage.js +139 -0
- package/dist/platform/node/index.d.ts +23 -0
- package/dist/platform/node/index.js +33 -0
- package/dist/platform/node/storage.d.ts +31 -0
- package/dist/platform/node/storage.js +104 -0
- package/dist/platform/storagePath.d.ts +7 -0
- package/dist/platform/storagePath.js +20 -0
- package/dist/pouchdb/LiveSyncDBFunctions.d.ts +14 -0
- package/dist/pouchdb/LiveSyncDBFunctions.js +129 -0
- package/dist/pouchdb/LiveSyncLocalDB.d.ts +196 -0
- package/dist/pouchdb/LiveSyncLocalDB.js +381 -0
- package/dist/pouchdb/PouchDBConstructor.d.ts +3 -0
- package/dist/pouchdb/PouchDBConstructor.js +0 -0
- package/dist/pouchdb/ReplicatorShim.d.ts +51 -0
- package/dist/pouchdb/ReplicatorShim.js +109 -0
- package/dist/pouchdb/StreamingFetch.d.ts +19 -0
- package/dist/pouchdb/StreamingFetch.js +263 -0
- package/dist/pouchdb/chunks.d.ts +38 -0
- package/dist/pouchdb/chunks.js +314 -0
- package/dist/pouchdb/compress.d.ts +11 -0
- package/dist/pouchdb/compress.js +99 -0
- package/dist/pouchdb/encryption.d.ts +20 -0
- package/dist/pouchdb/encryption.js +458 -0
- package/dist/pouchdb/negotiation.d.ts +9 -0
- package/dist/pouchdb/negotiation.js +109 -0
- package/dist/pouchdb/pouchdb-browser.d.ts +2 -0
- package/dist/pouchdb/pouchdb-browser.js +96 -0
- package/dist/pouchdb/pouchdb-http.d.ts +2 -0
- package/dist/pouchdb/pouchdb-http.js +94 -0
- package/dist/pouchdb/pouchdb-test.d.ts +2 -0
- package/dist/pouchdb/pouchdb-test.js +12 -0
- package/dist/pouchdb/utils_couchdb.d.ts +4 -0
- package/dist/pouchdb/utils_couchdb.js +38 -0
- package/dist/replication/LiveSyncAbstractReplicator.d.ts +69 -0
- package/dist/replication/LiveSyncAbstractReplicator.js +92 -0
- package/dist/replication/SyncParamsHandler.d.ts +35 -0
- package/dist/replication/SyncParamsHandler.js +118 -0
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +85 -0
- package/dist/replication/couchdb/LiveSyncReplicator.js +1132 -0
- package/dist/replication/httplib.d.ts +75 -0
- package/dist/replication/httplib.js +187 -0
- package/dist/replication/journal/JournalSyncCore.d.ts +70 -0
- package/dist/replication/journal/JournalSyncCore.js +737 -0
- package/dist/replication/journal/JournalSyncTypes.d.ts +9 -0
- package/dist/replication/journal/JournalSyncTypes.js +11 -0
- package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +40 -0
- package/dist/replication/journal/LiveSyncJournalReplicator.js +294 -0
- package/dist/replication/journal/LiveSyncJournalReplicatorEnv.d.ts +3 -0
- package/dist/replication/journal/LiveSyncJournalReplicatorEnv.js +0 -0
- package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +15 -0
- package/dist/replication/journal/objectstore/JournalStorageAdapter.js +0 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +21 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.js +204 -0
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +90 -0
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +380 -0
- package/dist/replication/trystero/P2PLogCollector.d.ts +8 -0
- package/dist/replication/trystero/P2PLogCollector.js +91 -0
- package/dist/replication/trystero/P2PReplicatorBase.d.ts +19 -0
- package/dist/replication/trystero/P2PReplicatorBase.js +0 -0
- package/dist/replication/trystero/P2PReplicatorCore.d.ts +12 -0
- package/dist/replication/trystero/P2PReplicatorCore.js +126 -0
- package/dist/replication/trystero/P2PReplicatorPaneCommon.d.ts +41 -0
- package/dist/replication/trystero/P2PReplicatorPaneCommon.js +20 -0
- package/dist/replication/trystero/ProxiedDB.d.ts +13 -0
- package/dist/replication/trystero/ProxiedDB.js +20 -0
- package/dist/replication/trystero/TrysteroReplicator.d.ts +152 -0
- package/dist/replication/trystero/TrysteroReplicator.js +683 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PClient.d.ts +19 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PClient.js +80 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PConnection.d.ts +2 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PConnection.js +4 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.d.ts +117 -0
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +540 -0
- package/dist/replication/trystero/UseP2PReplicatorResult.d.ts +11 -0
- package/dist/replication/trystero/UseP2PReplicatorResult.js +0 -0
- package/dist/replication/trystero/addP2PEventHandlers.d.ts +35 -0
- package/dist/replication/trystero/addP2PEventHandlers.js +43 -0
- package/dist/replication/trystero/rpcCompat.d.ts +1 -0
- package/dist/replication/trystero/rpcCompat.js +9 -0
- package/dist/replication/trystero/types.d.ts +95 -0
- package/dist/replication/trystero/types.js +27 -0
- package/dist/replication/trystero/useP2PReplicatorCommands.d.ts +7 -0
- package/dist/replication/trystero/useP2PReplicatorCommands.js +25 -0
- package/dist/replication/trystero/useP2PReplicatorFeature.d.ts +17 -0
- package/dist/replication/trystero/useP2PReplicatorFeature.js +82 -0
- package/dist/rpc/RpcRoom.d.ts +24 -0
- package/dist/rpc/RpcRoom.js +300 -0
- package/dist/rpc/RpcSession.d.ts +9 -0
- package/dist/rpc/RpcSession.js +32 -0
- package/dist/rpc/chunking.d.ts +11 -0
- package/dist/rpc/chunking.js +58 -0
- package/dist/rpc/errors.d.ts +8 -0
- package/dist/rpc/errors.js +26 -0
- package/dist/rpc/index.d.ts +6 -0
- package/dist/rpc/index.js +12 -0
- package/dist/rpc/pouchdb/RpcPouchDBProxy.d.ts +75 -0
- package/dist/rpc/pouchdb/RpcPouchDBProxy.js +115 -0
- package/dist/rpc/pouchdb/RpcPouchDBServer.d.ts +16 -0
- package/dist/rpc/pouchdb/RpcPouchDBServer.js +55 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.d.ts +24 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.js +208 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.types.d.ts +64 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.types.js +12 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.utils.d.ts +33 -0
- package/dist/rpc/transports/DiagRTCPeerConnections.utils.js +217 -0
- package/dist/rpc/transports/TrysteroTransport.d.ts +216 -0
- package/dist/rpc/transports/TrysteroTransport.js +134 -0
- package/dist/rpc/transports/trysteroUtils.d.ts +3 -0
- package/dist/rpc/transports/trysteroUtils.js +37 -0
- package/dist/rpc/types.d.ts +75 -0
- package/dist/rpc/types.js +6 -0
- package/dist/serviceFeatures/checkRemoteSize.d.ts +28 -0
- package/dist/serviceFeatures/checkRemoteSize.js +178 -0
- package/dist/serviceFeatures/offlineScanner.d.ts +128 -0
- package/dist/serviceFeatures/offlineScanner.js +553 -0
- package/dist/serviceFeatures/prepareDatabaseForUse.d.ts +20 -0
- package/dist/serviceFeatures/prepareDatabaseForUse.js +39 -0
- package/dist/serviceFeatures/remoteConfig.d.ts +46 -0
- package/dist/serviceFeatures/remoteConfig.js +247 -0
- package/dist/serviceFeatures/setupObsidian/qrCode.d.ts +4 -0
- package/dist/serviceFeatures/setupObsidian/qrCode.js +67 -0
- package/dist/serviceFeatures/setupObsidian/setupUri.d.ts +7 -0
- package/dist/serviceFeatures/setupObsidian/setupUri.js +70 -0
- package/dist/serviceFeatures/setupObsidian/types.d.ts +2 -0
- package/dist/serviceFeatures/setupObsidian/types.js +0 -0
- package/dist/serviceFeatures/targetFilter.d.ts +24 -0
- package/dist/serviceFeatures/targetFilter.js +178 -0
- package/dist/serviceModules/FileAccessBase.d.ts +93 -0
- package/dist/serviceModules/FileAccessBase.js +219 -0
- package/dist/serviceModules/Rebuilder.d.ts +92 -0
- package/dist/serviceModules/Rebuilder.js +449 -0
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.d.ts +40 -0
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.js +306 -0
- package/dist/serviceModules/ServiceFileAccessBase.d.ts +64 -0
- package/dist/serviceModules/ServiceFileAccessBase.js +312 -0
- package/dist/serviceModules/ServiceFileHandlerBase.d.ts +52 -0
- package/dist/serviceModules/ServiceFileHandlerBase.js +493 -0
- package/dist/serviceModules/ServiceModuleBase.d.ts +10 -0
- package/dist/serviceModules/ServiceModuleBase.js +13 -0
- package/dist/serviceModules/adapters/IConversionAdapter.d.ts +15 -0
- package/dist/serviceModules/adapters/IConversionAdapter.js +0 -0
- package/dist/serviceModules/adapters/IFileSystemAdapter.d.ts +47 -0
- package/dist/serviceModules/adapters/IFileSystemAdapter.js +0 -0
- package/dist/serviceModules/adapters/IPathAdapter.d.ts +15 -0
- package/dist/serviceModules/adapters/IPathAdapter.js +0 -0
- package/dist/serviceModules/adapters/IStorageAdapter.d.ts +56 -0
- package/dist/serviceModules/adapters/IStorageAdapter.js +0 -0
- package/dist/serviceModules/adapters/ITypeGuardAdapter.d.ts +14 -0
- package/dist/serviceModules/adapters/ITypeGuardAdapter.js +0 -0
- package/dist/serviceModules/adapters/IVaultAdapter.d.ts +51 -0
- package/dist/serviceModules/adapters/IVaultAdapter.js +0 -0
- package/dist/serviceModules/adapters/index.d.ts +6 -0
- package/dist/serviceModules/adapters/index.js +0 -0
- package/dist/services/BrowserServices.d.ts +36 -0
- package/dist/services/BrowserServices.js +123 -0
- package/dist/services/HeadlessServices.d.ts +14 -0
- package/dist/services/HeadlessServices.js +144 -0
- package/dist/services/InjectableServices.d.ts +1 -0
- package/dist/services/InjectableServices.js +4 -0
- package/dist/services/ServiceHub.d.ts +82 -0
- package/dist/services/ServiceHub.js +66 -0
- package/dist/services/base/APIService.d.ts +93 -0
- package/dist/services/base/APIService.js +44 -0
- package/dist/services/base/AppLifecycleService.d.ts +132 -0
- package/dist/services/base/AppLifecycleService.js +123 -0
- package/dist/services/base/ConfigService.d.ts +7 -0
- package/dist/services/base/ConfigService.js +6 -0
- package/dist/services/base/ConflictService.d.ts +54 -0
- package/dist/services/base/ConflictService.js +22 -0
- package/dist/services/base/ControlService.d.ts +54 -0
- package/dist/services/base/ControlService.js +103 -0
- package/dist/services/base/DatabaseEventService.d.ts +38 -0
- package/dist/services/base/DatabaseEventService.js +38 -0
- package/dist/services/base/DatabaseService.d.ts +40 -0
- package/dist/services/base/DatabaseService.js +79 -0
- package/dist/services/base/FileProcessingService.d.ts +25 -0
- package/dist/services/base/FileProcessingService.js +28 -0
- package/dist/services/base/IService.d.ts +284 -0
- package/dist/services/base/IService.js +1 -0
- package/dist/services/base/KeyValueDBService.d.ts +42 -0
- package/dist/services/base/KeyValueDBService.js +133 -0
- package/dist/services/base/MessageTranslator.d.ts +6 -0
- package/dist/services/base/MessageTranslator.js +4 -0
- package/dist/services/base/PathService.d.ts +38 -0
- package/dist/services/base/PathService.js +66 -0
- package/dist/services/base/RemoteService.d.ts +61 -0
- package/dist/services/base/RemoteService.js +212 -0
- package/dist/services/base/ReplicationService.d.ts +92 -0
- package/dist/services/base/ReplicationService.js +261 -0
- package/dist/services/base/ReplicatorService.d.ts +66 -0
- package/dist/services/base/ReplicatorService.js +164 -0
- package/dist/services/base/ServiceBase.d.ts +33 -0
- package/dist/services/base/ServiceBase.js +27 -0
- package/dist/services/base/SettingService.d.ts +112 -0
- package/dist/services/base/SettingService.js +543 -0
- package/dist/services/base/TestService.d.ts +28 -0
- package/dist/services/base/TestService.js +19 -0
- package/dist/services/base/TweakValueService.d.ts +40 -0
- package/dist/services/base/TweakValueService.js +6 -0
- package/dist/services/base/UnresolvedErrorManager.d.ts +15 -0
- package/dist/services/base/UnresolvedErrorManager.js +44 -0
- package/dist/services/base/VaultService.d.ts +69 -0
- package/dist/services/base/VaultService.js +70 -0
- package/dist/services/implements/base/SvelteDialog.d.ts +79 -0
- package/dist/services/implements/base/SvelteDialog.js +134 -0
- package/dist/services/implements/base/UIService.d.ts +24 -0
- package/dist/services/implements/base/UIService.js +37 -0
- package/dist/services/implements/browser/BrowserAPIService.d.ts +54 -0
- package/dist/services/implements/browser/BrowserAPIService.js +298 -0
- package/dist/services/implements/browser/BrowserDatabaseService.d.ts +7 -0
- package/dist/services/implements/browser/BrowserDatabaseService.js +10 -0
- package/dist/services/implements/browser/ConfigServiceBrowserCompat.d.ts +16 -0
- package/dist/services/implements/browser/ConfigServiceBrowserCompat.js +23 -0
- package/dist/services/implements/headless/HeadlessAPIService.d.ts +52 -0
- package/dist/services/implements/headless/HeadlessAPIService.js +127 -0
- package/dist/services/implements/headless/HeadlessDatabaseService.d.ts +7 -0
- package/dist/services/implements/headless/HeadlessDatabaseService.js +10 -0
- package/dist/services/implements/injectable/InjectableAPIService.d.ts +7 -0
- package/dist/services/implements/injectable/InjectableAPIService.js +18 -0
- package/dist/services/implements/injectable/InjectableAppLifecycleService.d.ts +11 -0
- package/dist/services/implements/injectable/InjectableAppLifecycleService.js +14 -0
- package/dist/services/implements/injectable/InjectableConflictService.d.ts +11 -0
- package/dist/services/implements/injectable/InjectableConflictService.js +14 -0
- package/dist/services/implements/injectable/InjectableDatabaseEventService.d.ts +4 -0
- package/dist/services/implements/injectable/InjectableDatabaseEventService.js +7 -0
- package/dist/services/implements/injectable/InjectableFileProcessingService.d.ts +4 -0
- package/dist/services/implements/injectable/InjectableFileProcessingService.js +6 -0
- package/dist/services/implements/injectable/InjectablePathService.d.ts +12 -0
- package/dist/services/implements/injectable/InjectablePathService.js +36 -0
- package/dist/services/implements/injectable/InjectableRemoteService.d.ts +4 -0
- package/dist/services/implements/injectable/InjectableRemoteService.js +7 -0
- package/dist/services/implements/injectable/InjectableReplicationService.d.ts +4 -0
- package/dist/services/implements/injectable/InjectableReplicationService.js +6 -0
- package/dist/services/implements/injectable/InjectableReplicatorService.d.ts +4 -0
- package/dist/services/implements/injectable/InjectableReplicatorService.js +7 -0
- package/dist/services/implements/injectable/InjectableServiceHub.d.ts +72 -0
- package/dist/services/implements/injectable/InjectableServiceHub.js +125 -0
- package/dist/services/implements/injectable/InjectableServices.d.ts +36 -0
- package/dist/services/implements/injectable/InjectableServices.js +1 -0
- package/dist/services/implements/injectable/InjectableSettingService.d.ts +11 -0
- package/dist/services/implements/injectable/InjectableSettingService.js +33 -0
- package/dist/services/implements/injectable/InjectableTestService.d.ts +5 -0
- package/dist/services/implements/injectable/InjectableTestService.js +8 -0
- package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +15 -0
- package/dist/services/implements/injectable/InjectableTweakValueService.js +12 -0
- package/dist/services/implements/injectable/InjectableVaultService.d.ts +9 -0
- package/dist/services/implements/injectable/InjectableVaultService.js +20 -0
- package/dist/services/lib/HandlerUtils.d.ts +374 -0
- package/dist/services/lib/HandlerUtils.js +412 -0
- package/dist/services/lib/logUtils.d.ts +13 -0
- package/dist/services/lib/logUtils.js +28 -0
- package/dist/services/lib/remoteActivity.d.ts +13 -0
- package/dist/services/lib/remoteActivity.js +11 -0
- package/dist/string_and_binary/chunks.d.ts +10 -0
- package/dist/string_and_binary/chunks.js +561 -0
- package/dist/string_and_binary/convert.d.ts +8 -0
- package/dist/string_and_binary/convert.js +46 -0
- package/dist/string_and_binary/hash.d.ts +2 -0
- package/dist/string_and_binary/hash.js +1 -0
- package/dist/string_and_binary/path.d.ts +35 -0
- package/dist/string_and_binary/path.js +240 -0
- package/dist/worker/bg.common.d.ts +2 -0
- package/dist/worker/bg.common.js +6 -0
- package/dist/worker/bg.worker.d.ts +1 -0
- package/dist/worker/bg.worker.encryption.d.ts +7 -0
- package/dist/worker/bg.worker.encryption.js +30 -0
- package/dist/worker/bg.worker.js +14 -0
- package/dist/worker/bg.worker.splitting.d.ts +6 -0
- package/dist/worker/bg.worker.splitting.js +36 -0
- package/dist/worker/bgWorker.d.ts +25 -0
- package/dist/worker/bgWorker.direct.d.ts +40 -0
- package/dist/worker/bgWorker.direct.js +65 -0
- package/dist/worker/bgWorker.encryption.d.ts +22 -0
- package/dist/worker/bgWorker.encryption.js +40 -0
- package/dist/worker/bgWorker.js +348 -0
- package/dist/worker/bgWorker.splitting.d.ts +27 -0
- package/dist/worker/bgWorker.splitting.js +123 -0
- package/dist/worker/universalTypes.d.ts +63 -0
- package/dist/worker/universalTypes.js +4 -0
- package/docs/development.md +51 -0
- package/docs/platform-storage.md +60 -0
- package/docs/releasing.md +69 -0
- package/package.json +693 -0
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VER,
|
|
3
|
+
MILESTONE_DOCID,
|
|
4
|
+
REPLICATION_BUSY_TIMEOUT,
|
|
5
|
+
LOG_LEVEL_INFO,
|
|
6
|
+
LOG_LEVEL_NOTICE,
|
|
7
|
+
LOG_LEVEL_VERBOSE,
|
|
8
|
+
DEVICE_ID_PREFERRED,
|
|
9
|
+
TweakValuesTemplate,
|
|
10
|
+
DOCID_SYNC_PARAMETERS,
|
|
11
|
+
DEFAULT_SYNC_PARAMETERS,
|
|
12
|
+
ProtocolVersions
|
|
13
|
+
} from "../../common/types.js";
|
|
14
|
+
import {
|
|
15
|
+
resolveWithIgnoreKnownError,
|
|
16
|
+
globalConcurrencyController,
|
|
17
|
+
extractObject,
|
|
18
|
+
wrapException,
|
|
19
|
+
sizeToHumanReadable,
|
|
20
|
+
arrayToChunkedArray,
|
|
21
|
+
parseHeaderValues
|
|
22
|
+
} from "../../common/utils.js";
|
|
23
|
+
import { Logger } from "../../common/logger.js";
|
|
24
|
+
import { checkRemoteVersion, countCompromisedChunks } from "../../pouchdb/negotiation.js";
|
|
25
|
+
import { preprocessOutgoing } from "../../pouchdb/encryption.js";
|
|
26
|
+
import { ensureDatabaseIsCompatible } from "../../pouchdb/LiveSyncDBFunctions.js";
|
|
27
|
+
import {
|
|
28
|
+
LiveSyncAbstractReplicator
|
|
29
|
+
} from "../LiveSyncAbstractReplicator.js";
|
|
30
|
+
import { shareRunningResult } from "octagonal-wheels/concurrency/lock";
|
|
31
|
+
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
|
|
32
|
+
import { Trench } from "octagonal-wheels/memory/memutil";
|
|
33
|
+
import { StreamInbox } from "octagonal-wheels/bureau/StreamInbox";
|
|
34
|
+
import {
|
|
35
|
+
clearHandlers,
|
|
36
|
+
createSyncParamsHanderForServer,
|
|
37
|
+
SyncParamsFetchError,
|
|
38
|
+
SyncParamsNotFoundError,
|
|
39
|
+
SyncParamsUpdateError
|
|
40
|
+
} from "../SyncParamsHandler.js";
|
|
41
|
+
const currentVersionRange = {
|
|
42
|
+
min: 0,
|
|
43
|
+
max: 2400,
|
|
44
|
+
current: 2
|
|
45
|
+
};
|
|
46
|
+
const selectorOnDemandPull = { selector: { type: { $ne: "leaf" } } };
|
|
47
|
+
async function* genReplication(s, signal) {
|
|
48
|
+
const inbox = new StreamInbox({ capacity: 1e4 });
|
|
49
|
+
const push = function(e) {
|
|
50
|
+
if (signal.aborted || inbox.isClosed) return;
|
|
51
|
+
if (inbox.post(e)) return;
|
|
52
|
+
Logger(`Replication event queue is full: ${e[0]}`, LOG_LEVEL_VERBOSE);
|
|
53
|
+
if (e[0] === "error" || e[0] === "denied") {
|
|
54
|
+
inbox.error(e[1]);
|
|
55
|
+
} else if (e[0] === "complete" || e[0] === "finally") {
|
|
56
|
+
inbox.close();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
void s.on("complete", (result) => push(["complete", result]));
|
|
60
|
+
void s.on("change", (result) => push(["change", result]));
|
|
61
|
+
void s.on("active", () => push(["active"]));
|
|
62
|
+
void s.on("denied", (err) => push(["denied", err]));
|
|
63
|
+
void s.on("error", (err) => push(["error", err]));
|
|
64
|
+
void s.on("paused", (err) => push(["paused", err]));
|
|
65
|
+
void s.then(() => push(["finally"])).catch(() => push(["finally"]));
|
|
66
|
+
const onAbort = () => inbox.close();
|
|
67
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
68
|
+
try {
|
|
69
|
+
const reader = inbox.readable.getReader();
|
|
70
|
+
while (!signal.aborted) {
|
|
71
|
+
const { done, value } = await reader.read();
|
|
72
|
+
if (done) break;
|
|
73
|
+
yield value;
|
|
74
|
+
}
|
|
75
|
+
} catch (ex) {
|
|
76
|
+
if (ex instanceof Error && ex.name == "AbortError") {
|
|
77
|
+
Logger(`Replication aborted`, LOG_LEVEL_VERBOSE);
|
|
78
|
+
} else {
|
|
79
|
+
throw ex;
|
|
80
|
+
}
|
|
81
|
+
} finally {
|
|
82
|
+
signal.removeEventListener("abort", onAbort);
|
|
83
|
+
s.cancel();
|
|
84
|
+
inbox.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
class LiveSyncCouchDBReplicator extends LiveSyncAbstractReplicator {
|
|
88
|
+
get isChunkSendingSupported() {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
isMobile() {
|
|
92
|
+
return this.env.services.API.isMobile();
|
|
93
|
+
}
|
|
94
|
+
constructor(env) {
|
|
95
|
+
super(env);
|
|
96
|
+
this.env = env;
|
|
97
|
+
void this.initializeDatabaseForReplication();
|
|
98
|
+
this.rawDatabase.on("close", () => {
|
|
99
|
+
this.closeReplication();
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
getInitialSyncParameters(setting) {
|
|
103
|
+
return Promise.resolve({
|
|
104
|
+
...DEFAULT_SYNC_PARAMETERS,
|
|
105
|
+
protocolVersion: ProtocolVersions.ADVANCED_E2EE
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async getSyncParameters(setting) {
|
|
109
|
+
try {
|
|
110
|
+
const downloadedSyncParams = await this.fetchRemoteDocument(setting, DOCID_SYNC_PARAMETERS);
|
|
111
|
+
if (!downloadedSyncParams) {
|
|
112
|
+
throw new SyncParamsNotFoundError(`Sync parameters not found on remote server`);
|
|
113
|
+
}
|
|
114
|
+
return downloadedSyncParams;
|
|
115
|
+
} catch (ex) {
|
|
116
|
+
Logger(`Could not retrieve remote sync parameters`, LOG_LEVEL_INFO);
|
|
117
|
+
throw SyncParamsFetchError.fromError(ex);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async putSyncParameters(setting, params) {
|
|
121
|
+
try {
|
|
122
|
+
const ret = await this.putRemoteDocument(setting, params);
|
|
123
|
+
if (ret.ok) {
|
|
124
|
+
return true;
|
|
125
|
+
} else {
|
|
126
|
+
throw new SyncParamsUpdateError(`Could not store remote sync parameters: ${JSON.stringify(ret)}`);
|
|
127
|
+
}
|
|
128
|
+
} catch (ex) {
|
|
129
|
+
Logger(`Could not store remote sync parameters`, LOG_LEVEL_INFO);
|
|
130
|
+
throw SyncParamsUpdateError.fromError(ex);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async getReplicationPBKDF2Salt(setting, refresh) {
|
|
134
|
+
const server = `${setting.couchDB_URI.replace(/\/+$/, "")}/${setting.couchDB_DBNAME}`;
|
|
135
|
+
const manager = createSyncParamsHanderForServer(server, {
|
|
136
|
+
put: (params) => this.putSyncParameters(setting, params),
|
|
137
|
+
get: () => this.getSyncParameters(setting),
|
|
138
|
+
create: () => this.getInitialSyncParameters(setting)
|
|
139
|
+
});
|
|
140
|
+
return await manager.getPBKDF2Salt(refresh);
|
|
141
|
+
}
|
|
142
|
+
async migrate(from, to) {
|
|
143
|
+
Logger(`Database updated from ${from} to ${to}`, LOG_LEVEL_NOTICE);
|
|
144
|
+
return Promise.resolve(true);
|
|
145
|
+
}
|
|
146
|
+
terminateSync() {
|
|
147
|
+
if (!this.controller) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.controller.abort();
|
|
151
|
+
this.controller = void 0;
|
|
152
|
+
}
|
|
153
|
+
async openReplication(setting, keepAlive, showResult, ignoreCleanLock) {
|
|
154
|
+
await this.initializeDatabaseForReplication();
|
|
155
|
+
if (keepAlive) {
|
|
156
|
+
void this.openContinuousReplication(setting, showResult, false);
|
|
157
|
+
} else {
|
|
158
|
+
return this.openOneShotReplication(setting, showResult, false, "sync", ignoreCleanLock);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
replicationActivated(showResult) {
|
|
162
|
+
this.syncStatus = "CONNECTED";
|
|
163
|
+
this.updateInfo();
|
|
164
|
+
Logger("Replication activated", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "sync");
|
|
165
|
+
}
|
|
166
|
+
async replicationChangeDetected(e, showResult, docSentOnStart, docArrivedOnStart) {
|
|
167
|
+
try {
|
|
168
|
+
if (e.direction == "pull") {
|
|
169
|
+
await this.env.services.replication.parseSynchroniseResult(e.change.docs);
|
|
170
|
+
this.docArrived += e.change.docs.length;
|
|
171
|
+
} else {
|
|
172
|
+
this.docSent += e.change.docs.length;
|
|
173
|
+
}
|
|
174
|
+
if (showResult) {
|
|
175
|
+
const maxPullSeq = this.maxPullSeq;
|
|
176
|
+
const maxPushSeq = this.maxPushSeq;
|
|
177
|
+
const lastSyncPullSeq = this.lastSyncPullSeq;
|
|
178
|
+
const lastSyncPushSeq = this.lastSyncPushSeq;
|
|
179
|
+
const pushLast = lastSyncPushSeq == 0 ? "" : lastSyncPushSeq >= maxPushSeq ? " (LIVE)" : ` (${maxPushSeq - lastSyncPushSeq})`;
|
|
180
|
+
const pullLast = lastSyncPullSeq == 0 ? "" : lastSyncPullSeq >= maxPullSeq ? " (LIVE)" : ` (${maxPullSeq - lastSyncPullSeq})`;
|
|
181
|
+
Logger(
|
|
182
|
+
`\u2191${this.docSent - docSentOnStart}${pushLast} \u2193${this.docArrived - docArrivedOnStart}${pullLast}`,
|
|
183
|
+
LOG_LEVEL_NOTICE,
|
|
184
|
+
"sync"
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
this.updateInfo();
|
|
188
|
+
} catch (ex) {
|
|
189
|
+
Logger("Replication callback error", LOG_LEVEL_NOTICE, "sync");
|
|
190
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
replicationCompleted(showResult) {
|
|
194
|
+
this.syncStatus = "COMPLETED";
|
|
195
|
+
this.updateInfo();
|
|
196
|
+
Logger("Replication completed", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, showResult ? "sync" : "");
|
|
197
|
+
this.terminateSync();
|
|
198
|
+
}
|
|
199
|
+
replicationDenied(e) {
|
|
200
|
+
this.syncStatus = "ERRORED";
|
|
201
|
+
this.updateInfo();
|
|
202
|
+
this.terminateSync();
|
|
203
|
+
Logger("Replication denied", LOG_LEVEL_NOTICE, "sync");
|
|
204
|
+
Logger(e, LOG_LEVEL_VERBOSE);
|
|
205
|
+
}
|
|
206
|
+
replicationErrored(e) {
|
|
207
|
+
this.syncStatus = "ERRORED";
|
|
208
|
+
this.terminateSync();
|
|
209
|
+
this.updateInfo();
|
|
210
|
+
Logger("Replication error", LOG_LEVEL_NOTICE, "sync");
|
|
211
|
+
Logger(e, LOG_LEVEL_VERBOSE);
|
|
212
|
+
}
|
|
213
|
+
replicationPaused() {
|
|
214
|
+
this.syncStatus = "PAUSED";
|
|
215
|
+
this.updateInfo();
|
|
216
|
+
Logger("Replication paused", LOG_LEVEL_VERBOSE, "sync");
|
|
217
|
+
}
|
|
218
|
+
async processSync(syncHandler, showResult, docSentOnStart, docArrivedOnStart, syncMode, retrying, reportCancelledAsDone = true) {
|
|
219
|
+
const controller = new AbortController();
|
|
220
|
+
if (this.controller) {
|
|
221
|
+
this.controller.abort();
|
|
222
|
+
}
|
|
223
|
+
this.controller = controller;
|
|
224
|
+
const gen = genReplication(syncHandler, controller.signal);
|
|
225
|
+
try {
|
|
226
|
+
for await (const [type, e] of gen) {
|
|
227
|
+
const releaser = await globalConcurrencyController.tryAcquire(1, REPLICATION_BUSY_TIMEOUT);
|
|
228
|
+
if (releaser === false) {
|
|
229
|
+
Logger("Replication stopped for busy.", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "sync");
|
|
230
|
+
return "FAILED";
|
|
231
|
+
}
|
|
232
|
+
releaser();
|
|
233
|
+
switch (type) {
|
|
234
|
+
case "change":
|
|
235
|
+
if ("direction" in e) {
|
|
236
|
+
if (e.direction == "pull") {
|
|
237
|
+
this.lastSyncPullSeq = Number(`${e.change.last_seq}`.split("-")[0]);
|
|
238
|
+
} else {
|
|
239
|
+
this.lastSyncPushSeq = Number(`${e.change.last_seq}`.split("-")[0]);
|
|
240
|
+
}
|
|
241
|
+
await this.replicationChangeDetected(e, showResult, docSentOnStart, docArrivedOnStart);
|
|
242
|
+
} else {
|
|
243
|
+
if (syncMode == "pullOnly") {
|
|
244
|
+
this.lastSyncPullSeq = Number(`${e.last_seq}`.split("-")[0]);
|
|
245
|
+
await this.replicationChangeDetected(
|
|
246
|
+
{ direction: "pull", change: e },
|
|
247
|
+
showResult,
|
|
248
|
+
docSentOnStart,
|
|
249
|
+
docArrivedOnStart
|
|
250
|
+
);
|
|
251
|
+
} else if (syncMode == "pushOnly") {
|
|
252
|
+
this.lastSyncPushSeq = Number(`${e.last_seq}`.split("-")[0]);
|
|
253
|
+
this.updateInfo();
|
|
254
|
+
await this.replicationChangeDetected(
|
|
255
|
+
{ direction: "push", change: e },
|
|
256
|
+
showResult,
|
|
257
|
+
docSentOnStart,
|
|
258
|
+
docArrivedOnStart
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (retrying) {
|
|
263
|
+
if (this.docSent - docSentOnStart + (this.docArrived - docArrivedOnStart) > this.originalSetting.batch_size * 2) {
|
|
264
|
+
return "NEED_RESURRECT";
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
case "complete":
|
|
269
|
+
this.replicationCompleted(showResult);
|
|
270
|
+
return "DONE";
|
|
271
|
+
case "active":
|
|
272
|
+
this.replicationActivated(showResult);
|
|
273
|
+
break;
|
|
274
|
+
case "denied":
|
|
275
|
+
this.replicationDenied(e);
|
|
276
|
+
return "FAILED";
|
|
277
|
+
case "error":
|
|
278
|
+
this.replicationErrored(e);
|
|
279
|
+
Logger("Replication stopped.", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "sync");
|
|
280
|
+
if (this.env.services.remote.hadLastPostFailedBySize) {
|
|
281
|
+
if (e && e.status == 413) {
|
|
282
|
+
Logger(
|
|
283
|
+
`Something went wrong during synchronisation. Please check the log!`,
|
|
284
|
+
LOG_LEVEL_NOTICE
|
|
285
|
+
);
|
|
286
|
+
return "FAILED";
|
|
287
|
+
}
|
|
288
|
+
return "NEED_RETRY";
|
|
289
|
+
} else {
|
|
290
|
+
Logger("Replication error", LOG_LEVEL_NOTICE, "sync");
|
|
291
|
+
Logger(e, LOG_LEVEL_VERBOSE);
|
|
292
|
+
}
|
|
293
|
+
return "FAILED";
|
|
294
|
+
case "paused":
|
|
295
|
+
this.replicationPaused();
|
|
296
|
+
break;
|
|
297
|
+
case "finally":
|
|
298
|
+
break;
|
|
299
|
+
default:
|
|
300
|
+
Logger(`Unexpected synchronization status:${JSON.stringify(e)}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (reportCancelledAsDone) {
|
|
304
|
+
return "DONE";
|
|
305
|
+
}
|
|
306
|
+
return "CANCELLED";
|
|
307
|
+
} catch (ex) {
|
|
308
|
+
Logger(`Unexpected synchronization exception`);
|
|
309
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
310
|
+
return "FAILED";
|
|
311
|
+
} finally {
|
|
312
|
+
this.terminateSync();
|
|
313
|
+
this.controller = void 0;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
getEmptyMaxEntry(remoteID) {
|
|
317
|
+
return {
|
|
318
|
+
_id: `_local/max_seq_on_chunk-${remoteID}`,
|
|
319
|
+
maxSeq: 0,
|
|
320
|
+
remoteID,
|
|
321
|
+
seqStatusMap: {},
|
|
322
|
+
_rev: void 0
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
async getLastTransferredSeqOfChunks(localDB, remoteID) {
|
|
326
|
+
const prevMax = {
|
|
327
|
+
_id: `_local/max_seq_on_chunk-${remoteID}`,
|
|
328
|
+
maxSeq: 0,
|
|
329
|
+
remoteID,
|
|
330
|
+
seqStatusMap: {},
|
|
331
|
+
_rev: void 0
|
|
332
|
+
};
|
|
333
|
+
const previous_max_seq_on_chunk = await wrapException(() => localDB.get(prevMax._id));
|
|
334
|
+
if (previous_max_seq_on_chunk instanceof Error) {
|
|
335
|
+
return prevMax;
|
|
336
|
+
}
|
|
337
|
+
return previous_max_seq_on_chunk;
|
|
338
|
+
}
|
|
339
|
+
async updateMaxTransferredSeqOnChunks(localDB, remoteID, seqStatusMap) {
|
|
340
|
+
const newMax = {
|
|
341
|
+
_id: "_local/max_seq_on_chunk",
|
|
342
|
+
maxSeq: 0,
|
|
343
|
+
remoteID,
|
|
344
|
+
seqStatusMap,
|
|
345
|
+
_rev: void 0
|
|
346
|
+
};
|
|
347
|
+
const seqs = Object.keys(seqStatusMap).map((e) => Number(e));
|
|
348
|
+
let maxSeq = 0;
|
|
349
|
+
for (const seq of seqs) {
|
|
350
|
+
if (!seqStatusMap[seq]) {
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
maxSeq = seq;
|
|
354
|
+
}
|
|
355
|
+
Logger(`Updating max seq on chunk to ${maxSeq}`, LOG_LEVEL_VERBOSE);
|
|
356
|
+
newMax.maxSeq = maxSeq;
|
|
357
|
+
const previous_max_seq_on_chunk = await wrapException(() => localDB.get(newMax._id));
|
|
358
|
+
if (previous_max_seq_on_chunk instanceof Error) {
|
|
359
|
+
delete newMax._rev;
|
|
360
|
+
} else {
|
|
361
|
+
newMax._rev = previous_max_seq_on_chunk._rev;
|
|
362
|
+
newMax.seqStatusMap = { ...previous_max_seq_on_chunk.seqStatusMap, ...seqStatusMap };
|
|
363
|
+
}
|
|
364
|
+
await wrapException(() => localDB.put(newMax));
|
|
365
|
+
return newMax;
|
|
366
|
+
}
|
|
367
|
+
// Used for sending chunks in bulk before replication.
|
|
368
|
+
async sendChunks(setting, remoteDB, showResult, fromSeq) {
|
|
369
|
+
const trench = new Trench(
|
|
370
|
+
this.env.services.keyValueDB.openSimpleStore("sc-"),
|
|
371
|
+
false
|
|
372
|
+
);
|
|
373
|
+
await trench.eraseAllEphemerals();
|
|
374
|
+
if (!remoteDB) {
|
|
375
|
+
const d = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
376
|
+
if (typeof d === "string") {
|
|
377
|
+
Logger(
|
|
378
|
+
this.translate("liveSyncReplicator.couldNotConnectToRemoteDb", { d }),
|
|
379
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
380
|
+
"fetch"
|
|
381
|
+
);
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
remoteDB = d.db;
|
|
385
|
+
}
|
|
386
|
+
await this.checkReplicationConnectivity(setting, false, false, false, false);
|
|
387
|
+
Logger(`Bulk sending chunks to remote database...`, showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "fetch");
|
|
388
|
+
const remoteMilestone = await remoteDB.get(MILESTONE_DOCID);
|
|
389
|
+
const remoteID = remoteMilestone?.created ?? 0;
|
|
390
|
+
const localDB = this.rawDatabase;
|
|
391
|
+
const te = new TextEncoder();
|
|
392
|
+
Logger(
|
|
393
|
+
this.translate("liveSyncReplicator.checkingLastSyncPoint"),
|
|
394
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
395
|
+
"fetch"
|
|
396
|
+
);
|
|
397
|
+
this.syncStatus = "CONNECTED";
|
|
398
|
+
const limitOneBatch = 250;
|
|
399
|
+
const prev = await this.getLastTransferredSeqOfChunks(localDB, remoteID);
|
|
400
|
+
const seq = fromSeq ?? prev.maxSeq;
|
|
401
|
+
const localScannedDocs = [];
|
|
402
|
+
const sentMap = {};
|
|
403
|
+
const diffChunks = localDB.changes({
|
|
404
|
+
since: seq,
|
|
405
|
+
live: false,
|
|
406
|
+
include_docs: true,
|
|
407
|
+
return_docs: false,
|
|
408
|
+
selector: { type: "leaf" }
|
|
409
|
+
// limit: limitOneBatch,
|
|
410
|
+
}).on("change", (e) => {
|
|
411
|
+
const numSeq = Number(e.seq);
|
|
412
|
+
if (prev.seqStatusMap[numSeq]) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
localScannedDocs.push({ id: e.id, seq: Number(e.seq) });
|
|
416
|
+
});
|
|
417
|
+
await diffChunks;
|
|
418
|
+
localScannedDocs.sort((a, b) => a.seq - b.seq);
|
|
419
|
+
const idSeqMap = Object.fromEntries(localScannedDocs.map((e) => [e.id, e.seq]));
|
|
420
|
+
for (const checkDocs of arrayToChunkedArray(localScannedDocs, limitOneBatch)) {
|
|
421
|
+
const remoteDocs = await remoteDB.allDocs({ keys: checkDocs.map((e) => e.id), include_docs: false });
|
|
422
|
+
const remoteDocMap = Object.fromEntries(
|
|
423
|
+
remoteDocs.rows.map((e) => [e.key, "error" in e ? e.error : e.value])
|
|
424
|
+
);
|
|
425
|
+
const sendDocs = checkDocs.filter((e) => remoteDocMap[e.id] == "not_found");
|
|
426
|
+
const sentDocs = checkDocs.filter((e) => remoteDocMap[e.id] != "not_found");
|
|
427
|
+
sendDocs.forEach((e) => sentMap[e.seq] = false);
|
|
428
|
+
sentDocs.forEach((e) => sentMap[e.seq] = true);
|
|
429
|
+
const sendDocsMap = Object.fromEntries(sendDocs.map((e) => [e.id, e.seq]));
|
|
430
|
+
if (sendDocs.length > 0) {
|
|
431
|
+
const localDocs = await localDB.allDocs({ keys: sendDocs.map((e) => e.id), include_docs: true });
|
|
432
|
+
await trench.queue(
|
|
433
|
+
"send-chunks",
|
|
434
|
+
localDocs.rows.filter((e) => "id" in e).map((e) => ({ seq: sendDocsMap[e.id], doc: e.doc, id: e.id }))
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
let bulkDocs = [];
|
|
439
|
+
let bulkDocsSizeBytes = 0;
|
|
440
|
+
let bulkDocsSizeCount = 0;
|
|
441
|
+
let maxSeq = 0;
|
|
442
|
+
const maxBatchSizeBytes = setting.sendChunksBulkMaxSize * 1024 * 1024;
|
|
443
|
+
const maxBatchSizeCount = 200;
|
|
444
|
+
const semaphore = Semaphore(4);
|
|
445
|
+
let sendingDocs = 0;
|
|
446
|
+
let sentDocsCount = 0;
|
|
447
|
+
const sendChunks = async (bulkDocs2, bulkDocsSize, seq2) => {
|
|
448
|
+
Logger(
|
|
449
|
+
`Sending ${bulkDocs2.length} (${bulkDocsSize} => ${sizeToHumanReadable(bulkDocsSize)} in plain) chunks to remote database...`,
|
|
450
|
+
LOG_LEVEL_VERBOSE
|
|
451
|
+
);
|
|
452
|
+
const releaser = await semaphore.acquire(1);
|
|
453
|
+
sendingDocs += bulkDocs2.length;
|
|
454
|
+
Logger(
|
|
455
|
+
`\u2191 Uploading chunks
|
|
456
|
+
${sendingDocs}/(${sentDocsCount} done)`,
|
|
457
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
458
|
+
"send"
|
|
459
|
+
);
|
|
460
|
+
try {
|
|
461
|
+
const uploadBulkDocTasks = bulkDocs2.map((e) => preprocessOutgoing(e));
|
|
462
|
+
const uploadBulkDocs = await Promise.all(uploadBulkDocTasks);
|
|
463
|
+
await remoteDB.bulkDocs(uploadBulkDocs, { new_edits: false });
|
|
464
|
+
uploadBulkDocs.forEach((e) => sentMap[idSeqMap[e._id]] = true);
|
|
465
|
+
await this.updateMaxTransferredSeqOnChunks(localDB, remoteID, sentMap);
|
|
466
|
+
sentDocsCount += bulkDocs2.length;
|
|
467
|
+
Logger(
|
|
468
|
+
`\u2191 Uploading chunks
|
|
469
|
+
${sendingDocs}/(${sentDocsCount} done)`,
|
|
470
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
471
|
+
"send"
|
|
472
|
+
);
|
|
473
|
+
} catch (ex) {
|
|
474
|
+
Logger("Bulk sending failed.", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "send");
|
|
475
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
476
|
+
return false;
|
|
477
|
+
} finally {
|
|
478
|
+
releaser();
|
|
479
|
+
}
|
|
480
|
+
return true;
|
|
481
|
+
};
|
|
482
|
+
const tasks = [];
|
|
483
|
+
do {
|
|
484
|
+
const nowSendChunks = await trench.dequeue("send-chunks");
|
|
485
|
+
if (!nowSendChunks || nowSendChunks.length == 0) {
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
for (const chunk of nowSendChunks) {
|
|
489
|
+
const jsonLength = te.encode(JSON.stringify(chunk.doc)).byteLength + 32;
|
|
490
|
+
if ((bulkDocsSizeBytes + jsonLength > maxBatchSizeBytes || bulkDocsSizeCount + 1 > maxBatchSizeCount) && bulkDocs.length > 0) {
|
|
491
|
+
tasks.push(sendChunks([...bulkDocs], bulkDocsSizeBytes, maxSeq));
|
|
492
|
+
bulkDocs = [];
|
|
493
|
+
bulkDocsSizeBytes = 0;
|
|
494
|
+
bulkDocsSizeCount = 0;
|
|
495
|
+
}
|
|
496
|
+
bulkDocs.push(chunk.doc);
|
|
497
|
+
maxSeq = chunk.seq;
|
|
498
|
+
bulkDocsSizeBytes += jsonLength;
|
|
499
|
+
bulkDocsSizeCount += 1;
|
|
500
|
+
}
|
|
501
|
+
if (bulkDocs.length > 0) {
|
|
502
|
+
tasks.push(sendChunks([...bulkDocs], bulkDocsSizeBytes, maxSeq));
|
|
503
|
+
}
|
|
504
|
+
const results = await Promise.all(
|
|
505
|
+
tasks.map(async (e) => {
|
|
506
|
+
try {
|
|
507
|
+
await e;
|
|
508
|
+
} catch (ex) {
|
|
509
|
+
Logger("Bulk sending failed.", showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "send");
|
|
510
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
})
|
|
514
|
+
);
|
|
515
|
+
if (results.some((e) => e === false)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
} while (true);
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
async openOneShotReplication(setting, showResult, retrying, syncMode, ignoreCleanLock = false) {
|
|
522
|
+
if (await this.ensurePBKDF2Salt(setting, showResult, !retrying) === false) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
const next = await shareRunningResult("oneShotReplication", async () => {
|
|
526
|
+
if (this.controller) {
|
|
527
|
+
Logger(
|
|
528
|
+
this.translate("liveSyncReplicator.replicationInProgress"),
|
|
529
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
530
|
+
"sync"
|
|
531
|
+
);
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
const localDB = this.rawDatabase;
|
|
535
|
+
Logger(this.translate("liveSyncReplicator.oneShotSyncBegin", { syncMode }));
|
|
536
|
+
const ret = await this.checkReplicationConnectivity(setting, false, retrying, showResult, ignoreCleanLock);
|
|
537
|
+
if (ret === false) {
|
|
538
|
+
Logger(
|
|
539
|
+
this.translate("liveSyncReplicator.couldNotConnectToServer"),
|
|
540
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
541
|
+
"sync"
|
|
542
|
+
);
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
this.maxPullSeq = Number(`${ret.info.update_seq}`.split("-")[0]);
|
|
546
|
+
this.maxPushSeq = Number(`${(await localDB.info()).update_seq}`.split("-")[0]);
|
|
547
|
+
if (showResult) {
|
|
548
|
+
Logger(this.translate("liveSyncReplicator.checkingLastSyncPoint"), LOG_LEVEL_NOTICE, "sync");
|
|
549
|
+
}
|
|
550
|
+
const { db, syncOptionBase } = ret;
|
|
551
|
+
this.syncStatus = "STARTED";
|
|
552
|
+
this.updateInfo();
|
|
553
|
+
const docArrivedOnStart = this.docArrived;
|
|
554
|
+
const docSentOnStart = this.docSent;
|
|
555
|
+
if (!retrying) {
|
|
556
|
+
this.originalSetting = setting;
|
|
557
|
+
}
|
|
558
|
+
this.terminateSync();
|
|
559
|
+
const syncHandler = syncMode == "sync" ? localDB.sync(db, { ...syncOptionBase }) : syncMode == "pullOnly" ? localDB.replicate.from(db, {
|
|
560
|
+
...syncOptionBase,
|
|
561
|
+
...setting.readChunksOnline ? selectorOnDemandPull : {}
|
|
562
|
+
}) : syncMode == "pushOnly" ? localDB.replicate.to(db, { ...syncOptionBase }) : void 0;
|
|
563
|
+
const syncResult = await this.processSync(
|
|
564
|
+
syncHandler,
|
|
565
|
+
showResult,
|
|
566
|
+
docSentOnStart,
|
|
567
|
+
docArrivedOnStart,
|
|
568
|
+
syncMode,
|
|
569
|
+
retrying,
|
|
570
|
+
false
|
|
571
|
+
);
|
|
572
|
+
if (syncResult == "DONE") {
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
if (syncResult == "CANCELLED") {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
if (syncResult == "FAILED") {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
if (syncResult == "NEED_RESURRECT") {
|
|
582
|
+
this.terminateSync();
|
|
583
|
+
return async () => await this.openOneShotReplication(
|
|
584
|
+
this.originalSetting,
|
|
585
|
+
showResult,
|
|
586
|
+
false,
|
|
587
|
+
syncMode,
|
|
588
|
+
ignoreCleanLock
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
if (syncResult == "NEED_RETRY") {
|
|
592
|
+
const tempSetting = JSON.parse(JSON.stringify(setting));
|
|
593
|
+
tempSetting.batch_size = Math.ceil(tempSetting.batch_size / 2) + 2;
|
|
594
|
+
tempSetting.batches_limit = Math.ceil(tempSetting.batches_limit / 2) + 2;
|
|
595
|
+
if (tempSetting.batch_size <= 5 && tempSetting.batches_limit <= 5) {
|
|
596
|
+
Logger(
|
|
597
|
+
this.translate("liveSyncReplicator.cantReplicateLowerValue"),
|
|
598
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
599
|
+
);
|
|
600
|
+
return false;
|
|
601
|
+
} else {
|
|
602
|
+
Logger(
|
|
603
|
+
this.translate("liveSyncReplicator.retryLowerBatchSize", {
|
|
604
|
+
batch_size: tempSetting.batch_size.toString(),
|
|
605
|
+
batches_limit: tempSetting.batches_limit.toString()
|
|
606
|
+
}),
|
|
607
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
608
|
+
);
|
|
609
|
+
return async () => await this.openOneShotReplication(tempSetting, showResult, true, syncMode, ignoreCleanLock);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return false;
|
|
613
|
+
});
|
|
614
|
+
if (typeof next === "boolean") {
|
|
615
|
+
return next;
|
|
616
|
+
}
|
|
617
|
+
return await next();
|
|
618
|
+
}
|
|
619
|
+
replicateAllToServer(setting, showingNotice) {
|
|
620
|
+
return this.openOneShotReplication(setting, showingNotice ?? false, false, "pushOnly");
|
|
621
|
+
}
|
|
622
|
+
replicateAllFromServer(setting, showingNotice) {
|
|
623
|
+
return this.openOneShotReplication(setting, showingNotice ?? false, false, "pullOnly");
|
|
624
|
+
}
|
|
625
|
+
async checkReplicationConnectivity(setting, keepAlive, skipCheck, showResult, ignoreCleanLock = false) {
|
|
626
|
+
if (setting.versionUpFlash != "") {
|
|
627
|
+
Logger(this.translate("Replicator.Message.VersionUpFlash"), LOG_LEVEL_NOTICE);
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
631
|
+
if (this.controller) {
|
|
632
|
+
Logger("Another replication running.");
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
636
|
+
if (typeof dbRet === "string") {
|
|
637
|
+
Logger(
|
|
638
|
+
this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }),
|
|
639
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
640
|
+
);
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
if (!skipCheck) {
|
|
644
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
645
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
this.remoteCleaned = false;
|
|
649
|
+
this.remoteLocked = false;
|
|
650
|
+
this.remoteLockedAndDeviceNotAccepted = false;
|
|
651
|
+
this.tweakSettingsMismatched = false;
|
|
652
|
+
this.preferredTweakValue = void 0;
|
|
653
|
+
const progress = `${dbRet.info.update_seq}`;
|
|
654
|
+
const info = {
|
|
655
|
+
app_version: this.env.services.API.getAppVersion(),
|
|
656
|
+
plugin_version: this.env.services.API.getPluginVersion(),
|
|
657
|
+
vault_name: this.env.services.vault.vaultName(),
|
|
658
|
+
device_name: this.env.services.vault.getVaultName(),
|
|
659
|
+
progress
|
|
660
|
+
};
|
|
661
|
+
const ensure = await ensureDatabaseIsCompatible(dbRet.db, setting, this.nodeid, currentVersionRange, info);
|
|
662
|
+
if (ensure == "INCOMPATIBLE") {
|
|
663
|
+
Logger(
|
|
664
|
+
"The remote database has no compatibility with the running version. Please upgrade the plugin.",
|
|
665
|
+
LOG_LEVEL_NOTICE
|
|
666
|
+
);
|
|
667
|
+
return false;
|
|
668
|
+
} else if (ensure == "NODE_LOCKED") {
|
|
669
|
+
Logger(
|
|
670
|
+
"The remote database has been rebuilt or corrupted since we have synchronized last time. Fetch rebuilt DB, explicit unlocking or chunk clean-up is required.",
|
|
671
|
+
LOG_LEVEL_NOTICE
|
|
672
|
+
);
|
|
673
|
+
this.remoteLockedAndDeviceNotAccepted = true;
|
|
674
|
+
this.remoteLocked = true;
|
|
675
|
+
return false;
|
|
676
|
+
} else if (ensure == "LOCKED") {
|
|
677
|
+
this.remoteLocked = true;
|
|
678
|
+
} else if (ensure == "NODE_CLEANED") {
|
|
679
|
+
if (ignoreCleanLock) {
|
|
680
|
+
this.remoteLocked = true;
|
|
681
|
+
} else {
|
|
682
|
+
Logger(
|
|
683
|
+
"The remote database has been cleaned up. Fetch rebuilt DB, explicit unlocking or chunk clean-up is required.",
|
|
684
|
+
LOG_LEVEL_NOTICE
|
|
685
|
+
);
|
|
686
|
+
this.remoteLockedAndDeviceNotAccepted = true;
|
|
687
|
+
this.remoteLocked = true;
|
|
688
|
+
this.remoteCleaned = true;
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
} else if (ensure == "OK") {
|
|
692
|
+
} else if (ensure[0] == "MISMATCHED") {
|
|
693
|
+
Logger(this.translate("liveSyncReplicator.mismatchedTweakDetected"), LOG_LEVEL_NOTICE);
|
|
694
|
+
this.tweakSettingsMismatched = true;
|
|
695
|
+
this.preferredTweakValue = ensure[1];
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
const syncOptionBase = {
|
|
700
|
+
batches_limit: setting.batches_limit,
|
|
701
|
+
batch_size: setting.batch_size
|
|
702
|
+
};
|
|
703
|
+
syncOptionBase.push = {};
|
|
704
|
+
if (setting.readChunksOnline) {
|
|
705
|
+
syncOptionBase.pull = { ...selectorOnDemandPull };
|
|
706
|
+
}
|
|
707
|
+
const syncOption = keepAlive ? { live: true, retry: true, heartbeat: setting.useTimeouts ? false : 3e4, ...syncOptionBase } : { ...syncOptionBase };
|
|
708
|
+
return { db: dbRet.db, info: dbRet.info, syncOptionBase, syncOption };
|
|
709
|
+
}
|
|
710
|
+
async openContinuousReplication(setting, showResult, retrying) {
|
|
711
|
+
const next = await shareRunningResult("continuousReplication", async () => {
|
|
712
|
+
if (this.controller) {
|
|
713
|
+
Logger(
|
|
714
|
+
this.translate("liveSyncReplicator.replicationInProgress"),
|
|
715
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
716
|
+
);
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
const localDB = this.rawDatabase;
|
|
720
|
+
Logger(this.translate("liveSyncReplicator.beforeLiveSync"));
|
|
721
|
+
const caughtUp = await this.env.services.replicator.runFiniteReplicationActivity(
|
|
722
|
+
() => this.openOneShotReplication(setting, showResult, false, "pullOnly"),
|
|
723
|
+
{ label: "replication" }
|
|
724
|
+
);
|
|
725
|
+
if (caughtUp) {
|
|
726
|
+
Logger(this.translate("liveSyncReplicator.liveSyncBegin"));
|
|
727
|
+
const ret = await this.checkReplicationConnectivity(setting, true, true, showResult);
|
|
728
|
+
if (ret === false) {
|
|
729
|
+
Logger(
|
|
730
|
+
this.translate("liveSyncReplicator.couldNotConnectToServer"),
|
|
731
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
732
|
+
);
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
if (showResult) {
|
|
736
|
+
Logger(this.translate("liveSyncReplicator.checkingLastSyncPoint"), LOG_LEVEL_NOTICE, "sync");
|
|
737
|
+
}
|
|
738
|
+
const { db, syncOption } = ret;
|
|
739
|
+
this.syncStatus = "STARTED";
|
|
740
|
+
this.maxPullSeq = Number(`${ret.info.update_seq}`.split("-")[0]);
|
|
741
|
+
this.maxPushSeq = Number(`${(await localDB.info()).update_seq}`.split("-")[0]);
|
|
742
|
+
this.updateInfo();
|
|
743
|
+
const docArrivedOnStart = this.docArrived;
|
|
744
|
+
const docSentOnStart = this.docSent;
|
|
745
|
+
if (!retrying) {
|
|
746
|
+
this.originalSetting = setting;
|
|
747
|
+
}
|
|
748
|
+
this.terminateSync();
|
|
749
|
+
const syncHandler = localDB.sync(db, {
|
|
750
|
+
...syncOption
|
|
751
|
+
});
|
|
752
|
+
const syncMode = "sync";
|
|
753
|
+
const syncResult = await this.processSync(
|
|
754
|
+
syncHandler,
|
|
755
|
+
showResult,
|
|
756
|
+
docSentOnStart,
|
|
757
|
+
docArrivedOnStart,
|
|
758
|
+
syncMode,
|
|
759
|
+
retrying
|
|
760
|
+
);
|
|
761
|
+
if (syncResult == "DONE") {
|
|
762
|
+
return true;
|
|
763
|
+
}
|
|
764
|
+
if (syncResult == "FAILED") {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
if (syncResult == "NEED_RESURRECT") {
|
|
768
|
+
this.terminateSync();
|
|
769
|
+
return async () => await this.openContinuousReplication(this.originalSetting, showResult, false);
|
|
770
|
+
}
|
|
771
|
+
if (syncResult == "NEED_RETRY") {
|
|
772
|
+
const tempSetting = JSON.parse(JSON.stringify(setting));
|
|
773
|
+
tempSetting.batch_size = Math.ceil(tempSetting.batch_size / 2) + 2;
|
|
774
|
+
tempSetting.batches_limit = Math.ceil(tempSetting.batches_limit / 2) + 2;
|
|
775
|
+
if (tempSetting.batch_size <= 5 && tempSetting.batches_limit <= 5) {
|
|
776
|
+
Logger(
|
|
777
|
+
this.translate("liveSyncReplicator.cantReplicateLowerValue"),
|
|
778
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
779
|
+
);
|
|
780
|
+
return false;
|
|
781
|
+
} else {
|
|
782
|
+
Logger(
|
|
783
|
+
this.translate("liveSyncReplicator.retryLowerBatchSize", {
|
|
784
|
+
batch_size: tempSetting.batch_size.toString(),
|
|
785
|
+
batches_limit: tempSetting.batches_limit.toString()
|
|
786
|
+
}),
|
|
787
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO
|
|
788
|
+
);
|
|
789
|
+
return async () => await this.openContinuousReplication(tempSetting, showResult, true);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return false;
|
|
794
|
+
});
|
|
795
|
+
if (typeof next === "boolean") {
|
|
796
|
+
return next;
|
|
797
|
+
}
|
|
798
|
+
return await next();
|
|
799
|
+
}
|
|
800
|
+
closeReplication() {
|
|
801
|
+
if (!this.controller) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
this.controller.abort();
|
|
805
|
+
this.controller = void 0;
|
|
806
|
+
this.syncStatus = "CLOSED";
|
|
807
|
+
Logger(this.translate("liveSyncReplicator.replicationClosed"));
|
|
808
|
+
this.updateInfo();
|
|
809
|
+
}
|
|
810
|
+
async tryResetRemoteDatabase(setting) {
|
|
811
|
+
this.closeReplication();
|
|
812
|
+
const con = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
813
|
+
if (typeof con == "string") return;
|
|
814
|
+
try {
|
|
815
|
+
await con.db.destroy();
|
|
816
|
+
Logger(this.translate("liveSyncReplicator.remoteDbDestroyed"), LOG_LEVEL_NOTICE);
|
|
817
|
+
await this.tryCreateRemoteDatabase(setting);
|
|
818
|
+
} catch (ex) {
|
|
819
|
+
Logger(this.translate("liveSyncReplicator.remoteDbDestroyError"), LOG_LEVEL_NOTICE);
|
|
820
|
+
Logger(ex, LOG_LEVEL_NOTICE);
|
|
821
|
+
}
|
|
822
|
+
clearHandlers();
|
|
823
|
+
await this.ensurePBKDF2Salt(setting, true, false);
|
|
824
|
+
}
|
|
825
|
+
async tryCreateRemoteDatabase(setting) {
|
|
826
|
+
this.closeReplication();
|
|
827
|
+
const con2 = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
828
|
+
if (typeof con2 === "string") return;
|
|
829
|
+
clearHandlers();
|
|
830
|
+
await this.ensurePBKDF2Salt(setting, true, false);
|
|
831
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCreatedOrConnected"), LOG_LEVEL_NOTICE);
|
|
832
|
+
}
|
|
833
|
+
async markRemoteLocked(setting, locked, lockByClean) {
|
|
834
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
835
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
836
|
+
if (typeof dbRet === "string") {
|
|
837
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
841
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const defInitPoint = {
|
|
845
|
+
_id: MILESTONE_DOCID,
|
|
846
|
+
type: "milestoneinfo",
|
|
847
|
+
created: Date.now(),
|
|
848
|
+
locked,
|
|
849
|
+
cleaned: lockByClean,
|
|
850
|
+
accepted_nodes: [this.nodeid],
|
|
851
|
+
node_chunk_info: { [this.nodeid]: currentVersionRange },
|
|
852
|
+
node_info: {},
|
|
853
|
+
tweak_values: {}
|
|
854
|
+
};
|
|
855
|
+
const remoteMilestone = {
|
|
856
|
+
...defInitPoint,
|
|
857
|
+
...await resolveWithIgnoreKnownError(dbRet.db.get(MILESTONE_DOCID), defInitPoint)
|
|
858
|
+
};
|
|
859
|
+
remoteMilestone.node_chunk_info = { ...defInitPoint.node_chunk_info, ...remoteMilestone.node_chunk_info };
|
|
860
|
+
remoteMilestone.accepted_nodes = [this.nodeid];
|
|
861
|
+
remoteMilestone.locked = locked;
|
|
862
|
+
remoteMilestone.cleaned = remoteMilestone.cleaned || lockByClean;
|
|
863
|
+
if (locked) {
|
|
864
|
+
Logger(this.translate("liveSyncReplicator.lockRemoteDb"), LOG_LEVEL_NOTICE);
|
|
865
|
+
} else {
|
|
866
|
+
Logger(this.translate("liveSyncReplicator.unlockRemoteDb"), LOG_LEVEL_NOTICE);
|
|
867
|
+
}
|
|
868
|
+
await dbRet.db.put(remoteMilestone);
|
|
869
|
+
}
|
|
870
|
+
async markRemoteResolved(setting) {
|
|
871
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
872
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
873
|
+
if (typeof dbRet === "string") {
|
|
874
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
878
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
const defInitPoint = {
|
|
882
|
+
_id: MILESTONE_DOCID,
|
|
883
|
+
type: "milestoneinfo",
|
|
884
|
+
created: Date.now(),
|
|
885
|
+
locked: false,
|
|
886
|
+
accepted_nodes: [this.nodeid],
|
|
887
|
+
node_info: {},
|
|
888
|
+
node_chunk_info: { [this.nodeid]: currentVersionRange },
|
|
889
|
+
tweak_values: {}
|
|
890
|
+
};
|
|
891
|
+
const remoteMilestone = {
|
|
892
|
+
...defInitPoint,
|
|
893
|
+
...await resolveWithIgnoreKnownError(dbRet.db.get(MILESTONE_DOCID), defInitPoint)
|
|
894
|
+
};
|
|
895
|
+
remoteMilestone.node_chunk_info = { ...defInitPoint.node_chunk_info, ...remoteMilestone.node_chunk_info };
|
|
896
|
+
remoteMilestone.accepted_nodes = Array.from(/* @__PURE__ */ new Set([...remoteMilestone.accepted_nodes, this.nodeid]));
|
|
897
|
+
Logger(this.translate("liveSyncReplicator.markDeviceResolved"), LOG_LEVEL_NOTICE);
|
|
898
|
+
const result = await dbRet.db.put(remoteMilestone);
|
|
899
|
+
if (result.ok) {
|
|
900
|
+
Logger(this.translate("liveSyncReplicator.remoteDbMarkedResolved"), LOG_LEVEL_VERBOSE);
|
|
901
|
+
} else {
|
|
902
|
+
Logger(this.translate("liveSyncReplicator.couldNotMarkResolveRemoteDb"), LOG_LEVEL_NOTICE);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
connectRemoteCouchDBWithSetting(settings, isMobile, performSetup = false, skipInfo = false) {
|
|
906
|
+
if (settings.encrypt && settings.passphrase == "" && !settings.permitEmptyPassphrase) {
|
|
907
|
+
return "Empty passphrases cannot be used without explicit permission";
|
|
908
|
+
}
|
|
909
|
+
const customHeaders = parseHeaderValues(settings.couchDB_CustomHeaders);
|
|
910
|
+
const auth = settings.useJWT ? {
|
|
911
|
+
jwtAlgorithm: settings.jwtAlgorithm,
|
|
912
|
+
jwtKey: settings.jwtKey,
|
|
913
|
+
jwtExpDuration: settings.jwtExpDuration,
|
|
914
|
+
jwtKid: settings.jwtKid,
|
|
915
|
+
jwtSub: settings.jwtSub,
|
|
916
|
+
type: "jwt"
|
|
917
|
+
} : {
|
|
918
|
+
username: settings.couchDB_USER,
|
|
919
|
+
password: settings.couchDB_PASSWORD,
|
|
920
|
+
type: "basic"
|
|
921
|
+
};
|
|
922
|
+
return this.env.services.remote.connect(
|
|
923
|
+
settings.couchDB_URI.replace(/\/+$/, "") + (settings.couchDB_DBNAME == "" ? "" : "/" + settings.couchDB_DBNAME),
|
|
924
|
+
auth,
|
|
925
|
+
settings.disableRequestURI || isMobile,
|
|
926
|
+
settings.encrypt ? settings.passphrase : false,
|
|
927
|
+
settings.useDynamicIterationCount,
|
|
928
|
+
performSetup,
|
|
929
|
+
skipInfo,
|
|
930
|
+
settings.enableCompression,
|
|
931
|
+
customHeaders,
|
|
932
|
+
settings.useRequestAPI,
|
|
933
|
+
async () => await this.getReplicationPBKDF2Salt(settings)
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
async _ensureConnection(settings, performSetup = false) {
|
|
937
|
+
const ret = await this.connectRemoteCouchDBWithSetting(settings, this.isMobile(), performSetup, true);
|
|
938
|
+
if (typeof ret === "string") {
|
|
939
|
+
throw new Error(`${this.translate("liveSyncReplicator.couldNotConnectToServer")}:${ret}`);
|
|
940
|
+
}
|
|
941
|
+
return ret.db;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Fetch a document from the remote database directly.
|
|
945
|
+
* @param settings RemoteDBSettings for the connection.
|
|
946
|
+
* @param id Document ID to fetch.
|
|
947
|
+
* @param db Optional PouchDB instance to use. If provided, it will use this instance instead of creating a new connection (then settings will be ignored).
|
|
948
|
+
* @returns The fetched document or false if the document does not exist.
|
|
949
|
+
* @throws {Error} Other errors that may occur during the fetch operation.
|
|
950
|
+
*/
|
|
951
|
+
async fetchRemoteDocument(settings, id, db) {
|
|
952
|
+
try {
|
|
953
|
+
const connDB = db ?? await this._ensureConnection(settings);
|
|
954
|
+
return await connDB.get(id);
|
|
955
|
+
} catch (ex) {
|
|
956
|
+
if (ex && ex.status == 404) {
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
throw ex;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Puts a document to the remote database directly
|
|
964
|
+
* @param settings RemoteDBSettings for the connection.
|
|
965
|
+
* @param doc Document to put.
|
|
966
|
+
* @param db Optional PouchDB instance to use. If provided, it will use this instance instead of creating a new connection (then settings will be ignored).
|
|
967
|
+
* @returns Response from the remote database or false if an error occurred.
|
|
968
|
+
* @throws {Error} If the document could not be put.
|
|
969
|
+
*/
|
|
970
|
+
async putRemoteDocument(settings, doc, db) {
|
|
971
|
+
const connDB = db ?? await this._ensureConnection(settings, true);
|
|
972
|
+
return await connDB.put(doc);
|
|
973
|
+
}
|
|
974
|
+
async fetchRemoteChunks(missingChunks, showResult) {
|
|
975
|
+
const ret = await this.connectRemoteCouchDBWithSetting(this.currentSettings, this.isMobile(), false, true);
|
|
976
|
+
if (typeof ret === "string") {
|
|
977
|
+
Logger(
|
|
978
|
+
`${this.translate("liveSyncReplicator.couldNotConnectToServer")} ${ret} `,
|
|
979
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
980
|
+
"fetch"
|
|
981
|
+
);
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
const remoteChunks = await ret.db.allDocs({ keys: missingChunks, include_docs: true });
|
|
985
|
+
if (remoteChunks.rows.some((e) => "error" in e)) {
|
|
986
|
+
Logger(
|
|
987
|
+
`Some chunks are not exists both on remote and local database.`,
|
|
988
|
+
showResult ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO,
|
|
989
|
+
"fetch"
|
|
990
|
+
);
|
|
991
|
+
Logger(`Missing chunks: ${missingChunks.join(",")}`, LOG_LEVEL_VERBOSE);
|
|
992
|
+
Logger(
|
|
993
|
+
`Error chunks: ${remoteChunks.rows.filter((e) => "error" in e).map((e) => e.key).join(",")}`,
|
|
994
|
+
LOG_LEVEL_VERBOSE
|
|
995
|
+
);
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
998
|
+
const remoteChunkItems = remoteChunks.rows.map((e) => e.doc);
|
|
999
|
+
return remoteChunkItems;
|
|
1000
|
+
}
|
|
1001
|
+
async tryConnectRemote(setting, showResult = true) {
|
|
1002
|
+
const db = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1003
|
+
if (typeof db === "string") {
|
|
1004
|
+
Logger(
|
|
1005
|
+
this.translate("liveSyncReplicator.couldNotConnectTo", {
|
|
1006
|
+
uri: setting.couchDB_URI,
|
|
1007
|
+
name: setting.couchDB_DBNAME,
|
|
1008
|
+
db
|
|
1009
|
+
}),
|
|
1010
|
+
LOG_LEVEL_NOTICE
|
|
1011
|
+
);
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
1014
|
+
Logger(`Connected to ${db.info.db_name} successfully`, LOG_LEVEL_NOTICE);
|
|
1015
|
+
return true;
|
|
1016
|
+
}
|
|
1017
|
+
async resetRemoteTweakSettings(setting) {
|
|
1018
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1019
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1020
|
+
if (typeof dbRet === "string") {
|
|
1021
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
1025
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
try {
|
|
1029
|
+
const remoteMilestone = await dbRet.db.get(MILESTONE_DOCID);
|
|
1030
|
+
remoteMilestone.tweak_values = {};
|
|
1031
|
+
await dbRet.db.put(remoteMilestone);
|
|
1032
|
+
Logger(`tweak values on the remote database have been cleared`, LOG_LEVEL_VERBOSE);
|
|
1033
|
+
} catch (ex) {
|
|
1034
|
+
Logger(`Could not retrieve remote milestone`, LOG_LEVEL_NOTICE);
|
|
1035
|
+
throw ex;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
async setPreferredRemoteTweakSettings(setting) {
|
|
1039
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1040
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1041
|
+
if (typeof dbRet === "string") {
|
|
1042
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
1046
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
try {
|
|
1050
|
+
const remoteMilestone = await dbRet.db.get(MILESTONE_DOCID);
|
|
1051
|
+
remoteMilestone.tweak_values[DEVICE_ID_PREFERRED] = extractObject(TweakValuesTemplate, { ...setting });
|
|
1052
|
+
await dbRet.db.put(remoteMilestone);
|
|
1053
|
+
Logger(`Preferred tweak values has been registered`, LOG_LEVEL_VERBOSE);
|
|
1054
|
+
} catch (ex) {
|
|
1055
|
+
Logger(`Could not retrieve remote milestone`, LOG_LEVEL_NOTICE);
|
|
1056
|
+
throw ex;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
async getRemotePreferredTweakValues(setting) {
|
|
1060
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1061
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1062
|
+
if (typeof dbRet === "string") {
|
|
1063
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1064
|
+
return false;
|
|
1065
|
+
}
|
|
1066
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
1067
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
try {
|
|
1071
|
+
const remoteMilestone = await dbRet.db.get(MILESTONE_DOCID);
|
|
1072
|
+
if (!remoteMilestone) throw new Error("Remote milestone not found");
|
|
1073
|
+
return remoteMilestone?.tweak_values?.[DEVICE_ID_PREFERRED] || false;
|
|
1074
|
+
} catch (ex) {
|
|
1075
|
+
Logger(`Could not retrieve remote milestone`, LOG_LEVEL_NOTICE);
|
|
1076
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
1077
|
+
return false;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
async compactRemote(setting) {
|
|
1081
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1082
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1083
|
+
if (typeof dbRet === "string") {
|
|
1084
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
const ret = await dbRet.db.compact({ interval: 1e3 });
|
|
1088
|
+
return ret.ok;
|
|
1089
|
+
}
|
|
1090
|
+
async getRemoteStatus(setting) {
|
|
1091
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1092
|
+
if (typeof dbRet === "string") {
|
|
1093
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1094
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
const info = await dbRet.db.info();
|
|
1098
|
+
return {
|
|
1099
|
+
...info,
|
|
1100
|
+
estimatedSize: info?.sizes?.file || 0
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
async countCompromisedChunks(setting = this.currentSettings) {
|
|
1104
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1105
|
+
if (typeof dbRet === "string") {
|
|
1106
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1107
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
const compromised = await countCompromisedChunks(dbRet.db);
|
|
1111
|
+
return compromised;
|
|
1112
|
+
}
|
|
1113
|
+
async getConnectedDeviceList(setting = this.currentSettings) {
|
|
1114
|
+
const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1115
|
+
if (typeof dbRet === "string") {
|
|
1116
|
+
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1117
|
+
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
const milestoneDoc = await dbRet.db.get(MILESTONE_DOCID);
|
|
1121
|
+
if (!milestoneDoc) {
|
|
1122
|
+
Logger("Could not retrieve remote milestone", LOG_LEVEL_NOTICE);
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
const nodeInfo = milestoneDoc.node_info;
|
|
1126
|
+
const acceptedNodes = milestoneDoc.accepted_nodes || [];
|
|
1127
|
+
return { node_info: nodeInfo, accepted_nodes: acceptedNodes };
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
export {
|
|
1131
|
+
LiveSyncCouchDBReplicator
|
|
1132
|
+
};
|