@vrtmrz/livesync-commonlib 0.1.3 → 0.1.5
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/dist/common/models/setting.const.defaults.js +2 -0
- package/dist/common/models/setting.const.qr.js +2 -0
- package/dist/common/models/setting.type.d.ts +11 -0
- package/dist/common/models/tweak.definition.d.ts +26 -0
- package/dist/common/models/tweak.definition.js +12 -0
- package/dist/common/settingConstants.d.ts +2 -0
- package/dist/common/settingConstants.js +8 -0
- package/dist/common/types.d.ts +6 -1
- package/dist/common/types.js +5 -1
- package/dist/replication/LiveSyncAbstractReplicator.d.ts +2 -2
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +2 -2
- package/dist/replication/couchdb/LiveSyncReplicator.js +62 -9
- package/dist/replication/journal/JournalSyncCore.d.ts +2 -1
- package/dist/replication/journal/JournalSyncCore.js +20 -0
- package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +2 -2
- package/dist/replication/journal/LiveSyncJournalReplicator.js +28 -12
- package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +15 -0
- package/dist/replication/journal/objectstore/JournalStorageAdapter.js +8 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +2 -1
- package/dist/replication/journal/objectstore/MinioStorageAdapter.js +29 -4
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +2 -2
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +2 -1
- package/dist/services/base/IService.d.ts +2 -2
- package/dist/services/base/TweakValueService.d.ts +2 -2
- package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +1 -1
- package/dist/worker/bgWorker.js +1 -1
- package/docs/proven-in-use.md +4 -0
- package/docs/settings-lifecycle.md +2 -0
- package/package.json +1 -1
|
@@ -114,6 +114,8 @@ const SETTINGS_SCHEMA_DEFAULTS = {
|
|
|
114
114
|
ignoreFiles: ".gitignore",
|
|
115
115
|
syncOnEditorSave: false,
|
|
116
116
|
keepReplicationActiveInBackground: false,
|
|
117
|
+
allowSleepDuringSynchronisation: false,
|
|
118
|
+
allowSleepDuringSynchronisationOnDesktop: true,
|
|
117
119
|
pluginSyncExtendedSetting: {},
|
|
118
120
|
syncMaxSizeInMB: 50,
|
|
119
121
|
settingSyncFile: "",
|
|
@@ -55,6 +55,8 @@ const KeyIndexOfSettings = {
|
|
|
55
55
|
syncOnEditorSave: 53,
|
|
56
56
|
keepReplicationActiveInBackground: -1,
|
|
57
57
|
// Desktop-only local preference; do not encode into the QR Code.
|
|
58
|
+
allowSleepDuringSynchronisation: 161,
|
|
59
|
+
allowSleepDuringSynchronisationOnDesktop: 162,
|
|
58
60
|
syncMinimumInterval: 54,
|
|
59
61
|
showVerboseLog: 55,
|
|
60
62
|
lessInformationInLog: 56,
|
|
@@ -103,6 +103,17 @@ interface SyncMethodSettings {
|
|
|
103
103
|
* and Periodic). Ignored on mobile. Default false.
|
|
104
104
|
*/
|
|
105
105
|
keepReplicationActiveInBackground: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Allow the operating system to sleep during finite synchronisation operations on every platform.
|
|
108
|
+
* Default false.
|
|
109
|
+
*/
|
|
110
|
+
allowSleepDuringSynchronisation: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Desktop-only override which allows the operating system to sleep during finite
|
|
113
|
+
* synchronisation operations when the general preference is disabled. Ignored on mobile.
|
|
114
|
+
* Default true.
|
|
115
|
+
*/
|
|
116
|
+
allowSleepDuringSynchronisationOnDesktop: boolean;
|
|
106
117
|
/**
|
|
107
118
|
* The minimum delay between synchronisation operations (in milliseconds).
|
|
108
119
|
* If the operation is triggered before this delay, the operation will be delayed until the delay is over, and executed as a single operation.
|
|
@@ -25,6 +25,8 @@ export declare const TweakValuesTemplate: {
|
|
|
25
25
|
syncOnFileOpen?: boolean;
|
|
26
26
|
syncOnEditorSave?: boolean;
|
|
27
27
|
keepReplicationActiveInBackground?: boolean;
|
|
28
|
+
allowSleepDuringSynchronisation?: boolean;
|
|
29
|
+
allowSleepDuringSynchronisationOnDesktop?: boolean;
|
|
28
30
|
syncMinimumInterval?: number;
|
|
29
31
|
showVerboseLog?: boolean;
|
|
30
32
|
lessInformationInLog?: boolean;
|
|
@@ -188,4 +190,28 @@ export declare const TweakValuesTemplate: {
|
|
|
188
190
|
};
|
|
189
191
|
export type TweakValues = Partial<typeof TweakValuesTemplate>;
|
|
190
192
|
export declare const DEVICE_ID_PREFERRED = "PREFERRED";
|
|
193
|
+
export declare const RemotePreferredTweakStatuses: {
|
|
194
|
+
readonly AVAILABLE: "available";
|
|
195
|
+
readonly NOT_CONFIGURED: "not-configured";
|
|
196
|
+
readonly UNAVAILABLE: "unavailable";
|
|
197
|
+
readonly UNSUPPORTED: "unsupported";
|
|
198
|
+
};
|
|
199
|
+
export type RemotePreferredTweakStatus = (typeof RemotePreferredTweakStatuses)[keyof typeof RemotePreferredTweakStatuses];
|
|
200
|
+
export declare const RemotePreferredTweakNotConfiguredReasons: {
|
|
201
|
+
readonly MILESTONE_MISSING: "milestone-missing";
|
|
202
|
+
readonly PREFERRED_VALUES_MISSING: "preferred-values-missing";
|
|
203
|
+
};
|
|
204
|
+
export type RemotePreferredTweakNotConfiguredReason = (typeof RemotePreferredTweakNotConfiguredReasons)[keyof typeof RemotePreferredTweakNotConfiguredReasons];
|
|
205
|
+
export type RemotePreferredTweakResult = {
|
|
206
|
+
status: typeof RemotePreferredTweakStatuses.AVAILABLE;
|
|
207
|
+
values: TweakValues;
|
|
208
|
+
} | {
|
|
209
|
+
status: typeof RemotePreferredTweakStatuses.NOT_CONFIGURED;
|
|
210
|
+
reason: RemotePreferredTweakNotConfiguredReason;
|
|
211
|
+
} | {
|
|
212
|
+
status: typeof RemotePreferredTweakStatuses.UNAVAILABLE;
|
|
213
|
+
error: unknown;
|
|
214
|
+
} | {
|
|
215
|
+
status: typeof RemotePreferredTweakStatuses.UNSUPPORTED;
|
|
216
|
+
};
|
|
191
217
|
export {};
|
|
@@ -60,11 +60,23 @@ const TweakValuesTemplate = {
|
|
|
60
60
|
tweakModified: 0
|
|
61
61
|
};
|
|
62
62
|
const DEVICE_ID_PREFERRED = "PREFERRED";
|
|
63
|
+
const RemotePreferredTweakStatuses = {
|
|
64
|
+
AVAILABLE: "available",
|
|
65
|
+
NOT_CONFIGURED: "not-configured",
|
|
66
|
+
UNAVAILABLE: "unavailable",
|
|
67
|
+
UNSUPPORTED: "unsupported"
|
|
68
|
+
};
|
|
69
|
+
const RemotePreferredTweakNotConfiguredReasons = {
|
|
70
|
+
MILESTONE_MISSING: "milestone-missing",
|
|
71
|
+
PREFERRED_VALUES_MISSING: "preferred-values-missing"
|
|
72
|
+
};
|
|
63
73
|
export {
|
|
64
74
|
CompatibleButLossyChanges,
|
|
65
75
|
DEVICE_ID_PREFERRED,
|
|
66
76
|
IncompatibleChanges,
|
|
67
77
|
IncompatibleChangesInSpecificPattern,
|
|
78
|
+
RemotePreferredTweakNotConfiguredReasons,
|
|
79
|
+
RemotePreferredTweakStatuses,
|
|
68
80
|
TweakValuesDefault,
|
|
69
81
|
TweakValuesRecommendedTemplate,
|
|
70
82
|
TweakValuesShouldMatchedTemplate,
|
|
@@ -35,6 +35,8 @@ export declare const AllSettingDefault: {
|
|
|
35
35
|
syncOnFileOpen: boolean;
|
|
36
36
|
syncOnEditorSave: boolean;
|
|
37
37
|
keepReplicationActiveInBackground: boolean;
|
|
38
|
+
allowSleepDuringSynchronisation: boolean;
|
|
39
|
+
allowSleepDuringSynchronisationOnDesktop: boolean;
|
|
38
40
|
syncMinimumInterval: number;
|
|
39
41
|
showVerboseLog: boolean;
|
|
40
42
|
lessInformationInLog: boolean;
|
|
@@ -88,6 +88,14 @@ const SettingInformation = {
|
|
|
88
88
|
name: "Keep replication active in the background",
|
|
89
89
|
desc: "Desktop only; uses more battery and network."
|
|
90
90
|
},
|
|
91
|
+
allowSleepDuringSynchronisation: {
|
|
92
|
+
name: "Allow sleep during synchronisation",
|
|
93
|
+
desc: "Allow the operating system to sleep while finite synchronisation operations are in progress."
|
|
94
|
+
},
|
|
95
|
+
allowSleepDuringSynchronisationOnDesktop: {
|
|
96
|
+
name: "Allow sleep during synchronisation on the desktop",
|
|
97
|
+
desc: "Desktop only. Allow sleep on this device even when the general option is disabled."
|
|
98
|
+
},
|
|
91
99
|
syncOnFileOpen: {
|
|
92
100
|
name: "Sync on File Open",
|
|
93
101
|
desc: "Forces the file to be synced when opened."
|
package/dist/common/types.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { SETTING_KEY_P2P_DEVICE_NAME, configURIBase, configURIBaseQR, SuffixData
|
|
|
21
21
|
import { configurationNames, LEVEL_ADVANCED, LEVEL_POWER_USER, LEVEL_EDGE_CASE, type ConfigLevel, type ConfigurationItem, statusDisplay, confName, confDesc } from "./models/shared.definition.configNames.js";
|
|
22
22
|
import type { CustomRegExpSource, CustomRegExpSourceList, ParsedCustomRegExp, Prettify } from "./models/shared.type.util.js";
|
|
23
23
|
import { ProtocolVersions, type ProtocolVersion, DOCID_SYNC_PARAMETERS, DOCID_JOURNAL_SYNC_PARAMETERS, type SyncParameters, DEFAULT_SYNC_PARAMETERS } from "./models/sync.definition.js";
|
|
24
|
-
import { TweakValuesShouldMatchedTemplate, IncompatibleChanges, CompatibleButLossyChanges, IncompatibleChangesInSpecificPattern, TweakValuesRecommendedTemplate, TweakValuesDefault, TweakValuesTemplate, type TweakValues, DEVICE_ID_PREFERRED } from "./models/tweak.definition.js";
|
|
24
|
+
import { TweakValuesShouldMatchedTemplate, IncompatibleChanges, CompatibleButLossyChanges, IncompatibleChangesInSpecificPattern, TweakValuesRecommendedTemplate, TweakValuesDefault, TweakValuesTemplate, type TweakValues, DEVICE_ID_PREFERRED, RemotePreferredTweakStatuses, type RemotePreferredTweakStatus, RemotePreferredTweakNotConfiguredReasons, type RemotePreferredTweakNotConfiguredReason, type RemotePreferredTweakResult } from "./models/tweak.definition.js";
|
|
25
25
|
import type { diff_result_leaf, dmp_result, diff_result, DIFF_CHECK_RESULT_AUTO, diff_check_result } from "./models/diff.definition.js";
|
|
26
26
|
import { PREFIXMD_LOGFILE, PREFIXMD_LOGFILE_UC, FlagFilesOriginal, FlagFilesHumanReadable, FLAGMD_REDFLAG, FLAGMD_REDFLAG2, FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3, FLAGMD_REDFLAG3_HR } from "./models/redflag.const.js";
|
|
27
27
|
import { DatabaseConnectingStatuses, type DatabaseConnectingStatus } from "./models/shared.definition.js";
|
|
@@ -68,6 +68,11 @@ export { confDesc };
|
|
|
68
68
|
export { TweakValuesTemplate };
|
|
69
69
|
export type { TweakValues };
|
|
70
70
|
export { DEVICE_ID_PREFERRED };
|
|
71
|
+
export { RemotePreferredTweakStatuses };
|
|
72
|
+
export type { RemotePreferredTweakStatus };
|
|
73
|
+
export { RemotePreferredTweakNotConfiguredReasons };
|
|
74
|
+
export type { RemotePreferredTweakNotConfiguredReason };
|
|
75
|
+
export type { RemotePreferredTweakResult };
|
|
71
76
|
export type { NodeKey };
|
|
72
77
|
export type { DeviceInfo };
|
|
73
78
|
export type { NodeData };
|
package/dist/common/types.js
CHANGED
|
@@ -110,7 +110,9 @@ import {
|
|
|
110
110
|
TweakValuesRecommendedTemplate,
|
|
111
111
|
TweakValuesDefault,
|
|
112
112
|
TweakValuesTemplate,
|
|
113
|
-
DEVICE_ID_PREFERRED
|
|
113
|
+
DEVICE_ID_PREFERRED,
|
|
114
|
+
RemotePreferredTweakStatuses,
|
|
115
|
+
RemotePreferredTweakNotConfiguredReasons
|
|
114
116
|
} from "./models/tweak.definition.js";
|
|
115
117
|
import {
|
|
116
118
|
PREFIXMD_LOGFILE,
|
|
@@ -197,6 +199,8 @@ export {
|
|
|
197
199
|
REPLICATION_BUSY_TIMEOUT,
|
|
198
200
|
RESULT_NOT_FOUND,
|
|
199
201
|
RESULT_TIMED_OUT,
|
|
202
|
+
RemotePreferredTweakNotConfiguredReasons,
|
|
203
|
+
RemotePreferredTweakStatuses,
|
|
200
204
|
RemoteTypes,
|
|
201
205
|
SALT_OF_ID,
|
|
202
206
|
SALT_OF_PASSPHRASE,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EntryDoc, type DatabaseConnectingStatus, type RemoteDBSettings, type EntryLeaf, type TweakValues, type NodeData } from "../common/types.js";
|
|
1
|
+
import { type EntryDoc, type DatabaseConnectingStatus, type RemoteDBSettings, type EntryLeaf, type TweakValues, type RemotePreferredTweakResult, type NodeData } from "../common/types.js";
|
|
2
2
|
import type { RequiredServices } from "../interfaces/ServiceModule.js";
|
|
3
3
|
import type { TranslationParameters } from "../services/base/MessageTranslator.js";
|
|
4
4
|
import type { CommonlibMessageKey } from "../services/base/CommonlibMessages.js";
|
|
@@ -60,7 +60,7 @@ export declare abstract class LiveSyncAbstractReplicator {
|
|
|
60
60
|
abstract setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise<void>;
|
|
61
61
|
abstract fetchRemoteChunks(missingChunks: string[], showResult: boolean): Promise<false | EntryLeaf[]>;
|
|
62
62
|
abstract getRemoteStatus(setting: RemoteDBSettings): Promise<false | RemoteDBStatus>;
|
|
63
|
-
abstract getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise<
|
|
63
|
+
abstract getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
64
64
|
abstract countCompromisedChunks(setting?: RemoteDBSettings): Promise<number | boolean>;
|
|
65
65
|
abstract getConnectedDeviceList(setting?: RemoteDBSettings): Promise<false | {
|
|
66
66
|
node_info: Record<string, NodeData>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EntryDoc, type RemoteDBSettings, type EntryLeaf, type
|
|
1
|
+
import { type EntryDoc, type RemoteDBSettings, type EntryLeaf, type SyncParameters, type DatabaseEntry, type NodeData, type RemotePreferredTweakResult } from "../../common/types.js";
|
|
2
2
|
import { LiveSyncAbstractReplicator, type LiveSyncReplicatorEnv, type RemoteDBStatus } from "../LiveSyncAbstractReplicator.js";
|
|
3
3
|
import type { ServiceHub } from "../../services/ServiceHub.js";
|
|
4
4
|
export interface LiveSyncCouchDBReplicatorEnv extends LiveSyncReplicatorEnv {
|
|
@@ -73,7 +73,7 @@ export declare class LiveSyncCouchDBReplicator extends LiveSyncAbstractReplicato
|
|
|
73
73
|
tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise<boolean>;
|
|
74
74
|
resetRemoteTweakSettings(setting: RemoteDBSettings): Promise<void>;
|
|
75
75
|
setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise<void>;
|
|
76
|
-
getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise<
|
|
76
|
+
getRemotePreferredTweakValues(setting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
77
77
|
compactRemote(setting: RemoteDBSettings): Promise<boolean>;
|
|
78
78
|
getRemoteStatus(setting: RemoteDBSettings): Promise<RemoteDBStatus | false>;
|
|
79
79
|
countCompromisedChunks(setting?: RemoteDBSettings): Promise<number | boolean>;
|
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
TweakValuesTemplate,
|
|
10
10
|
DOCID_SYNC_PARAMETERS,
|
|
11
11
|
DEFAULT_SYNC_PARAMETERS,
|
|
12
|
-
ProtocolVersions
|
|
12
|
+
ProtocolVersions,
|
|
13
|
+
RemotePreferredTweakNotConfiguredReasons,
|
|
14
|
+
RemotePreferredTweakStatuses
|
|
13
15
|
} from "../../common/types.js";
|
|
14
16
|
import {
|
|
15
17
|
resolveWithIgnoreKnownError,
|
|
@@ -22,6 +24,7 @@ import {
|
|
|
22
24
|
} from "../../common/utils.js";
|
|
23
25
|
import { Logger } from "../../common/logger.js";
|
|
24
26
|
import { checkRemoteVersion, countCompromisedChunks } from "../../pouchdb/negotiation.js";
|
|
27
|
+
import { isErrorOfMissingDoc } from "../../pouchdb/utils_couchdb.js";
|
|
25
28
|
import { preprocessOutgoing } from "../../pouchdb/encryption.js";
|
|
26
29
|
import { ensureDatabaseIsCompatible } from "../../pouchdb/LiveSyncDBFunctions.js";
|
|
27
30
|
import {
|
|
@@ -1050,23 +1053,73 @@ ${sendingDocs}/(${sentDocsCount} done)`,
|
|
|
1050
1053
|
}
|
|
1051
1054
|
async getRemotePreferredTweakValues(setting) {
|
|
1052
1055
|
const uri = setting.couchDB_URI.replace(/\/+$/, "") + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME);
|
|
1053
|
-
|
|
1056
|
+
let dbRet;
|
|
1057
|
+
try {
|
|
1058
|
+
dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.isMobile(), true);
|
|
1059
|
+
} catch (ex) {
|
|
1060
|
+
Logger(`Could not connect to the remote database`, LOG_LEVEL_NOTICE);
|
|
1061
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
1062
|
+
return {
|
|
1063
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
1064
|
+
error: ex
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1054
1067
|
if (typeof dbRet === "string") {
|
|
1055
1068
|
Logger(this.translate("liveSyncReplicator.couldNotConnectToURI", { uri, dbRet }), LOG_LEVEL_NOTICE);
|
|
1056
|
-
return
|
|
1069
|
+
return {
|
|
1070
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
1071
|
+
error: new Error(dbRet)
|
|
1072
|
+
};
|
|
1057
1073
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1074
|
+
try {
|
|
1075
|
+
if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) {
|
|
1076
|
+
const error = new Error("The remote database version is not compatible");
|
|
1077
|
+
Logger(this.translate("liveSyncReplicator.remoteDbCorrupted"), LOG_LEVEL_NOTICE);
|
|
1078
|
+
return {
|
|
1079
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
1080
|
+
error
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
} catch (ex) {
|
|
1084
|
+
Logger(`Could not check the remote database version`, LOG_LEVEL_NOTICE);
|
|
1085
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
1086
|
+
return {
|
|
1087
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
1088
|
+
error: ex
|
|
1089
|
+
};
|
|
1061
1090
|
}
|
|
1062
1091
|
try {
|
|
1063
1092
|
const remoteMilestone = await dbRet.db.get(MILESTONE_DOCID);
|
|
1064
|
-
if (!remoteMilestone)
|
|
1065
|
-
|
|
1093
|
+
if (!remoteMilestone) {
|
|
1094
|
+
return {
|
|
1095
|
+
status: RemotePreferredTweakStatuses.NOT_CONFIGURED,
|
|
1096
|
+
reason: RemotePreferredTweakNotConfiguredReasons.MILESTONE_MISSING
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
const preferred = remoteMilestone.tweak_values?.[DEVICE_ID_PREFERRED];
|
|
1100
|
+
if (!preferred) {
|
|
1101
|
+
return {
|
|
1102
|
+
status: RemotePreferredTweakStatuses.NOT_CONFIGURED,
|
|
1103
|
+
reason: RemotePreferredTweakNotConfiguredReasons.PREFERRED_VALUES_MISSING
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
return {
|
|
1107
|
+
status: RemotePreferredTweakStatuses.AVAILABLE,
|
|
1108
|
+
values: preferred
|
|
1109
|
+
};
|
|
1066
1110
|
} catch (ex) {
|
|
1111
|
+
if (isErrorOfMissingDoc(ex)) {
|
|
1112
|
+
return {
|
|
1113
|
+
status: RemotePreferredTweakStatuses.NOT_CONFIGURED,
|
|
1114
|
+
reason: RemotePreferredTweakNotConfiguredReasons.MILESTONE_MISSING
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1067
1117
|
Logger(`Could not retrieve remote milestone`, LOG_LEVEL_NOTICE);
|
|
1068
1118
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
1069
|
-
return
|
|
1119
|
+
return {
|
|
1120
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
1121
|
+
error: ex
|
|
1122
|
+
};
|
|
1070
1123
|
}
|
|
1071
1124
|
}
|
|
1072
1125
|
async compactRemote(setting) {
|
|
@@ -3,7 +3,7 @@ import type { ReplicationCallback, ReplicationStat } from "../LiveSyncAbstractRe
|
|
|
3
3
|
import { type SimpleStore } from "../../common/utils.js";
|
|
4
4
|
import { type CheckPointInfo } from "./JournalSyncTypes.js";
|
|
5
5
|
import type { LiveSyncJournalReplicatorEnv } from "./LiveSyncJournalReplicatorEnv.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type IJournalStorage, type JournalStorageReadResult } from "./objectstore/JournalStorageAdapter.js";
|
|
7
7
|
type ProcessingEntry = PouchDB.Core.PutDocument<EntryDoc> & PouchDB.Core.GetMeta;
|
|
8
8
|
export declare class JournalSyncCore {
|
|
9
9
|
_settings: BucketSyncSetting;
|
|
@@ -22,6 +22,7 @@ export declare class JournalSyncCore {
|
|
|
22
22
|
getHash(settings: BucketSyncSetting): string;
|
|
23
23
|
constructor(settings: BucketSyncSetting, store: SimpleStore<CheckPointInfo>, env: LiveSyncJournalReplicatorEnv, storage: IJournalStorage);
|
|
24
24
|
downloadJson<T>(key: string): Promise<T | false>;
|
|
25
|
+
downloadJsonWithResult<T>(key: string): Promise<JournalStorageReadResult<T>>;
|
|
25
26
|
uploadJson<T>(key: string, body: T): Promise<boolean>;
|
|
26
27
|
applyNewConfig(settings: BucketSyncSetting, store: SimpleStore<CheckPointInfo>, env: LiveSyncJournalReplicatorEnv): void;
|
|
27
28
|
updateInfo(info: Partial<ReplicationStat>): void;
|
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
import { shareRunningResult } from "octagonal-wheels/concurrency/lock";
|
|
19
19
|
import { wrappedDeflate, wrappedInflate } from "../../pouchdb/compress.js";
|
|
20
20
|
import { CheckPointInfoDefault } from "./JournalSyncTypes.js";
|
|
21
|
+
import {
|
|
22
|
+
JournalStorageReadStatuses
|
|
23
|
+
} from "./objectstore/JournalStorageAdapter.js";
|
|
21
24
|
import {
|
|
22
25
|
clearHandlers,
|
|
23
26
|
createSyncParamsHanderForServer,
|
|
@@ -116,6 +119,23 @@ class JournalSyncCore {
|
|
|
116
119
|
return false;
|
|
117
120
|
}
|
|
118
121
|
}
|
|
122
|
+
async downloadJsonWithResult(key) {
|
|
123
|
+
const result = await this.storage.downloadWithResult(key, true);
|
|
124
|
+
if (result.status !== JournalStorageReadStatuses.AVAILABLE) return result;
|
|
125
|
+
try {
|
|
126
|
+
return {
|
|
127
|
+
status: JournalStorageReadStatuses.AVAILABLE,
|
|
128
|
+
value: JSON.parse(new TextDecoder().decode(result.value))
|
|
129
|
+
};
|
|
130
|
+
} catch (ex) {
|
|
131
|
+
Logger(`Could not parse downloaded json ${key}`);
|
|
132
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
133
|
+
return {
|
|
134
|
+
status: JournalStorageReadStatuses.UNAVAILABLE,
|
|
135
|
+
error: ex
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
119
139
|
async uploadJson(key, body) {
|
|
120
140
|
try {
|
|
121
141
|
const data = new TextEncoder().encode(JSON.stringify(body));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RemoteDBSettings, type EntryLeaf, type ChunkVersionRange, type
|
|
1
|
+
import { type RemoteDBSettings, type EntryLeaf, type ChunkVersionRange, type NodeData, type RemotePreferredTweakResult } from "../../common/types.js";
|
|
2
2
|
import { JournalSyncCore } from "./JournalSyncCore.js";
|
|
3
3
|
import { LiveSyncAbstractReplicator, type RemoteDBStatus } from "../LiveSyncAbstractReplicator.js";
|
|
4
4
|
import { type ENSURE_DB_RESULT } from "../../pouchdb/LiveSyncDBFunctions.js";
|
|
@@ -29,7 +29,7 @@ export declare class LiveSyncJournalReplicator extends LiveSyncAbstractReplicato
|
|
|
29
29
|
tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise<boolean>;
|
|
30
30
|
resetRemoteTweakSettings(setting: RemoteDBSettings): Promise<void>;
|
|
31
31
|
setPreferredRemoteTweakSettings(setting: RemoteDBSettings): Promise<void>;
|
|
32
|
-
getRemotePreferredTweakValues(
|
|
32
|
+
getRemotePreferredTweakValues(_setting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
33
33
|
getRemoteStatus(setting: RemoteDBSettings): Promise<false | RemoteDBStatus>;
|
|
34
34
|
countCompromisedChunks(): Promise<number>;
|
|
35
35
|
getConnectedDeviceList(setting?: RemoteDBSettings): Promise<false | {
|
|
@@ -2,7 +2,9 @@ import {
|
|
|
2
2
|
LOG_LEVEL_NOTICE,
|
|
3
3
|
LOG_LEVEL_VERBOSE,
|
|
4
4
|
DEVICE_ID_PREFERRED,
|
|
5
|
-
TweakValuesTemplate
|
|
5
|
+
TweakValuesTemplate,
|
|
6
|
+
RemotePreferredTweakNotConfiguredReasons,
|
|
7
|
+
RemotePreferredTweakStatuses
|
|
6
8
|
} from "../../common/types.js";
|
|
7
9
|
import { Logger } from "../../common/logger.js";
|
|
8
10
|
import { JournalSyncCore } from "./JournalSyncCore.js";
|
|
@@ -11,6 +13,7 @@ import { LiveSyncAbstractReplicator } from "../LiveSyncAbstractReplicator.js";
|
|
|
11
13
|
import { ensureRemoteIsCompatible } from "../../pouchdb/LiveSyncDBFunctions.js";
|
|
12
14
|
import { extractObject } from "../../common/utils.js";
|
|
13
15
|
import { clearHandlers } from "../SyncParamsHandler.js";
|
|
16
|
+
import { JournalStorageReadStatuses } from "./objectstore/JournalStorageAdapter.js";
|
|
14
17
|
const MILSTONE_DOCID = "_00000000-milestone.json";
|
|
15
18
|
const currentVersionRange = {
|
|
16
19
|
min: 0,
|
|
@@ -256,18 +259,31 @@ ${ex.message}`, LOG_LEVEL_NOTICE);
|
|
|
256
259
|
throw ex;
|
|
257
260
|
}
|
|
258
261
|
}
|
|
259
|
-
async getRemotePreferredTweakValues(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
262
|
+
async getRemotePreferredTweakValues(_setting) {
|
|
263
|
+
const result = await this.client.downloadJsonWithResult(MILSTONE_DOCID);
|
|
264
|
+
if (result.status === JournalStorageReadStatuses.NOT_FOUND) {
|
|
265
|
+
return {
|
|
266
|
+
status: RemotePreferredTweakStatuses.NOT_CONFIGURED,
|
|
267
|
+
reason: RemotePreferredTweakNotConfiguredReasons.MILESTONE_MISSING
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (result.status === JournalStorageReadStatuses.UNAVAILABLE) {
|
|
271
|
+
return {
|
|
272
|
+
status: RemotePreferredTweakStatuses.UNAVAILABLE,
|
|
273
|
+
error: result.error
|
|
274
|
+
};
|
|
270
275
|
}
|
|
276
|
+
const preferred = result.value.tweak_values?.[DEVICE_ID_PREFERRED];
|
|
277
|
+
if (!preferred) {
|
|
278
|
+
return {
|
|
279
|
+
status: RemotePreferredTweakStatuses.NOT_CONFIGURED,
|
|
280
|
+
reason: RemotePreferredTweakNotConfiguredReasons.PREFERRED_VALUES_MISSING
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
status: RemotePreferredTweakStatuses.AVAILABLE,
|
|
285
|
+
values: preferred
|
|
286
|
+
};
|
|
271
287
|
}
|
|
272
288
|
async getRemoteStatus(setting) {
|
|
273
289
|
const testClient = new MinioStorageAdapter(setting, this.env);
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import type { RemoteDBStatus } from "../../LiveSyncAbstractReplicator.js";
|
|
2
2
|
import type { BucketSyncSetting } from "../../../common/types.js";
|
|
3
|
+
export declare const JournalStorageReadStatuses: {
|
|
4
|
+
readonly AVAILABLE: "available";
|
|
5
|
+
readonly NOT_FOUND: "not-found";
|
|
6
|
+
readonly UNAVAILABLE: "unavailable";
|
|
7
|
+
};
|
|
8
|
+
export type JournalStorageReadResult<T> = {
|
|
9
|
+
status: typeof JournalStorageReadStatuses.AVAILABLE;
|
|
10
|
+
value: T;
|
|
11
|
+
} | {
|
|
12
|
+
status: typeof JournalStorageReadStatuses.NOT_FOUND;
|
|
13
|
+
} | {
|
|
14
|
+
status: typeof JournalStorageReadStatuses.UNAVAILABLE;
|
|
15
|
+
error: unknown;
|
|
16
|
+
};
|
|
3
17
|
export interface IJournalStorage {
|
|
4
18
|
upload(key: string, data: Uint8Array, mime: string): Promise<boolean>;
|
|
5
19
|
download(key: string, ignoreCache?: boolean): Promise<Uint8Array | false>;
|
|
20
|
+
downloadWithResult(key: string, ignoreCache?: boolean): Promise<JournalStorageReadResult<Uint8Array>>;
|
|
6
21
|
listFiles(from: string, limit?: number): Promise<string[]>;
|
|
7
22
|
deleteFiles(keys: string[]): Promise<boolean>;
|
|
8
23
|
isAvailable(): Promise<boolean>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S3 } from "@aws-sdk/client-s3";
|
|
2
2
|
import { type BucketSyncSetting } from "../../../common/types.js";
|
|
3
3
|
import type { RemoteDBStatus } from "../../LiveSyncAbstractReplicator.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type IJournalStorage, type JournalStorageReadResult } from "./JournalStorageAdapter.js";
|
|
5
5
|
import type { LiveSyncJournalReplicatorEnv } from "../LiveSyncJournalReplicatorEnv.js";
|
|
6
6
|
export declare class MinioStorageAdapter implements IJournalStorage {
|
|
7
7
|
_instance?: S3;
|
|
@@ -13,6 +13,7 @@ export declare class MinioStorageAdapter implements IJournalStorage {
|
|
|
13
13
|
get customHeaders(): [string, string][];
|
|
14
14
|
_getClient(): S3;
|
|
15
15
|
upload(key: string, data: Uint8Array, mime: string): Promise<boolean>;
|
|
16
|
+
downloadWithResult(key: string, ignoreCache?: boolean): Promise<JournalStorageReadResult<Uint8Array>>;
|
|
16
17
|
download(key: string, ignoreCache?: boolean): Promise<Uint8Array | false>;
|
|
17
18
|
listFiles(from: string, limit?: number): Promise<string[]>;
|
|
18
19
|
deleteFiles(keys: string[]): Promise<boolean>;
|
|
@@ -11,6 +11,9 @@ import { ConfiguredRetryStrategy } from "@smithy/util-retry";
|
|
|
11
11
|
import { promiseWithResolvers } from "octagonal-wheels/promises";
|
|
12
12
|
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "../../../common/types.js";
|
|
13
13
|
import { Logger } from "../../../common/logger.js";
|
|
14
|
+
import {
|
|
15
|
+
JournalStorageReadStatuses
|
|
16
|
+
} from "./JournalStorageAdapter.js";
|
|
14
17
|
import { parseHeaderValues } from "../../../common/utils.js";
|
|
15
18
|
import { runWithTrackedPhysicalRequest } from "../../../services/lib/remoteActivity.js";
|
|
16
19
|
class MinioStorageAdapter {
|
|
@@ -110,7 +113,7 @@ class MinioStorageAdapter {
|
|
|
110
113
|
}
|
|
111
114
|
return false;
|
|
112
115
|
}
|
|
113
|
-
async
|
|
116
|
+
async downloadWithResult(key, ignoreCache = false) {
|
|
114
117
|
const client = this._getClient();
|
|
115
118
|
const cmd = new GetObjectCommand({
|
|
116
119
|
Bucket: this._settings.bucket,
|
|
@@ -121,15 +124,31 @@ class MinioStorageAdapter {
|
|
|
121
124
|
return await this.runTrackedRequest(async () => {
|
|
122
125
|
const r = await client.send(cmd);
|
|
123
126
|
if (r.Body) {
|
|
124
|
-
return
|
|
127
|
+
return {
|
|
128
|
+
status: JournalStorageReadStatuses.AVAILABLE,
|
|
129
|
+
value: new Uint8Array(await r.Body.transformToByteArray())
|
|
130
|
+
};
|
|
125
131
|
}
|
|
126
|
-
return
|
|
132
|
+
return {
|
|
133
|
+
status: JournalStorageReadStatuses.UNAVAILABLE,
|
|
134
|
+
error: new Error(`The response body for ${key} was empty`)
|
|
135
|
+
};
|
|
127
136
|
});
|
|
128
137
|
} catch (ex) {
|
|
138
|
+
if (isMissingObjectError(ex)) {
|
|
139
|
+
return { status: JournalStorageReadStatuses.NOT_FOUND };
|
|
140
|
+
}
|
|
129
141
|
Logger(`Could not download ${key}`);
|
|
130
142
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
143
|
+
return {
|
|
144
|
+
status: JournalStorageReadStatuses.UNAVAILABLE,
|
|
145
|
+
error: ex
|
|
146
|
+
};
|
|
131
147
|
}
|
|
132
|
-
|
|
148
|
+
}
|
|
149
|
+
async download(key, ignoreCache = false) {
|
|
150
|
+
const result = await this.downloadWithResult(key, ignoreCache);
|
|
151
|
+
return result.status === JournalStorageReadStatuses.AVAILABLE ? result.value : false;
|
|
133
152
|
}
|
|
134
153
|
async listFiles(from, limit) {
|
|
135
154
|
const client = this._getClient();
|
|
@@ -199,6 +218,12 @@ class MinioStorageAdapter {
|
|
|
199
218
|
}
|
|
200
219
|
}
|
|
201
220
|
}
|
|
221
|
+
function isMissingObjectError(error) {
|
|
222
|
+
if (!error || typeof error !== "object") return false;
|
|
223
|
+
const { name, Code, code } = error;
|
|
224
|
+
const errorCode = Code ?? code ?? name;
|
|
225
|
+
return errorCode === "NoSuchKey" || errorCode === "NotFound";
|
|
226
|
+
}
|
|
202
227
|
export {
|
|
203
228
|
MinioStorageAdapter
|
|
204
229
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RemoteDBSettings, type EntryLeaf, type
|
|
1
|
+
import { type RemoteDBSettings, type EntryLeaf, type RemotePreferredTweakResult, type LOG_LEVEL, type NodeData } from "../../common/types.js";
|
|
2
2
|
import { LiveSyncAbstractReplicator, type LiveSyncReplicatorEnv, type RemoteDBStatus } from "../LiveSyncAbstractReplicator.js";
|
|
3
3
|
import { TrysteroReplicator } from "./TrysteroReplicator.js";
|
|
4
4
|
import { P2PHost, type AcceptanceDecision, type RevokeAcceptanceDecision } from "./TrysteroReplicatorP2PServer.js";
|
|
@@ -81,7 +81,7 @@ export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicat
|
|
|
81
81
|
setPreferredRemoteTweakSettings(_setting: RemoteDBSettings): Promise<void>;
|
|
82
82
|
fetchRemoteChunks(_missingChunks: string[], _showResult: boolean): Promise<false | EntryLeaf[]>;
|
|
83
83
|
getRemoteStatus(_setting: RemoteDBSettings): Promise<false | RemoteDBStatus>;
|
|
84
|
-
getRemotePreferredTweakValues(_setting: RemoteDBSettings): Promise<
|
|
84
|
+
getRemotePreferredTweakValues(_setting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
85
85
|
countCompromisedChunks(): Promise<number>;
|
|
86
86
|
getConnectedDeviceList(_setting?: RemoteDBSettings): Promise<false | {
|
|
87
87
|
node_info: Record<string, NodeData>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Logger } from "../../common/logger.js";
|
|
2
2
|
import {
|
|
3
|
+
RemotePreferredTweakStatuses,
|
|
3
4
|
LOG_LEVEL_NOTICE,
|
|
4
5
|
LOG_LEVEL_INFO,
|
|
5
6
|
LOG_LEVEL_VERBOSE,
|
|
@@ -369,7 +370,7 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
|
369
370
|
"Trying to get tweak values but P2P replication does not support to do this. This operation has been ignored",
|
|
370
371
|
LOG_LEVEL_INFO
|
|
371
372
|
);
|
|
372
|
-
return Promise.resolve(
|
|
373
|
+
return Promise.resolve({ status: RemotePreferredTweakStatuses.UNSUPPORTED });
|
|
373
374
|
}
|
|
374
375
|
countCompromisedChunks() {
|
|
375
376
|
Logger("P2P Replicator cannot count compromised chunks", LOG_LEVEL_VERBOSE);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FetchHttpHandler } from "@smithy/fetch-http-handler";
|
|
2
2
|
import { type LOG_LEVEL } from "octagonal-wheels/common/logger";
|
|
3
|
-
import type { AnyEntry, AUTO_MERGED, CouchDBCredentials, diff_result, DocumentID, EntryDoc, EntryHasPath, FileEventItem, FilePath, FilePathWithPrefix, LoadedEntry, MetaEntry, MISSING_OR_ERROR, ObsidianLiveSyncSettings, RemoteDBSettings, SettingsMigrationState, TweakValues, UXFileInfo, UXFileInfoStub } from "../../common/types.js";
|
|
3
|
+
import type { AnyEntry, AUTO_MERGED, CouchDBCredentials, diff_result, DocumentID, EntryDoc, EntryHasPath, FileEventItem, FilePath, FilePathWithPrefix, LoadedEntry, MetaEntry, MISSING_OR_ERROR, ObsidianLiveSyncSettings, RemoteDBSettings, RemotePreferredTweakResult, SettingsMigrationState, TweakValues, UXFileInfo, UXFileInfoStub } from "../../common/types.js";
|
|
4
4
|
import type { LiveSyncLocalDB } from "../../pouchdb/LiveSyncLocalDB.js";
|
|
5
5
|
import type { LiveSyncAbstractReplicator } from "../../replication/LiveSyncAbstractReplicator.js";
|
|
6
6
|
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
|
@@ -221,7 +221,7 @@ export interface ISettingService {
|
|
|
221
221
|
deleteSmallConfig(key: string): void;
|
|
222
222
|
}
|
|
223
223
|
export interface ITweakValueService {
|
|
224
|
-
fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise<
|
|
224
|
+
fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
225
225
|
checkAndAskResolvingMismatched(preferred: Partial<TweakValues>): Promise<[TweakValues | boolean, boolean]>;
|
|
226
226
|
askResolvingMismatched(preferredSource: TweakValues): Promise<"OK" | "CHECKAGAIN" | "IGNORE">;
|
|
227
227
|
checkAndAskUseRemoteConfiguration(settings: RemoteDBSettings): Promise<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RemoteDBSettings, TweakValues } from "../../common/types.js";
|
|
1
|
+
import type { RemoteDBSettings, RemotePreferredTweakResult, TweakValues } from "../../common/types.js";
|
|
2
2
|
import type { ITweakValueService } from "./IService.js";
|
|
3
3
|
import { ServiceBase, type ServiceContext } from "./ServiceBase.js";
|
|
4
4
|
/**
|
|
@@ -9,7 +9,7 @@ export declare abstract class TweakValueService<T extends ServiceContext = Servi
|
|
|
9
9
|
* Fetch and trial the remote database settings to determine if they are preferred.
|
|
10
10
|
* @param trialSetting The remote database settings to connect.
|
|
11
11
|
*/
|
|
12
|
-
abstract fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise<
|
|
12
|
+
abstract fetchRemotePreferred(trialSetting: RemoteDBSettings): Promise<RemotePreferredTweakResult>;
|
|
13
13
|
/**
|
|
14
14
|
* Check and ask the user to resolve any mismatched tweak values.
|
|
15
15
|
* @param preferred The preferred tweak values to check against.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ServiceContext } from "../../base/ServiceBase.js";
|
|
2
2
|
import { TweakValueService } from "../../base/TweakValueService.js";
|
|
3
3
|
export declare class InjectableTweakValueService<T extends ServiceContext> extends TweakValueService<T> {
|
|
4
|
-
fetchRemotePreferred: import("../../lib/HandlerUtils.js").HandlerFunction<(trialSetting: import("../../../settings.js").RemoteDBSettings) => Promise<import("../../../common/types.js").
|
|
4
|
+
fetchRemotePreferred: import("../../lib/HandlerUtils.js").HandlerFunction<(trialSetting: import("../../../settings.js").RemoteDBSettings) => Promise<import("../../../common/types.js").RemotePreferredTweakResult>, unknown>;
|
|
5
5
|
checkAndAskResolvingMismatched: import("../../lib/HandlerUtils.js").HandlerFunction<(preferred: Partial<import("../../../common/types.js").TweakValues>) => Promise<[import("../../../common/types.js").TweakValues | boolean, boolean]>, unknown>;
|
|
6
6
|
askResolvingMismatched: import("../../lib/HandlerUtils.js").HandlerFunction<(preferredSource: import("../../../common/types.js").TweakValues) => Promise<"OK" | "CHECKAGAIN" | "IGNORE">, unknown>;
|
|
7
7
|
checkAndAskUseRemoteConfiguration: import("../../lib/HandlerUtils.js").HandlerFunction<(settings: import("../../../settings.js").RemoteDBSettings) => Promise<{
|