core-3nweb-client-lib 0.50.3 → 0.50.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/build/api-defs/asmail.d.ts +1 -0
- package/build/core/asmail/inbox/inbox-events.js +7 -10
- package/build/core/asmail/inbox/index.js +10 -3
- package/build/core/asmail/inbox/msg-downloader.d.ts +1 -1
- package/build/core/asmail/inbox/msg-downloader.js +13 -16
- package/build/core/asmail/inbox/msg-indexing/dataset/v1/sql-db.js +1 -1
- package/build/core/asmail/sending-params/params-from-others.js +4 -1
- package/build/core/keyring/peer-keys/dataset/v2/peer-keys-db.js +1 -2
- package/build/lib-client/asmail/recipient.d.ts +1 -1
- package/build/lib-client/asmail/recipient.js +5 -3
- package/build/tests/caps-api/asmail/specs/send-without-attachments.js +58 -2
- package/build/tests/caps-api/asmail/test-utils.d.ts +2 -0
- package/build/tests/caps-api/asmail/test-utils.js +35 -0
- package/package.json +1 -1
|
@@ -87,16 +87,13 @@ class InboxEvents {
|
|
|
87
87
|
async whenConnected() {
|
|
88
88
|
return this.msgReceiver.connectedState.whenStateIsSet();
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// await this.rmMsg(msgId).catch(noop);
|
|
98
|
-
await this.logError(err, `Cannot get message ${msgId}`);
|
|
99
|
-
}
|
|
90
|
+
getMessage(msgId) {
|
|
91
|
+
return this.getMsg(msgId).catch(async (exc) => {
|
|
92
|
+
if ((exc.type === 'connect') || (exc.type === 'inbox')) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
await this.logError(exc, `Cannot get message ${msgId}`);
|
|
96
|
+
});
|
|
100
97
|
}
|
|
101
98
|
subscribe(event, observer) {
|
|
102
99
|
if (event === 'message') {
|
|
@@ -83,7 +83,7 @@ async function makeInboxOnServer(cachePath, syncedFS, localFS, r) {
|
|
|
83
83
|
if (msgOnDisk) {
|
|
84
84
|
return msgOnDisk;
|
|
85
85
|
}
|
|
86
|
-
const meta = await downloader.getMsgMeta(msgId);
|
|
86
|
+
const meta = await downloader.getMsgMeta(msgId, false);
|
|
87
87
|
return await cache.addMsg(msgId, meta);
|
|
88
88
|
}
|
|
89
89
|
function checkerOfMidKeyCerts(deliveryTS) {
|
|
@@ -201,7 +201,9 @@ async function makeInboxOnServer(cachePath, syncedFS, localFS, r) {
|
|
|
201
201
|
}
|
|
202
202
|
await Promise.all(msgIds.map(msgId => startCachingAndAddKeyToIndex(msgId)
|
|
203
203
|
.catch(async (exc) => {
|
|
204
|
-
|
|
204
|
+
if (!exc.incompleteDelivery && !exc.msgNotFound) {
|
|
205
|
+
await logError(exc, `Failed to start caching message ${msgId}`);
|
|
206
|
+
}
|
|
205
207
|
})));
|
|
206
208
|
return index.listMsgs(fromTS);
|
|
207
209
|
});
|
|
@@ -220,7 +222,12 @@ async function makeInboxOnServer(cachePath, syncedFS, localFS, r) {
|
|
|
220
222
|
return [];
|
|
221
223
|
}
|
|
222
224
|
// cache and index these
|
|
223
|
-
await Promise.all(msgIds.map(msgId => startCachingAndAddKeyToIndex(msgId)
|
|
225
|
+
await Promise.all(msgIds.map(msgId => startCachingAndAddKeyToIndex(msgId)
|
|
226
|
+
.catch(async (exc) => {
|
|
227
|
+
if (!exc.incompleteDelivery && !exc.msgNotFound) {
|
|
228
|
+
await logError(exc, `Failed to start caching message ${msgId}`);
|
|
229
|
+
}
|
|
230
|
+
})));
|
|
224
231
|
// get info's from index, focusing on specific messages only
|
|
225
232
|
return (await index.listMsgs(fromTS)).filter(({ msgId }) => msgIds.includes(msgId));
|
|
226
233
|
}
|
|
@@ -5,7 +5,7 @@ export declare class MsgDownloader {
|
|
|
5
5
|
private readonly msgReceiver;
|
|
6
6
|
private readonly runner;
|
|
7
7
|
constructor(msgReceiver: MailRecipient);
|
|
8
|
-
getMsgMeta(msgId: string): Promise<MsgMeta>;
|
|
8
|
+
getMsgMeta(msgId: string, allowIncomplete: boolean): Promise<MsgMeta>;
|
|
9
9
|
getObjDownloader(msgId: string): ObjDownloader;
|
|
10
10
|
private getLayoutWithHeaderAndFirstSegs;
|
|
11
11
|
private getSegs;
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.MsgDownloader = void 0;
|
|
20
|
+
const recipient_1 = require("../../../lib-client/asmail/recipient");
|
|
20
21
|
const obj_on_disk_1 = require("../../../lib-client/objs-on-disk/obj-on-disk");
|
|
21
|
-
const sleep_1 = require("../../../lib-common/processes/sleep");
|
|
22
22
|
const MAX_GETTING_CHUNK = 512 * 1024;
|
|
23
23
|
const DOWNLOAD_START_CHUNK = 128 * 1024;
|
|
24
24
|
class MsgDownloader {
|
|
@@ -27,23 +27,19 @@ class MsgDownloader {
|
|
|
27
27
|
this.runner = new obj_on_disk_1.DownloadsRunner();
|
|
28
28
|
Object.freeze(this);
|
|
29
29
|
}
|
|
30
|
-
async getMsgMeta(msgId) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw exc;
|
|
30
|
+
async getMsgMeta(msgId, allowIncomplete) {
|
|
31
|
+
return await this.msgReceiver.getMsgMeta(msgId, allowIncomplete)
|
|
32
|
+
.catch(async (exc) => {
|
|
33
|
+
if (exc.incompleteDelivery) {
|
|
34
|
+
// cleanout old incomplete messages
|
|
35
|
+
const deliveryStart = exc.deliveryStart;
|
|
36
|
+
if (!(Math.abs(Date.now() - deliveryStart) < 12 * 60 * 60 * 1000)) {
|
|
37
|
+
await this.msgReceiver.removeMsg(msgId).catch(noop);
|
|
38
|
+
throw (0, recipient_1.makeMsgNotFoundException)(msgId);
|
|
42
39
|
}
|
|
43
40
|
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
throw lastExc;
|
|
41
|
+
throw exc;
|
|
42
|
+
});
|
|
47
43
|
}
|
|
48
44
|
getObjDownloader(msgId) {
|
|
49
45
|
return {
|
|
@@ -68,4 +64,5 @@ class MsgDownloader {
|
|
|
68
64
|
exports.MsgDownloader = MsgDownloader;
|
|
69
65
|
Object.freeze(MsgDownloader.prototype);
|
|
70
66
|
Object.freeze(MsgDownloader);
|
|
67
|
+
function noop() { }
|
|
71
68
|
Object.freeze(exports);
|
|
@@ -192,7 +192,7 @@ async function setMsgIndexInfoIntoAttrOf(dbFile, info) {
|
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
function dbFileName(shardTS) {
|
|
195
|
-
return (shardTS ?
|
|
195
|
+
return (shardTS ? `${shardTS}${DB_EXT}` : LATEST_DB);
|
|
196
196
|
}
|
|
197
197
|
function shardTSFromFileName(fName) {
|
|
198
198
|
if (fName.endsWith(DB_EXT)) {
|
|
@@ -68,7 +68,10 @@ async function makeParamsFromOthers(fs, fileName) {
|
|
|
68
68
|
let paramsWhereUpdated = (numExistingRecs > numRemRecs);
|
|
69
69
|
for (const [address, inP] of Object.entries(onRemote)) {
|
|
70
70
|
const existing = params[address];
|
|
71
|
-
if (existing
|
|
71
|
+
if (!existing) {
|
|
72
|
+
params[address] = inP;
|
|
73
|
+
}
|
|
74
|
+
else if (existing.timestamp < inP.timestamp) {
|
|
72
75
|
params[address] = inP;
|
|
73
76
|
paramsWhereUpdated = true;
|
|
74
77
|
}
|
|
@@ -94,8 +94,7 @@ const queryToCreatePeerKeysDbV2 = [
|
|
|
94
94
|
msgMasterKeyAlg TEXT NOT NULL,
|
|
95
95
|
msgMasterKey BLOB NOT NULL,
|
|
96
96
|
--
|
|
97
|
-
PRIMARY KEY (peerCAddr, recipientKId, peerKId)
|
|
98
|
-
UNIQUE (peerCAddr, recipientKId) ON CONFLICT FAIL
|
|
97
|
+
PRIMARY KEY (peerCAddr, recipientKId, peerKId)
|
|
99
98
|
)
|
|
100
99
|
`,
|
|
101
100
|
`--sql
|
|
@@ -5,7 +5,7 @@ import { SubscribingClient } from '../../lib-common/ipc/ws-ipc';
|
|
|
5
5
|
type InboxException = web3n.asmail.InboxException;
|
|
6
6
|
type Observer<T> = web3n.Observer<T>;
|
|
7
7
|
export declare function makeMsgNotFoundException(msgId: string): InboxException;
|
|
8
|
-
export declare function makeMsgIncompleteException(msgId: string): InboxException;
|
|
8
|
+
export declare function makeMsgIncompleteException(msgId: string, deliveryStart: number): InboxException;
|
|
9
9
|
export declare function makeFailToDecryptMsgException(msgId: string): InboxException;
|
|
10
10
|
export declare function makeObjNotFoundException(msgId: string, objId: string): InboxException;
|
|
11
11
|
export declare function makeMsgIsBrokenException(msgId: string): InboxException;
|
|
@@ -39,12 +39,13 @@ function makeMsgNotFoundException(msgId) {
|
|
|
39
39
|
};
|
|
40
40
|
return exc;
|
|
41
41
|
}
|
|
42
|
-
function makeMsgIncompleteException(msgId) {
|
|
42
|
+
function makeMsgIncompleteException(msgId, deliveryStart) {
|
|
43
43
|
const exc = {
|
|
44
44
|
runtimeException: true,
|
|
45
45
|
type: 'inbox',
|
|
46
46
|
msgId,
|
|
47
47
|
incompleteDelivery: true,
|
|
48
|
+
deliveryStart,
|
|
48
49
|
stack: (0, runtime_1.getStackHere)(1)
|
|
49
50
|
};
|
|
50
51
|
return exc;
|
|
@@ -116,8 +117,9 @@ class MailRecipient extends user_with_mid_session_1.ServiceUser {
|
|
|
116
117
|
responseType: 'json'
|
|
117
118
|
});
|
|
118
119
|
if (rep.status === api.msgMetadata.SC.ok) {
|
|
119
|
-
if (!
|
|
120
|
-
|
|
120
|
+
if (!rep.data.deliveryCompletion && !allowIncomplete) {
|
|
121
|
+
const { deliveryStart } = rep.data;
|
|
122
|
+
throw makeMsgIncompleteException(msgId, deliveryStart);
|
|
121
123
|
}
|
|
122
124
|
const { meta, errMsg } = api.sanitizedMeta(rep.data, allowIncomplete);
|
|
123
125
|
if (!meta) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2016 - 2018, 2020 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2016 - 2018, 2020, 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
|
|
@@ -24,7 +24,7 @@ exports.specs = {
|
|
|
24
24
|
description: '.sendMsg',
|
|
25
25
|
its: []
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
let it = {
|
|
28
28
|
expectation: 'send message to existing address and get it'
|
|
29
29
|
};
|
|
30
30
|
it.func = async function (s) {
|
|
@@ -87,4 +87,60 @@ it.func = async function (s) {
|
|
|
87
87
|
await u2_w3n.mail.inbox.removeMsg(msgId); // second call is a noop
|
|
88
88
|
};
|
|
89
89
|
exports.specs.its.push(it);
|
|
90
|
+
it = {
|
|
91
|
+
expectation: 'send lots of messages with sendImmediately flag set true',
|
|
92
|
+
timeout: 20000
|
|
93
|
+
};
|
|
94
|
+
it.func = async function (s) {
|
|
95
|
+
const u1_w3n = s.testAppCapsByUserIndex(0);
|
|
96
|
+
const u2 = s.users[1];
|
|
97
|
+
const u2_w3n = s.testAppCapsByUserIndex(1);
|
|
98
|
+
const totalNumOfTestMsgs = 30;
|
|
99
|
+
const recipient = u2.userId;
|
|
100
|
+
const msgsFromRecipient = (0, test_utils_1.getMsgsFrom)(u2_w3n.mail.inbox, totalNumOfTestMsgs);
|
|
101
|
+
const receivedMsgs = new Array(totalNumOfTestMsgs);
|
|
102
|
+
const watchingInboxOfU2 = (async function () {
|
|
103
|
+
for await (const msg of msgsFromRecipient) {
|
|
104
|
+
const i = msg.jsonBody.testMsgNum;
|
|
105
|
+
receivedMsgs[i] = msg;
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
const idForSendingPrefix = `${Date.now()}`;
|
|
109
|
+
const notifs = [];
|
|
110
|
+
const deliveryProcesses = [];
|
|
111
|
+
for (let i = 0; i < totalNumOfTestMsgs; i += 1) {
|
|
112
|
+
const idForSending = `${idForSendingPrefix}-${i}`;
|
|
113
|
+
const msgNotifs = [];
|
|
114
|
+
notifs.push(msgNotifs);
|
|
115
|
+
const outMsg = {
|
|
116
|
+
msgType: 'mail',
|
|
117
|
+
jsonBody: {
|
|
118
|
+
testMsgNum: i
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
await u1_w3n.mail.delivery.addMsg([recipient], outMsg, idForSending, {
|
|
122
|
+
sendImmediately: true,
|
|
123
|
+
retryRecipient: { numOfAttempts: 2, timeBetweenAttempts: 1000 }
|
|
124
|
+
});
|
|
125
|
+
const msgDeliveryProc = new Promise((resolve, reject) => {
|
|
126
|
+
u1_w3n.mail.delivery.observeDelivery(idForSending, {
|
|
127
|
+
next: p => msgNotifs.push(p),
|
|
128
|
+
complete: resolve,
|
|
129
|
+
error: reject
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
deliveryProcesses.push(msgDeliveryProc);
|
|
133
|
+
}
|
|
134
|
+
await Promise.allSettled(deliveryProcesses);
|
|
135
|
+
await watchingInboxOfU2;
|
|
136
|
+
for (let i = 0; i < totalNumOfTestMsgs; i += 1) {
|
|
137
|
+
const msgDeliveryNotifs = notifs[i];
|
|
138
|
+
expect(msgDeliveryNotifs.length).toBeGreaterThan(0);
|
|
139
|
+
const last = msgDeliveryNotifs[msgDeliveryNotifs.length - 1];
|
|
140
|
+
expect(last.allDone).withContext(`message ${i} should've been sent without errors`).toBe('all-ok');
|
|
141
|
+
const msg = receivedMsgs[i];
|
|
142
|
+
expect(msg.jsonBody.testMsgNum).withContext(`message ${i} should've been received`).toBe(i);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.specs.its.push(it);
|
|
90
146
|
Object.freeze(exports);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SpecIt as GenericSpecIt } from "../../libs-for-tests/spec-module";
|
|
2
2
|
import { MultiUserSetup } from "../../libs-for-tests/setups";
|
|
3
|
+
type InboxService = web3n.asmail.InboxService;
|
|
3
4
|
type commonW3N = web3n.caps.common.W3N;
|
|
4
5
|
/**
|
|
5
6
|
* This function to be run in renderer's context via execExpects
|
|
@@ -9,4 +10,5 @@ type commonW3N = web3n.caps.common.W3N;
|
|
|
9
10
|
export declare function sendTxtMsg(w3n: commonW3N, recipient: string, txtBody: string): Promise<string>;
|
|
10
11
|
export type SpecIt = GenericSpecIt<MultiUserSetup>;
|
|
11
12
|
export declare function throwDeliveryErrorFrom(lastNotif: web3n.asmail.DeliveryProgress): void;
|
|
13
|
+
export declare function getMsgsFrom(inbox: InboxService, numOfMsgsToGet: number): AsyncGenerator<web3n.asmail.IncomingMessage, void, unknown>;
|
|
12
14
|
export {};
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.sendTxtMsg = sendTxtMsg;
|
|
20
20
|
exports.throwDeliveryErrorFrom = throwDeliveryErrorFrom;
|
|
21
|
+
exports.getMsgsFrom = getMsgsFrom;
|
|
21
22
|
const assert_1 = require("../../../lib-common/assert");
|
|
22
23
|
const error_1 = require("../../../lib-common/exceptions/error");
|
|
24
|
+
const deferred_1 = require("../../../lib-common/processes/deferred");
|
|
23
25
|
/**
|
|
24
26
|
* This function to be run in renderer's context via execExpects
|
|
25
27
|
* @param recipient
|
|
@@ -58,3 +60,36 @@ function throwDeliveryErrorFrom(lastNotif) {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
}
|
|
63
|
+
async function* getMsgsFrom(inbox, numOfMsgsToGet) {
|
|
64
|
+
let msgCounter = 0;
|
|
65
|
+
let expectedMsg = (0, deferred_1.defer)();
|
|
66
|
+
const unsub = inbox.subscribe('message', {
|
|
67
|
+
next: msg => {
|
|
68
|
+
expectedMsg === null || expectedMsg === void 0 ? void 0 : expectedMsg.resolve(msg);
|
|
69
|
+
msgCounter += 1;
|
|
70
|
+
expectedMsg = ((msgCounter < numOfMsgsToGet) ? (0, deferred_1.defer)() : undefined);
|
|
71
|
+
},
|
|
72
|
+
error: err => {
|
|
73
|
+
expectedMsg === null || expectedMsg === void 0 ? void 0 : expectedMsg.reject(err);
|
|
74
|
+
expectedMsg = undefined;
|
|
75
|
+
},
|
|
76
|
+
complete: () => {
|
|
77
|
+
expectedMsg === null || expectedMsg === void 0 ? void 0 : expectedMsg.resolve(undefined);
|
|
78
|
+
expectedMsg = undefined;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
try {
|
|
82
|
+
while (expectedMsg) {
|
|
83
|
+
const msg = await (expectedMsg === null || expectedMsg === void 0 ? void 0 : expectedMsg.promise);
|
|
84
|
+
if (msg) {
|
|
85
|
+
yield msg;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
unsub();
|
|
94
|
+
}
|
|
95
|
+
}
|