core-3nweb-client-lib 0.49.7 → 0.50.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/build/api-defs/asmail.d.ts +1 -0
- package/build/api-defs/files.d.ts +1 -1
- package/build/core/asmail/delivery/per-recipient-wip.js +4 -0
- package/build/core/asmail/inbox/index.d.ts +8 -31
- package/build/core/asmail/inbox/index.js +119 -164
- package/build/core/asmail/inbox/msg-indexing/index.js +8 -9
- package/build/core/asmail/inbox/msg-on-disk.d.ts +0 -5
- package/build/core/asmail/inbox/msg-on-disk.js +1 -22
- package/build/core/asmail/index.js +4 -4
- package/build/core/asmail/sending-params/index.d.ts +13 -14
- package/build/core/asmail/sending-params/index.js +15 -35
- package/build/core/asmail/sending-params/invitations-anon.d.ts +7 -31
- package/build/core/asmail/sending-params/invitations-anon.js +77 -127
- package/build/core/asmail/sending-params/own-params.d.ts +5 -25
- package/build/core/asmail/sending-params/own-params.js +144 -97
- package/build/core/asmail/sending-params/params-from-others.d.ts +6 -16
- package/build/core/asmail/sending-params/params-from-others.js +88 -58
- package/build/core/index.d.ts +2 -1
- package/build/core/index.js +4 -4
- package/build/core/keyring/index.js +2 -3
- package/build/core/keyring/introductory-keys/published-intro-key.d.ts +2 -2
- package/build/core/keyring/introductory-keys/published-intro-key.js +71 -71
- package/build/core/keyring/peer-keys/index.js +6 -7
- package/build/core/storage/index.d.ts +2 -1
- package/build/core/storage/index.js +4 -3
- package/build/core/storage/system-folders/index.d.ts +1 -2
- package/build/core/storage/system-folders/index.js +18 -22
- package/build/lib-client/asmail/recipient.d.ts +1 -0
- package/build/lib-client/asmail/recipient.js +11 -0
- package/build/lib-client/fs-utils/fs-sync-utils.d.ts +1 -1
- package/build/lib-client/fs-utils/fs-sync-utils.js +21 -15
- package/build/lib-client/xsp-fs/folder-node.js +13 -3
- package/build/lib-client/xsp-fs/util/file-based-json.js +1 -1
- package/build/lib-common/dataset-sync/per-device-json-array-logs.js +43 -28
- package/build/lib-common/dataset-sync/single-file.d.ts +12 -0
- package/build/lib-common/dataset-sync/single-file.js +73 -0
- package/build/lib-common/dataset-sync/utils.d.ts +16 -0
- package/build/lib-common/dataset-sync/utils.js +72 -0
- package/build/lib-common-on-node/device-fs-places.d.ts +3 -0
- package/build/{lib-client/xsp-fs/util/for-arrays.js → lib-common-on-node/device-fs-places.js} +21 -13
- package/build/tests/computer.3nweb.core/keyrings.js +2 -2
- package/build/tests/libs-for-tests/core-runner.js +2 -1
- package/package.json +1 -1
- package/build/lib-client/xsp-fs/util/for-arrays.d.ts +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2017 - 2018, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2017 - 2018, 2025 - 2026 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -16,46 +16,26 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
19
|
+
exports.makeSendingParamsHolder = makeSendingParamsHolder;
|
|
20
20
|
const params_from_others_1 = require("./params-from-others");
|
|
21
21
|
const own_params_1 = require("./own-params");
|
|
22
22
|
const invitations_anon_1 = require("./invitations-anon");
|
|
23
23
|
const PARAMS_FROM_OTHERS_FILE = 'params-from-others.json';
|
|
24
24
|
const OWN_PARAMS_FILE = 'own-params.json';
|
|
25
25
|
const ANONYM_INVITES_FILE = 'anonymous-invites.json';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.thisSide = {
|
|
35
|
-
getUpdated: this.ownParams.getFor,
|
|
36
|
-
setAsUsed: this.ownParams.setAsInUse
|
|
37
|
-
};
|
|
38
|
-
Object.freeze(this);
|
|
39
|
-
}
|
|
40
|
-
static async makeAndInit(fs, anonInvitesOnServer, random) {
|
|
41
|
-
const [paramsFromOthers, ownParams] = await Promise.all([
|
|
42
|
-
fs.writableFile(PARAMS_FROM_OTHERS_FILE)
|
|
43
|
-
.then(f => params_from_others_1.ParamsFromOthers.makeAndInit(f)),
|
|
44
|
-
fs.writableFile(ANONYM_INVITES_FILE)
|
|
45
|
-
.then(async (anonInvitesFile) => {
|
|
46
|
-
const anonInvites = await invitations_anon_1.AnonymousInvites.makeAndInit(anonInvitesFile, anonInvitesOnServer, random);
|
|
47
|
-
return await own_params_1.OwnSendingParams.makeAndInit(await fs.writableFile(OWN_PARAMS_FILE), anonInvites);
|
|
48
|
-
})
|
|
49
|
-
]);
|
|
50
|
-
await fs.close();
|
|
51
|
-
return new SendingParamsHolder(paramsFromOthers, ownParams);
|
|
52
|
-
}
|
|
53
|
-
async close() {
|
|
54
|
-
await this.ownParams.close();
|
|
55
|
-
await this.paramsFromOthers.close();
|
|
26
|
+
async function makeSendingParamsHolder(fs, anonInvitesOnServer, random) {
|
|
27
|
+
const [otherSides, thisSide] = await Promise.all([
|
|
28
|
+
(0, params_from_others_1.makeParamsFromOthers)(fs, PARAMS_FROM_OTHERS_FILE),
|
|
29
|
+
(0, own_params_1.makeOwnSendingParams)(fs, OWN_PARAMS_FILE, await (0, invitations_anon_1.makeAnonymousInvites)(fs, ANONYM_INVITES_FILE, anonInvitesOnServer, random))
|
|
30
|
+
]);
|
|
31
|
+
async function close() {
|
|
32
|
+
await thisSide.close();
|
|
33
|
+
await otherSides.close();
|
|
56
34
|
}
|
|
35
|
+
return {
|
|
36
|
+
thisSide,
|
|
37
|
+
otherSides,
|
|
38
|
+
close
|
|
39
|
+
};
|
|
57
40
|
}
|
|
58
|
-
exports.SendingParamsHolder = SendingParamsHolder;
|
|
59
|
-
Object.freeze(SendingParamsHolder.prototype);
|
|
60
|
-
Object.freeze(SendingParamsHolder);
|
|
61
41
|
Object.freeze(exports);
|
|
@@ -1,37 +1,13 @@
|
|
|
1
1
|
import { ParamOnServer } from '../../../lib-client/asmail/service-config';
|
|
2
2
|
import { AsyncRNG } from '../../../lib-common/rng-def';
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
msgMaxSize: number;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
export declare class AnonymousInvites {
|
|
13
|
-
private readonly anonInvitesOnServer;
|
|
14
|
-
private readonly random;
|
|
15
|
-
private invites;
|
|
16
|
-
private readonly fileProc;
|
|
17
|
-
private constructor();
|
|
18
|
-
static makeAndInit(file: WritableFile, anonInvitesOnServer: ParamOnServer<'anon-sender/invites'>, random: AsyncRNG): Promise<AnonymousInvites>;
|
|
19
|
-
private onFileEvent;
|
|
20
|
-
protected setFromJSON(json: InvitesJSON): void;
|
|
21
|
-
private toFileJSON;
|
|
22
|
-
private persist;
|
|
23
|
-
private absorbRemoteChanges;
|
|
24
|
-
private toServerParam;
|
|
25
|
-
private toServiceJSON;
|
|
26
|
-
private syncServiceSetting;
|
|
27
|
-
getAll(): Map<string, {
|
|
3
|
+
type WritableFS = web3n.files.WritableFS;
|
|
4
|
+
export type AnonymousInvites = Awaited<ReturnType<typeof makeAnonymousInvites>>;
|
|
5
|
+
export declare function makeAnonymousInvites(fs: WritableFS, fileName: string, anonInvitesOnServer: ParamOnServer<'anon-sender/invites'>, random: AsyncRNG): Promise<{
|
|
6
|
+
create: (label: string, msgMaxSize: number) => Promise<string>;
|
|
7
|
+
getAll: () => Map<string, {
|
|
28
8
|
invite: string;
|
|
29
9
|
msgMaxSize: number;
|
|
30
10
|
}>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
private findByLabel;
|
|
34
|
-
setMsgMaxSize(label: string, msgMaxSize: number): Promise<void>;
|
|
35
|
-
close(): Promise<void>;
|
|
36
|
-
}
|
|
11
|
+
close: () => Promise<void>;
|
|
12
|
+
}>;
|
|
37
13
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2025 - 2026 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -16,160 +16,110 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
20
|
-
const file_based_json_1 = require("../../../lib-client/xsp-fs/util/file-based-json");
|
|
21
|
-
const json_utils_1 = require("../../../lib-common/json-utils");
|
|
19
|
+
exports.makeAnonymousInvites = makeAnonymousInvites;
|
|
22
20
|
const rng_def_1 = require("../../../lib-common/rng-def");
|
|
21
|
+
const single_file_1 = require("../../../lib-common/dataset-sync/single-file");
|
|
23
22
|
const INVITE_TOKEN_LEN = 40;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Object.seal(this);
|
|
31
|
-
}
|
|
32
|
-
static async makeAndInit(file, anonInvitesOnServer, random) {
|
|
33
|
-
const anonInvites = new AnonymousInvites(anonInvitesOnServer, random);
|
|
34
|
-
await anonInvites.fileProc.start(file, () => anonInvites.toFileJSON());
|
|
35
|
-
// XXX these are part of proper syncing logic
|
|
36
|
-
// await anonInvites.absorbRemoteChanges();
|
|
37
|
-
// await anonInvites.syncServiceSetting();
|
|
38
|
-
return anonInvites;
|
|
39
|
-
}
|
|
40
|
-
async onFileEvent(ev) {
|
|
41
|
-
if (ev.src === 'local') {
|
|
42
|
-
return;
|
|
23
|
+
async function makeAnonymousInvites(fs, fileName, anonInvitesOnServer, random) {
|
|
24
|
+
const { file: invitesFile, changeProc } = await (0, single_file_1.initSyncedFile)(fs, fileName, newFile => newFile.writeJSON({ invites: {} }));
|
|
25
|
+
function parseInvitesFromJSON(json) {
|
|
26
|
+
const invites = json.invites;
|
|
27
|
+
if (invites || (typeof invites === 'object')) {
|
|
28
|
+
return invites;
|
|
43
29
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await this.fileProc.order.startOrChain(() => this.absorbRemoteChanges());
|
|
47
|
-
break;
|
|
48
|
-
case 'removed':
|
|
49
|
-
throw new Error(`Unexpected removal of file with parameter "anon-sender/invites"`);
|
|
50
|
-
default:
|
|
51
|
-
return;
|
|
30
|
+
else {
|
|
31
|
+
return {};
|
|
52
32
|
}
|
|
53
33
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
34
|
+
let invites = parseInvitesFromJSON(await invitesFile.readJSON());
|
|
35
|
+
async function onChangeFromOtherDevices(newVersion) {
|
|
36
|
+
changeProc.startOrChain(async () => {
|
|
37
|
+
const { version, json } = await invitesFile.v.readJSON();
|
|
38
|
+
if (version === newVersion) {
|
|
39
|
+
invites = parseInvitesFromJSON(json);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
61
42
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
await
|
|
65
|
-
|
|
43
|
+
function doOnConflict() {
|
|
44
|
+
return changeProc.startOrChain(async () => {
|
|
45
|
+
const { remote, state } = await invitesFile.v.sync.status(false);
|
|
46
|
+
if ((state !== 'conflicting') || !(remote === null || remote === void 0 ? void 0 : remote.latest)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const onRemote = (await invitesFile.v.readJSON({ remoteVersion: remote.latest })).json;
|
|
50
|
+
const numOfInvitesOnRemote = Object.keys(onRemote.invites).length;
|
|
51
|
+
const numOfCurrentInvites = Object.keys(invites).length;
|
|
52
|
+
const joined = { ...onRemote.invites, ...invites };
|
|
53
|
+
const numOfJoined = Object.keys(joined).length;
|
|
54
|
+
if ((numOfCurrentInvites === numOfInvitesOnRemote) && (numOfCurrentInvites === numOfJoined)) {
|
|
55
|
+
await invitesFile.v.sync.adoptRemote({ remoteVersion: remote.latest });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
invites = joined;
|
|
59
|
+
await invitesFile.writeJSON({ invites });
|
|
60
|
+
await invitesFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
|
|
61
|
+
await anonInvitesOnServer.setOnServer(invitesToServerParamForm(invites));
|
|
62
|
+
}
|
|
66
63
|
});
|
|
67
64
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Code from pre-v.sync:
|
|
74
|
-
// const { json } = await this.fileProc.get();
|
|
75
|
-
// this.setFromJSON(json);
|
|
65
|
+
const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(invitesFile, changeProc, onChangeFromOtherDevices, doOnConflict);
|
|
66
|
+
async function persist() {
|
|
67
|
+
await anonInvitesOnServer.setOnServer(invitesToServerParamForm(invites));
|
|
68
|
+
await invitesFile.writeJSON({ invites });
|
|
69
|
+
triggerUpload();
|
|
76
70
|
}
|
|
77
|
-
|
|
71
|
+
function invitesToServerParamForm(invites) {
|
|
78
72
|
const serverParam = {};
|
|
79
|
-
for (const [invite, { msgMaxSize }] of Object.entries(
|
|
73
|
+
for (const [invite, { msgMaxSize }] of Object.entries(invites)) {
|
|
80
74
|
serverParam[invite] = msgMaxSize;
|
|
81
75
|
}
|
|
82
76
|
return serverParam;
|
|
83
77
|
}
|
|
84
|
-
|
|
85
|
-
const serverJSON = {};
|
|
86
|
-
Object.entries(this.invites)
|
|
87
|
-
.forEach(([invite, params]) => {
|
|
88
|
-
serverJSON[invite] = params.msgMaxSize;
|
|
89
|
-
});
|
|
90
|
-
return serverJSON;
|
|
91
|
-
}
|
|
92
|
-
async syncServiceSetting(rethrowConnectExc = false) {
|
|
93
|
-
// XXX we may have the following bug here:
|
|
94
|
-
// Device with older version of param gets to this point, and sets older
|
|
95
|
-
// value.
|
|
96
|
-
// To protect aginst this case, absorbing from file must ensure highest
|
|
97
|
-
// synced version is read.
|
|
98
|
-
try {
|
|
99
|
-
const infoOnServer = await this.anonInvitesOnServer.getFromServer()
|
|
100
|
-
.catch((exc) => {
|
|
101
|
-
if (exc.type === 'connect') {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
throw exc;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
const currentVal = this.toServiceJSON();
|
|
109
|
-
if (!(0, json_utils_1.deepEqual)(infoOnServer, currentVal)) {
|
|
110
|
-
await this.anonInvitesOnServer.setOnServer(currentVal);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch (exc) {
|
|
114
|
-
if (!rethrowConnectExc
|
|
115
|
-
&& (exc.type === 'connect')) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
throw exc;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
getAll() {
|
|
78
|
+
function getAll() {
|
|
122
79
|
const byLabel = new Map();
|
|
123
|
-
Object.entries(
|
|
80
|
+
Object.entries(invites)
|
|
124
81
|
.forEach(([invite, params]) => {
|
|
125
82
|
byLabel.set(params.label, { invite, msgMaxSize: params.msgMaxSize });
|
|
126
83
|
});
|
|
127
84
|
return byLabel;
|
|
128
85
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
86
|
+
function create(label, msgMaxSize) {
|
|
87
|
+
return changeProc.startOrChain(async () => {
|
|
88
|
+
const existingInvite = findByLabel(label);
|
|
89
|
+
if (existingInvite) {
|
|
90
|
+
throw new Error(`Anonymous sender invite already exists with label ${label}`);
|
|
91
|
+
}
|
|
92
|
+
const invite = await generateNewRandomInvite();
|
|
93
|
+
invites[invite] = { label, msgMaxSize };
|
|
94
|
+
try {
|
|
95
|
+
await persist();
|
|
96
|
+
return invite;
|
|
97
|
+
}
|
|
98
|
+
catch (exc) {
|
|
99
|
+
delete invites[invite];
|
|
100
|
+
throw exc;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
145
103
|
}
|
|
146
|
-
|
|
147
|
-
async generateNewRandomInvite() {
|
|
104
|
+
async function generateNewRandomInvite() {
|
|
148
105
|
let invite;
|
|
149
106
|
do {
|
|
150
|
-
invite = await (0, rng_def_1.stringOfB64Chars)(INVITE_TOKEN_LEN,
|
|
151
|
-
} while (
|
|
107
|
+
invite = await (0, rng_def_1.stringOfB64Chars)(INVITE_TOKEN_LEN, random);
|
|
108
|
+
} while (invites[invite]);
|
|
152
109
|
return invite;
|
|
153
110
|
}
|
|
154
|
-
findByLabel(label) {
|
|
155
|
-
const found = Object.entries(
|
|
111
|
+
function findByLabel(label) {
|
|
112
|
+
const found = Object.entries(invites)
|
|
156
113
|
.find(([_, params]) => (params.label === label));
|
|
157
114
|
return (found ? found[0] : undefined);
|
|
158
115
|
}
|
|
159
|
-
async
|
|
160
|
-
|
|
161
|
-
if (!invite) {
|
|
162
|
-
throw new Error(`There is no anonymous sender invite with label ${label}`);
|
|
163
|
-
}
|
|
164
|
-
this.invites[invite].msgMaxSize = msgMaxSize;
|
|
165
|
-
await this.persist();
|
|
166
|
-
}
|
|
167
|
-
;
|
|
168
|
-
async close() {
|
|
169
|
-
await this.fileProc.close();
|
|
116
|
+
async function close() {
|
|
117
|
+
stopFileWatching();
|
|
170
118
|
}
|
|
119
|
+
return {
|
|
120
|
+
create,
|
|
121
|
+
getAll,
|
|
122
|
+
close
|
|
123
|
+
};
|
|
171
124
|
}
|
|
172
|
-
exports.AnonymousInvites = AnonymousInvites;
|
|
173
|
-
Object.freeze(AnonymousInvites.prototype);
|
|
174
|
-
Object.freeze(AnonymousInvites);
|
|
175
125
|
Object.freeze(exports);
|
|
@@ -1,28 +1,8 @@
|
|
|
1
1
|
import { SendingParamsHolder } from './index';
|
|
2
2
|
import { AnonymousInvites } from './invitations-anon';
|
|
3
|
-
type
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* other correspondents for sending messages back. These parameters may have
|
|
9
|
-
* invitation tokens, and this class uses config service to register tokens on
|
|
10
|
-
* a server.
|
|
11
|
-
*/
|
|
12
|
-
export declare class OwnSendingParams {
|
|
13
|
-
private readonly anonInvites;
|
|
14
|
-
private readonly params;
|
|
15
|
-
private defaultParams;
|
|
16
|
-
private readonly fileProc;
|
|
17
|
-
private constructor();
|
|
18
|
-
static makeAndInit(file: WritableFile, anonInvites: AnonymousInvites): Promise<OwnSendingParams>;
|
|
19
|
-
private setDefaultParams;
|
|
20
|
-
private toFileJSON;
|
|
21
|
-
private persist;
|
|
22
|
-
private absorbChangesFromFile;
|
|
23
|
-
protected onFileEvent(ev: FileEvent): Promise<void>;
|
|
24
|
-
getFor: ExposedFuncs['getUpdated'];
|
|
25
|
-
setAsInUse: ExposedFuncs['setAsUsed'];
|
|
26
|
-
close(): Promise<void>;
|
|
27
|
-
}
|
|
3
|
+
type WritableFS = web3n.files.WritableFS;
|
|
4
|
+
export type OwnSendingParams = Awaited<ReturnType<typeof makeOwnSendingParams>>;
|
|
5
|
+
export declare function makeOwnSendingParams(fs: WritableFS, fileName: string, anonInvites: AnonymousInvites): Promise<SendingParamsHolder['thisSide'] & {
|
|
6
|
+
close: () => Promise<void>;
|
|
7
|
+
}>;
|
|
28
8
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2017 - 2018, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2017 - 2018, 2025 - 2026 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -16,126 +16,173 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
20
|
-
const file_based_json_1 = require("../../../lib-client/xsp-fs/util/file-based-json");
|
|
19
|
+
exports.makeOwnSendingParams = makeOwnSendingParams;
|
|
21
20
|
const json_utils_1 = require("../../../lib-common/json-utils");
|
|
21
|
+
const single_file_1 = require("../../../lib-common/dataset-sync/single-file");
|
|
22
22
|
const DEFAULT_INVITE_LABEL = 'Default';
|
|
23
23
|
const DEFAULT_INVITE_MAX_MSG_SIZE = 1024 * 1024 * 1024;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class OwnSendingParams {
|
|
31
|
-
constructor(anonInvites) {
|
|
32
|
-
this.anonInvites = anonInvites;
|
|
33
|
-
this.params = new Map();
|
|
34
|
-
this.defaultParams = undefined;
|
|
35
|
-
this.getFor = async (address) => {
|
|
36
|
-
let p = this.params.get(address);
|
|
37
|
-
if (p) {
|
|
38
|
-
if (p.suggested) {
|
|
39
|
-
return p.suggested;
|
|
40
|
-
}
|
|
41
|
-
else if (p.inUse) {
|
|
42
|
-
return; // undefined, cause params are known to correspondent,
|
|
43
|
-
// and there are no params to suggest for future use.
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// XXX Or, instead, should we set defaultParams?
|
|
47
|
-
if (!this.defaultParams) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
p = {
|
|
51
|
-
address,
|
|
52
|
-
suggested: (0, json_utils_1.copy)(this.defaultParams)
|
|
53
|
-
};
|
|
54
|
-
p.suggested.timestamp = Date.now();
|
|
55
|
-
this.params.set(p.address, p);
|
|
56
|
-
await this.fileProc.order.startOrChain(() => this.persist());
|
|
57
|
-
return p.suggested;
|
|
58
|
-
};
|
|
59
|
-
this.setAsInUse = async (address, invite) => {
|
|
60
|
-
await this.fileProc.order.startOrChain(async () => {
|
|
61
|
-
const p = this.params.get(address);
|
|
62
|
-
if (!p || !p.suggested) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (p.suggested.invitation !== invite) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
p.inUse = p.suggested;
|
|
69
|
-
p.suggested = undefined;
|
|
70
|
-
await this.persist();
|
|
71
|
-
});
|
|
72
|
-
};
|
|
73
|
-
this.fileProc = new file_based_json_1.JsonFileProc(this.onFileEvent.bind(this));
|
|
74
|
-
Object.seal(this);
|
|
24
|
+
async function makeOwnSendingParams(fs, fileName, anonInvites) {
|
|
25
|
+
let params = {};
|
|
26
|
+
let defaultParams = undefined;
|
|
27
|
+
const { file: paramsFile, changeProc } = await (0, single_file_1.initSyncedFile)(fs, fileName, newFile => newFile.writeJSON(currentToFileJSON()));
|
|
28
|
+
if (!paramsFile.isNew) {
|
|
29
|
+
({ defaultParams, params } = parseFromJSON(await paramsFile.readJSON()));
|
|
75
30
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
await
|
|
79
|
-
await ownParams.absorbChangesFromFile();
|
|
80
|
-
if (!ownParams.defaultParams) {
|
|
81
|
-
await ownParams.setDefaultParams();
|
|
82
|
-
}
|
|
83
|
-
return ownParams;
|
|
31
|
+
const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(paramsFile, changeProc, onChangeFromOtherDevices, doOnConflict);
|
|
32
|
+
if (paramsFile.isNew) {
|
|
33
|
+
await setDefaultParams();
|
|
84
34
|
}
|
|
85
|
-
async setDefaultParams() {
|
|
86
|
-
await
|
|
87
|
-
const invites =
|
|
35
|
+
async function setDefaultParams() {
|
|
36
|
+
await changeProc.startOrChain(async () => {
|
|
37
|
+
const invites = anonInvites.getAll();
|
|
88
38
|
const defaultInvite = invites.get(DEFAULT_INVITE_LABEL);
|
|
89
39
|
if (defaultInvite) {
|
|
90
|
-
|
|
40
|
+
defaultParams = {
|
|
91
41
|
timestamp: 0,
|
|
92
42
|
invitation: defaultInvite.invite
|
|
93
43
|
};
|
|
94
44
|
}
|
|
95
45
|
else {
|
|
96
|
-
const invitation = await
|
|
97
|
-
|
|
46
|
+
const invitation = await anonInvites.create(DEFAULT_INVITE_LABEL, DEFAULT_INVITE_MAX_MSG_SIZE);
|
|
47
|
+
defaultParams = {
|
|
98
48
|
timestamp: 0,
|
|
99
49
|
invitation
|
|
100
50
|
};
|
|
101
51
|
}
|
|
102
|
-
await
|
|
52
|
+
await persist();
|
|
103
53
|
});
|
|
104
54
|
}
|
|
105
|
-
|
|
55
|
+
function currentToFileJSON() {
|
|
106
56
|
return {
|
|
107
|
-
default:
|
|
108
|
-
senderSpecific:
|
|
57
|
+
default: defaultParams,
|
|
58
|
+
senderSpecific: Object.values(params)
|
|
109
59
|
};
|
|
110
60
|
}
|
|
111
|
-
async persist() {
|
|
112
|
-
await
|
|
113
|
-
|
|
114
|
-
async absorbChangesFromFile() {
|
|
115
|
-
const { json } = await this.fileProc.get(false);
|
|
116
|
-
// we may add checks to json data
|
|
117
|
-
this.params.clear();
|
|
118
|
-
json.senderSpecific.forEach(p => this.params.set(p.address, p));
|
|
119
|
-
this.defaultParams = json.default;
|
|
61
|
+
async function persist() {
|
|
62
|
+
await paramsFile.writeJSON(currentToFileJSON());
|
|
63
|
+
triggerUpload();
|
|
120
64
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
65
|
+
function parseFromJSON(json) {
|
|
66
|
+
const params = {};
|
|
67
|
+
for (const p of json.senderSpecific) {
|
|
68
|
+
params[p.address] = p;
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
70
|
+
return {
|
|
71
|
+
defaultParams: json.default,
|
|
72
|
+
params
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function onChangeFromOtherDevices(newVersion) {
|
|
76
|
+
return changeProc.startOrChain(async () => {
|
|
77
|
+
const { version, json } = await paramsFile.v.readJSON();
|
|
78
|
+
if (version === newVersion) {
|
|
79
|
+
({ defaultParams, params } = parseFromJSON(json));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function doOnConflict() {
|
|
84
|
+
return changeProc.startOrChain(async () => {
|
|
85
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
86
|
+
const { remote, state } = await paramsFile.v.sync.status(false);
|
|
87
|
+
if ((state !== 'conflicting') || !(remote === null || remote === void 0 ? void 0 : remote.latest)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const onRemote = parseFromJSON((await paramsFile.v.readJSON({ remoteVersion: remote.latest })).json);
|
|
91
|
+
let uploadLocal = false;
|
|
92
|
+
if (!onRemote.defaultParams && defaultParams) {
|
|
93
|
+
uploadLocal = true;
|
|
94
|
+
}
|
|
95
|
+
else if (onRemote.defaultParams && !defaultParams) {
|
|
96
|
+
defaultParams = onRemote.defaultParams;
|
|
97
|
+
}
|
|
98
|
+
else if (onRemote.defaultParams && defaultParams) {
|
|
99
|
+
if (onRemote.defaultParams.timestamp >= defaultParams.timestamp) {
|
|
100
|
+
defaultParams = onRemote.defaultParams;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
uploadLocal = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const [addr, p] of Object.entries(params)) {
|
|
107
|
+
const remP = onRemote.params[addr];
|
|
108
|
+
if (!remP) {
|
|
109
|
+
uploadLocal = true;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if ((0, json_utils_1.deepEqual)(p, remP)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const tsP = Math.max((_b = (_a = p === null || p === void 0 ? void 0 : p.inUse) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : 0, (_d = (_c = p === null || p === void 0 ? void 0 : p.suggested) === null || _c === void 0 ? void 0 : _c.timestamp) !== null && _d !== void 0 ? _d : 0);
|
|
116
|
+
const tsRem = Math.max((_f = (_e = remP === null || remP === void 0 ? void 0 : remP.inUse) === null || _e === void 0 ? void 0 : _e.timestamp) !== null && _f !== void 0 ? _f : 0, (_h = (_g = remP === null || remP === void 0 ? void 0 : remP.suggested) === null || _g === void 0 ? void 0 : _g.timestamp) !== null && _h !== void 0 ? _h : 0);
|
|
117
|
+
if (tsP > tsRem) {
|
|
118
|
+
uploadLocal = true;
|
|
119
|
+
}
|
|
120
|
+
else if (tsP < tsRem) {
|
|
121
|
+
params[addr] = remP;
|
|
122
|
+
}
|
|
123
|
+
else if (tsP !== 0) {
|
|
124
|
+
if (((_j = remP.inUse) === null || _j === void 0 ? void 0 : _j.timestamp) === tsP) {
|
|
125
|
+
params[addr] = remP;
|
|
126
|
+
}
|
|
127
|
+
else if (((_k = p.inUse) === null || _k === void 0 ? void 0 : _k.timestamp) === tsP) {
|
|
128
|
+
uploadLocal = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (uploadLocal) {
|
|
133
|
+
await paramsFile.writeJSON(currentToFileJSON());
|
|
134
|
+
await paramsFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
await paramsFile.v.sync.adoptRemote({ remoteVersion: remote.latest });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async function getUpdated(address) {
|
|
142
|
+
return changeProc.startOrChain(async () => {
|
|
143
|
+
let p = params[address];
|
|
144
|
+
if (p) {
|
|
145
|
+
if (p.suggested) {
|
|
146
|
+
return p.suggested;
|
|
147
|
+
}
|
|
148
|
+
else if (p.inUse) {
|
|
149
|
+
return; // undefined, cause params are known to correspondent,
|
|
150
|
+
// and there are no params to suggest for future use.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// XXX Or, instead, should we set defaultParams?
|
|
154
|
+
if (!defaultParams) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
p = {
|
|
158
|
+
address,
|
|
159
|
+
suggested: (0, json_utils_1.copy)(defaultParams)
|
|
160
|
+
};
|
|
161
|
+
p.suggested.timestamp = Date.now();
|
|
162
|
+
params[p.address] = p;
|
|
163
|
+
await persist();
|
|
164
|
+
return p.suggested;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function setAsUsed(address, invite) {
|
|
168
|
+
return changeProc.startOrChain(async () => {
|
|
169
|
+
const p = params[address];
|
|
170
|
+
if (!(p === null || p === void 0 ? void 0 : p.suggested) || (p.suggested.invitation !== invite)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
p.inUse = p.suggested;
|
|
174
|
+
p.suggested = undefined;
|
|
175
|
+
await persist();
|
|
176
|
+
});
|
|
132
177
|
}
|
|
133
|
-
async close() {
|
|
134
|
-
|
|
135
|
-
|
|
178
|
+
async function close() {
|
|
179
|
+
anonInvites.close();
|
|
180
|
+
stopFileWatching();
|
|
136
181
|
}
|
|
182
|
+
return {
|
|
183
|
+
close,
|
|
184
|
+
getUpdated,
|
|
185
|
+
setAsUsed
|
|
186
|
+
};
|
|
137
187
|
}
|
|
138
|
-
exports.OwnSendingParams = OwnSendingParams;
|
|
139
|
-
Object.freeze(OwnSendingParams.prototype);
|
|
140
|
-
Object.freeze(OwnSendingParams);
|
|
141
188
|
Object.freeze(exports);
|