@wireapp/core 42.9.2 → 42.9.3
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/lib/Account.d.ts +2 -0
- package/lib/Account.d.ts.map +1 -1
- package/lib/Account.js +17 -1
- package/lib/conversation/ConversationService/ConversationService.js +3 -3
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.js +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts +7 -5
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.js +11 -11
- package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +9 -1
- package/lib/storage/CoreDB.d.ts +7 -0
- package/lib/storage/CoreDB.d.ts.map +1 -1
- package/lib/storage/CoreDB.js +3 -1
- package/lib/testUtils/index.d.ts +1 -0
- package/lib/testUtils/index.d.ts.map +1 -1
- package/lib/testUtils/index.js +9 -1
- package/lib/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.test.js +7 -14
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.d.ts +12 -3
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.d.ts.map +1 -1
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.js +35 -28
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.test.js +36 -19
- package/lib/util/TaskScheduler/TaskScheduler.d.ts +1 -1
- package/lib/util/TaskScheduler/TaskScheduler.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/Account.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { HandledEventPayload, NotificationService, NotificationSource } from './
|
|
|
18
18
|
import { SelfService } from './self/';
|
|
19
19
|
import { TeamService } from './team/';
|
|
20
20
|
import { UserService } from './user/';
|
|
21
|
+
import { RecurringTaskScheduler } from './util/RecurringTaskScheduler';
|
|
21
22
|
export type ProcessedEventPayload = HandledEventPayload;
|
|
22
23
|
export declare enum EVENTS {
|
|
23
24
|
/**
|
|
@@ -87,6 +88,7 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
87
88
|
user: UserService;
|
|
88
89
|
};
|
|
89
90
|
backendFeatures: BackendFeatures;
|
|
91
|
+
recurringTaskScheduler: RecurringTaskScheduler;
|
|
90
92
|
/**
|
|
91
93
|
* @param apiClient The apiClient instance to use in the core (will create a new new one if undefined)
|
|
92
94
|
* @param accountOptions
|
package/lib/Account.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,YAAY,EAGZ,OAAO,EACP,MAAM,EAEN,SAAS,EACV,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAuB,UAAU,EAAE,gBAAgB,EAAC,MAAM,iCAAiC,CAAC;AACnG,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AAOxD,OAAO,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAC,UAAU,EAAe,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAC,cAAc,EAAC,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,UAAU,EAAE,aAAa,EAAC,MAAM,WAAW,CAAC;AACpD,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAAC,YAAY,EAAC,MAAM,UAAU,CAAC;AACtC,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAC,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAC,SAAS,EAAE,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAC,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAEpC,OAAO,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AACpC,OAAO,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"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"}
|
package/lib/Account.js
CHANGED
|
@@ -56,6 +56,7 @@ const self_1 = require("./self/");
|
|
|
56
56
|
const CoreDB_1 = require("./storage/CoreDB");
|
|
57
57
|
const team_1 = require("./team/");
|
|
58
58
|
const user_1 = require("./user/");
|
|
59
|
+
const RecurringTaskScheduler_1 = require("./util/RecurringTaskScheduler");
|
|
59
60
|
var EVENTS;
|
|
60
61
|
(function (EVENTS) {
|
|
61
62
|
/**
|
|
@@ -92,6 +93,21 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
92
93
|
this.cryptoProtocolConfig = cryptoProtocolConfig;
|
|
93
94
|
this.nbPrekeys = nbPrekeys;
|
|
94
95
|
this.createStore = createStore;
|
|
96
|
+
this.recurringTaskScheduler = new RecurringTaskScheduler_1.RecurringTaskScheduler({
|
|
97
|
+
get: async (key) => {
|
|
98
|
+
var _a;
|
|
99
|
+
const task = await ((_a = this.db) === null || _a === void 0 ? void 0 : _a.get('recurringTasks', key));
|
|
100
|
+
return task === null || task === void 0 ? void 0 : task.firingDate;
|
|
101
|
+
},
|
|
102
|
+
set: async (key, timestamp) => {
|
|
103
|
+
var _a;
|
|
104
|
+
await ((_a = this.db) === null || _a === void 0 ? void 0 : _a.put('recurringTasks', { key, firingDate: timestamp }, key));
|
|
105
|
+
},
|
|
106
|
+
delete: async (key) => {
|
|
107
|
+
var _a;
|
|
108
|
+
await ((_a = this.db) === null || _a === void 0 ? void 0 : _a.delete('recurringTasks', key));
|
|
109
|
+
},
|
|
110
|
+
});
|
|
95
111
|
apiClient.on(api_client_1.APIClient.TOPIC.COOKIE_REFRESH, async (cookie) => {
|
|
96
112
|
if (cookie && this.storeEngine) {
|
|
97
113
|
try {
|
|
@@ -260,7 +276,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
260
276
|
const cryptoClientDef = await this.buildCryptoClient(context, this.storeEngine, enableMLS);
|
|
261
277
|
const [clientType, cryptoClient] = cryptoClientDef;
|
|
262
278
|
const mlsService = clientType === CryptoClient_1.CryptoClientType.CORE_CRYPTO && enableMLS
|
|
263
|
-
? new mls_1.MLSService(this.apiClient, cryptoClient.getNativeClient(), this.db, Object.assign({}, (_b = this.cryptoProtocolConfig) === null || _b === void 0 ? void 0 : _b.mls))
|
|
279
|
+
? new mls_1.MLSService(this.apiClient, cryptoClient.getNativeClient(), this.db, this.recurringTaskScheduler, Object.assign({}, (_b = this.cryptoProtocolConfig) === null || _b === void 0 ? void 0 : _b.mls))
|
|
264
280
|
: undefined;
|
|
265
281
|
const proteusService = new proteus_1.ProteusService(this.apiClient, cryptoClient, {
|
|
266
282
|
onNewClient: payload => this.emit(EVENTS.NEW_SESSION, payload),
|
|
@@ -291,7 +291,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
291
291
|
const response = await this.mlsService.addUsersToExistingConversation(groupId, coreCryptoKeyPackagesPayload);
|
|
292
292
|
const conversation = await this.getConversation(conversationId);
|
|
293
293
|
//We store the info when user was added (and key material was created), so we will know when to renew it
|
|
294
|
-
this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
294
|
+
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
295
295
|
return {
|
|
296
296
|
events: response.events,
|
|
297
297
|
conversation,
|
|
@@ -305,7 +305,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
305
305
|
const fullyQualifiedClientIds = (0, fullyQualifiedClientIdUtils_1.mapQualifiedUserClientIdsToFullyQualifiedClientIds)(clientsToRemove.qualified_user_map);
|
|
306
306
|
const messageResponse = await this.mlsService.removeClientsFromConversation(groupId, fullyQualifiedClientIds);
|
|
307
307
|
//key material gets updated after removing a user from the group, so we can reset last key update time value in the store
|
|
308
|
-
this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
308
|
+
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
309
309
|
const conversation = await this.getConversation(conversationId);
|
|
310
310
|
return {
|
|
311
311
|
events: messageResponse.events,
|
|
@@ -334,7 +334,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
334
334
|
//@todo: it's temporary - we wait for core-crypto fix to return the actual Uint8Array instead of regular array
|
|
335
335
|
(0, mls_1.optionalToUint8Array)(externalProposal));
|
|
336
336
|
//We store the info when user was added (and key material was created), so we will know when to renew it
|
|
337
|
-
this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
337
|
+
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
338
338
|
});
|
|
339
339
|
}
|
|
340
340
|
/**
|
|
@@ -27,7 +27,7 @@ const handleMLSWelcomeMessage = async ({ mlsService, event, }) => {
|
|
|
27
27
|
const groupIdStr = bazinga64_1.Encoder.toBase64(newGroupId).asString;
|
|
28
28
|
// The groupId can then be sent back to the consumer
|
|
29
29
|
// After we were added to the group we need to schedule a periodic key material renewal
|
|
30
|
-
mlsService.scheduleKeyMaterialRenewal(groupIdStr);
|
|
30
|
+
await mlsService.scheduleKeyMaterialRenewal(groupIdStr);
|
|
31
31
|
return {
|
|
32
32
|
event: Object.assign(Object.assign({}, event), { data: groupIdStr }),
|
|
33
33
|
};
|
|
@@ -10,6 +10,7 @@ import { AddProposalArgs, ConversationId, CoreCrypto, DecryptedMessage, External
|
|
|
10
10
|
import { MLSServiceConfig } from './MLSService.types';
|
|
11
11
|
import { KeyPackageClaimUser } from '../../../conversation';
|
|
12
12
|
import { CoreDatabase } from '../../../storage/CoreDB';
|
|
13
|
+
import { RecurringTaskScheduler } from '../../../util/RecurringTaskScheduler';
|
|
13
14
|
import { CommitPendingProposalsParams, HandlePendingProposalsParams, MLSCallbacks } from '../types';
|
|
14
15
|
export declare const optionalToUint8Array: (array: Uint8Array | []) => Uint8Array;
|
|
15
16
|
interface LocalMLSServiceConfig extends MLSServiceConfig {
|
|
@@ -33,12 +34,13 @@ export declare class MLSService extends TypedEventEmitter<Events> {
|
|
|
33
34
|
private readonly apiClient;
|
|
34
35
|
private readonly coreCryptoClient;
|
|
35
36
|
private readonly coreDatabase;
|
|
37
|
+
private readonly recurringTaskScheduler;
|
|
36
38
|
logger: logdown.Logger;
|
|
37
39
|
config: LocalMLSServiceConfig;
|
|
38
40
|
groupIdFromConversationId?: MLSCallbacks['groupIdFromConversationId'];
|
|
39
41
|
private readonly textEncoder;
|
|
40
42
|
private readonly textDecoder;
|
|
41
|
-
constructor(apiClient: APIClient, coreCryptoClient: CoreCrypto, coreDatabase: CoreDatabase, { keyingMaterialUpdateThreshold, nbKeyPackages, defaultCiphersuite, defaultCredentialType, }: Partial<MLSServiceConfig>);
|
|
43
|
+
constructor(apiClient: APIClient, coreCryptoClient: CoreCrypto, coreDatabase: CoreDatabase, recurringTaskScheduler: RecurringTaskScheduler, { keyingMaterialUpdateThreshold, nbKeyPackages, defaultCiphersuite, defaultCredentialType, }: Partial<MLSServiceConfig>);
|
|
42
44
|
initClient(userId: QualifiedId, client: RegisteredClient): Promise<void>;
|
|
43
45
|
private readonly uploadCommitBundle;
|
|
44
46
|
/**
|
|
@@ -139,17 +141,17 @@ export declare class MLSService extends TypedEventEmitter<Events> {
|
|
|
139
141
|
* Will reset the renewal to the threshold given as config
|
|
140
142
|
* @param groupId The group that should have its key material updated
|
|
141
143
|
*/
|
|
142
|
-
resetKeyMaterialRenewal(groupId: string): void
|
|
144
|
+
resetKeyMaterialRenewal(groupId: string): Promise<void>;
|
|
143
145
|
/**
|
|
144
146
|
* Will cancel the renewal of the key material for a given groupId
|
|
145
147
|
* @param groupId The group that should stop having its key material updated
|
|
146
148
|
*/
|
|
147
|
-
cancelKeyMaterialRenewal(groupId: string): void
|
|
149
|
+
cancelKeyMaterialRenewal(groupId: string): Promise<void>;
|
|
148
150
|
/**
|
|
149
151
|
* Will schedule a task to update the key material of the conversation according to the threshold given as config
|
|
150
152
|
* @param groupId
|
|
151
153
|
*/
|
|
152
|
-
scheduleKeyMaterialRenewal(groupId: string): void
|
|
154
|
+
scheduleKeyMaterialRenewal(groupId: string): Promise<void>;
|
|
153
155
|
/**
|
|
154
156
|
* Get all keying material last update dates and schedule tasks for renewal
|
|
155
157
|
* Function must only be called once, after application start
|
|
@@ -160,7 +162,7 @@ export declare class MLSService extends TypedEventEmitter<Events> {
|
|
|
160
162
|
* Function must only be called once, after application start
|
|
161
163
|
* @param clientId id of the client
|
|
162
164
|
*/
|
|
163
|
-
schedulePeriodicKeyPackagesBackendSync(clientId: string): void
|
|
165
|
+
schedulePeriodicKeyPackagesBackendSync(clientId: string): Promise<void>;
|
|
164
166
|
/**
|
|
165
167
|
* Checks if there are enough key packages locally and if not,
|
|
166
168
|
* checks the number of keys available on backend and (if needed) generates new keys and uploads them.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MLSService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/MLSService/MLSService.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAqB,gBAAgB,EAAC,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAC,sBAAsB,EAAE,kBAAkB,EAAC,MAAM,sCAAsC,CAAC;AAChG,OAAO,EAAC,eAAe,EAAC,MAAM,sDAAsD,CAAC;AACrF,OAAO,EAAC,8BAA8B,EAAE,2BAA2B,EAAC,MAAM,+BAA+B,CAAC;AAE1G,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAGzD,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAW,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,eAAe,EAIf,cAAc,EACd,UAAU,EAEV,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAC,gBAAgB,EAAsB,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAC,YAAY,EAAC,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"MLSService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/MLSService/MLSService.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,7 +45,6 @@ const subconversationGroupIdStore_1 = require("./stores/subconversationGroupIdSt
|
|
|
45
45
|
const messageSender_1 = require("../../../conversation/message/messageSender");
|
|
46
46
|
const fullyQualifiedClientIdUtils_1 = require("../../../util/fullyQualifiedClientIdUtils");
|
|
47
47
|
const numberToHex_1 = require("../../../util/numberToHex");
|
|
48
|
-
const RecurringTaskScheduler_1 = require("../../../util/RecurringTaskScheduler");
|
|
49
48
|
const TaskScheduler_1 = require("../../../util/TaskScheduler");
|
|
50
49
|
const events_1 = require("../EventHandler/events");
|
|
51
50
|
//@todo: this function is temporary, we wait for the update from core-crypto side
|
|
@@ -61,11 +60,12 @@ const defaultConfig = {
|
|
|
61
60
|
defaultCredentialType: core_crypto_1.CredentialType.Basic,
|
|
62
61
|
};
|
|
63
62
|
class MLSService extends commons_1.TypedEventEmitter {
|
|
64
|
-
constructor(apiClient, coreCryptoClient, coreDatabase, { keyingMaterialUpdateThreshold = defaultConfig.keyingMaterialUpdateThreshold, nbKeyPackages = defaultConfig.nbKeyPackages, defaultCiphersuite = defaultConfig.defaultCiphersuite, defaultCredentialType = defaultConfig.defaultCredentialType, }) {
|
|
63
|
+
constructor(apiClient, coreCryptoClient, coreDatabase, recurringTaskScheduler, { keyingMaterialUpdateThreshold = defaultConfig.keyingMaterialUpdateThreshold, nbKeyPackages = defaultConfig.nbKeyPackages, defaultCiphersuite = defaultConfig.defaultCiphersuite, defaultCredentialType = defaultConfig.defaultCredentialType, }) {
|
|
65
64
|
super();
|
|
66
65
|
this.apiClient = apiClient;
|
|
67
66
|
this.coreCryptoClient = coreCryptoClient;
|
|
68
67
|
this.coreDatabase = coreDatabase;
|
|
68
|
+
this.recurringTaskScheduler = recurringTaskScheduler;
|
|
69
69
|
this.logger = (0, logdown_1.default)('@wireapp/core/MLSService');
|
|
70
70
|
this.textEncoder = new TextEncoder();
|
|
71
71
|
this.textDecoder = new TextDecoder();
|
|
@@ -202,7 +202,7 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
202
202
|
if (mlsResponse) {
|
|
203
203
|
//after we've successfully joined via external commit, we schedule periodic key material renewal
|
|
204
204
|
const groupIdStr = bazinga64_1.Encoder.toBase64(groupId).asString;
|
|
205
|
-
this.scheduleKeyMaterialRenewal(groupIdStr);
|
|
205
|
+
await this.scheduleKeyMaterialRenewal(groupIdStr);
|
|
206
206
|
}
|
|
207
207
|
return mlsResponse;
|
|
208
208
|
}
|
|
@@ -363,7 +363,7 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
363
363
|
: // If there are no clients to add, just update the keying material
|
|
364
364
|
await this.updateKeyingMaterial(groupId);
|
|
365
365
|
// We schedule a periodic key material renewal
|
|
366
|
-
this.scheduleKeyMaterialRenewal(groupId);
|
|
366
|
+
await this.scheduleKeyMaterialRenewal(groupId);
|
|
367
367
|
/**
|
|
368
368
|
* @note If we can't fetch a user's key packages then we can not add them to mls conversation
|
|
369
369
|
* so we're adding them to the list of failed users.
|
|
@@ -431,16 +431,16 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
431
431
|
* Will reset the renewal to the threshold given as config
|
|
432
432
|
* @param groupId The group that should have its key material updated
|
|
433
433
|
*/
|
|
434
|
-
resetKeyMaterialRenewal(groupId) {
|
|
435
|
-
this.cancelKeyMaterialRenewal(groupId);
|
|
436
|
-
this.scheduleKeyMaterialRenewal(groupId);
|
|
434
|
+
async resetKeyMaterialRenewal(groupId) {
|
|
435
|
+
await this.cancelKeyMaterialRenewal(groupId);
|
|
436
|
+
await this.scheduleKeyMaterialRenewal(groupId);
|
|
437
437
|
}
|
|
438
438
|
/**
|
|
439
439
|
* Will cancel the renewal of the key material for a given groupId
|
|
440
440
|
* @param groupId The group that should stop having its key material updated
|
|
441
441
|
*/
|
|
442
442
|
cancelKeyMaterialRenewal(groupId) {
|
|
443
|
-
return
|
|
443
|
+
return this.recurringTaskScheduler.cancelTask(this.createKeyMaterialUpdateTaskSchedulerId(groupId));
|
|
444
444
|
}
|
|
445
445
|
/**
|
|
446
446
|
* Will schedule a task to update the key material of the conversation according to the threshold given as config
|
|
@@ -448,7 +448,7 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
448
448
|
*/
|
|
449
449
|
scheduleKeyMaterialRenewal(groupId) {
|
|
450
450
|
const key = this.createKeyMaterialUpdateTaskSchedulerId(groupId);
|
|
451
|
-
|
|
451
|
+
return this.recurringTaskScheduler.registerTask({
|
|
452
452
|
task: () => this.renewKeyMaterial(groupId),
|
|
453
453
|
every: this.config.keyingMaterialUpdateThreshold,
|
|
454
454
|
key,
|
|
@@ -472,7 +472,7 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
472
472
|
* @param clientId id of the client
|
|
473
473
|
*/
|
|
474
474
|
schedulePeriodicKeyPackagesBackendSync(clientId) {
|
|
475
|
-
|
|
475
|
+
return this.recurringTaskScheduler.registerTask({
|
|
476
476
|
every: commons_1.TimeUtil.TimeInMillis.DAY,
|
|
477
477
|
key: 'try-key-packages-backend-sync',
|
|
478
478
|
task: () => this.verifyRemoteMLSKeyPackagesAmount(clientId),
|
|
@@ -527,7 +527,7 @@ class MLSService extends commons_1.TypedEventEmitter {
|
|
|
527
527
|
//if the mls group does not exist, we don't need to wipe it
|
|
528
528
|
return;
|
|
529
529
|
}
|
|
530
|
-
this.cancelKeyMaterialRenewal(groupId);
|
|
530
|
+
await this.cancelKeyMaterialRenewal(groupId);
|
|
531
531
|
const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
532
532
|
return this.coreCryptoClient.wipeConversation(groupIdBytes);
|
|
533
533
|
}
|
|
@@ -24,6 +24,7 @@ const crypto_1 = require("crypto");
|
|
|
24
24
|
const api_client_1 = require("@wireapp/api-client");
|
|
25
25
|
const MLSService_1 = require("./MLSService");
|
|
26
26
|
const CoreDB_1 = require("../../../storage/CoreDB");
|
|
27
|
+
const RecurringTaskScheduler_1 = require("../../../util/RecurringTaskScheduler");
|
|
27
28
|
jest.createMockFromModule('@wireapp/api-client');
|
|
28
29
|
function createUserId() {
|
|
29
30
|
return { id: (0, crypto_1.randomUUID)(), domain: '' };
|
|
@@ -44,7 +45,14 @@ const createMLSService = async () => {
|
|
|
44
45
|
commitPendingProposals: jest.fn(),
|
|
45
46
|
};
|
|
46
47
|
const mockedDb = await (0, CoreDB_1.openDB)('core-test-db');
|
|
47
|
-
const
|
|
48
|
+
const recurringTaskScheduler = new RecurringTaskScheduler_1.RecurringTaskScheduler({
|
|
49
|
+
delete: key => mockedDb.delete('recurringTasks', key),
|
|
50
|
+
get: async (key) => { var _a; return (_a = (await mockedDb.get('recurringTasks', key))) === null || _a === void 0 ? void 0 : _a.firingDate; },
|
|
51
|
+
set: async (key, timestamp) => {
|
|
52
|
+
await mockedDb.put('recurringTasks', { key, firingDate: timestamp });
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const mlsService = new MLSService_1.MLSService(apiClient, mockCoreCrypto, mockedDb, recurringTaskScheduler, {});
|
|
48
56
|
return [mlsService, { apiClient, coreCrypto: mockCoreCrypto }];
|
|
49
57
|
};
|
|
50
58
|
describe('MLSService', () => {
|
package/lib/storage/CoreDB.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ interface CoreDBSchema extends DBSchema {
|
|
|
14
14
|
firingDate: number;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
+
recurringTasks: {
|
|
18
|
+
key: string;
|
|
19
|
+
value: {
|
|
20
|
+
key: string;
|
|
21
|
+
firingDate: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
17
24
|
}
|
|
18
25
|
export type CoreDatabase = IDBPDatabase<CoreDBSchema>;
|
|
19
26
|
export declare function openDB(dbName: string): Promise<CoreDatabase>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoreDB.d.ts","sourceRoot":"","sources":["../../src/storage/CoreDB.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,QAAQ,EAA2B,YAAY,EAAsB,MAAM,KAAK,CAAC;AAGzF,UAAU,YAAa,SAAQ,QAAQ;IACrC,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAC,CAAC;KAC/C,CAAC;IACF,gBAAgB,EAAE;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAC,CAAC;KAC9C,CAAC;CACH;AAED,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAEtD,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"CoreDB.d.ts","sourceRoot":"","sources":["../../src/storage/CoreDB.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,QAAQ,EAA2B,YAAY,EAAsB,MAAM,KAAK,CAAC;AAGzF,UAAU,YAAa,SAAQ,QAAQ;IACrC,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAC,CAAC;KAC/C,CAAC;IACF,gBAAgB,EAAE;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAC,CAAC;KAC9C,CAAC;IACF,cAAc,EAAE;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAC,CAAC;KAC1C,CAAC;CACH;AAED,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAEtD,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAelE;AAED,wBAAsB,QAAQ,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D"}
|
package/lib/storage/CoreDB.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.deleteDB = exports.openDB = void 0;
|
|
22
22
|
const idb_1 = require("idb");
|
|
23
|
-
const VERSION =
|
|
23
|
+
const VERSION = 3;
|
|
24
24
|
async function openDB(dbName) {
|
|
25
25
|
const db = await (0, idb_1.openDB)(dbName, VERSION, {
|
|
26
26
|
upgrade: (db, oldVersion) => {
|
|
@@ -30,6 +30,8 @@ async function openDB(dbName) {
|
|
|
30
30
|
case 1:
|
|
31
31
|
db.deleteObjectStore('prekeys');
|
|
32
32
|
db.createObjectStore('pendingProposals');
|
|
33
|
+
case 2:
|
|
34
|
+
db.createObjectStore('recurringTasks');
|
|
33
35
|
}
|
|
34
36
|
},
|
|
35
37
|
});
|
package/lib/testUtils/index.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export declare function generateQualifiedId(domain: string): {
|
|
|
4
4
|
domain: string;
|
|
5
5
|
};
|
|
6
6
|
export declare function generateQualifiedIds(nbUsers: number, domain: string): QualifiedId[];
|
|
7
|
+
export declare const advanceJestTimersWithPromise: (time: number) => Promise<unknown>;
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testUtils/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAIzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM;;;EAEjD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAMnE"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testUtils/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAIzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM;;;EAEjD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAMnE;AAKD,eAAO,MAAM,4BAA4B,SAAgB,MAAM,qBAG9D,CAAC"}
|
package/lib/testUtils/index.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.generateQualifiedIds = exports.generateQualifiedId = void 0;
|
|
21
|
+
exports.advanceJestTimersWithPromise = exports.generateQualifiedIds = exports.generateQualifiedId = void 0;
|
|
22
22
|
const crypto_1 = require("crypto");
|
|
23
23
|
function generateQualifiedId(domain) {
|
|
24
24
|
return { id: (0, crypto_1.randomUUID)(), domain };
|
|
@@ -32,3 +32,11 @@ function generateQualifiedIds(nbUsers, domain) {
|
|
|
32
32
|
return users;
|
|
33
33
|
}
|
|
34
34
|
exports.generateQualifiedIds = generateQualifiedIds;
|
|
35
|
+
/*
|
|
36
|
+
* Jest fake timers do not play well with promises, so we need to advance the timers and wait for all the promises to resolve.
|
|
37
|
+
*/
|
|
38
|
+
const advanceJestTimersWithPromise = async (time) => {
|
|
39
|
+
jest.advanceTimersByTime(time);
|
|
40
|
+
return new Promise(jest.requireActual('timers').setImmediate);
|
|
41
|
+
};
|
|
42
|
+
exports.advanceJestTimersWithPromise = advanceJestTimersWithPromise;
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
const LowPrecisionTaskScheduler_1 = require("./LowPrecisionTaskScheduler");
|
|
22
|
+
const testUtils_1 = require("../../testUtils");
|
|
22
23
|
describe('LowPrecisionTaskScheduler', () => {
|
|
23
24
|
beforeEach(() => {
|
|
24
25
|
jest.useFakeTimers();
|
|
@@ -35,10 +36,7 @@ describe('LowPrecisionTaskScheduler', () => {
|
|
|
35
36
|
intervalDelay: 2000,
|
|
36
37
|
task: mockedTask,
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
-
await Promise.resolve();
|
|
40
|
-
jest.advanceTimersByTime(2001);
|
|
41
|
-
await Promise.resolve();
|
|
39
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(5000);
|
|
42
40
|
expect(mockedTask).toHaveBeenCalledTimes(1);
|
|
43
41
|
});
|
|
44
42
|
it('adds single task to schedule and runs it after given delay', async () => {
|
|
@@ -49,8 +47,7 @@ describe('LowPrecisionTaskScheduler', () => {
|
|
|
49
47
|
intervalDelay: 1000,
|
|
50
48
|
task: mockedTask,
|
|
51
49
|
});
|
|
52
|
-
|
|
53
|
-
await Promise.resolve();
|
|
50
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(1001);
|
|
54
51
|
expect(mockedTask).toHaveBeenCalled();
|
|
55
52
|
});
|
|
56
53
|
it('adds multiple tasks to schedule and runs it after given delay', async () => {
|
|
@@ -62,16 +59,14 @@ describe('LowPrecisionTaskScheduler', () => {
|
|
|
62
59
|
intervalDelay: 5000,
|
|
63
60
|
task: mockedTask1,
|
|
64
61
|
});
|
|
65
|
-
|
|
62
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(1000);
|
|
66
63
|
LowPrecisionTaskScheduler_1.LowPrecisionTaskScheduler.addTask({
|
|
67
64
|
key: 'test2-key',
|
|
68
65
|
firingDate: 0,
|
|
69
66
|
intervalDelay: 5000,
|
|
70
67
|
task: mockedTask2,
|
|
71
68
|
});
|
|
72
|
-
|
|
73
|
-
await Promise.resolve();
|
|
74
|
-
await Promise.resolve();
|
|
69
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(5001);
|
|
75
70
|
expect(mockedTask1).toHaveBeenCalled();
|
|
76
71
|
expect(mockedTask2).toHaveBeenCalled();
|
|
77
72
|
});
|
|
@@ -84,7 +79,7 @@ describe('LowPrecisionTaskScheduler', () => {
|
|
|
84
79
|
intervalDelay: 4000,
|
|
85
80
|
task: mockedTask3,
|
|
86
81
|
});
|
|
87
|
-
|
|
82
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(1000);
|
|
88
83
|
LowPrecisionTaskScheduler_1.LowPrecisionTaskScheduler.addTask({
|
|
89
84
|
key: 'test4-key',
|
|
90
85
|
firingDate: 0,
|
|
@@ -95,9 +90,7 @@ describe('LowPrecisionTaskScheduler', () => {
|
|
|
95
90
|
intervalDelay: 4000,
|
|
96
91
|
key: 'test3-key',
|
|
97
92
|
});
|
|
98
|
-
|
|
99
|
-
await Promise.resolve();
|
|
100
|
-
await Promise.resolve();
|
|
93
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(4001);
|
|
101
94
|
expect(mockedTask3).not.toHaveBeenCalled();
|
|
102
95
|
expect(mockedTask4).toHaveBeenCalled();
|
|
103
96
|
});
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
interface RecurringTaskSchedulerStorage {
|
|
2
|
+
set: (key: string, timestamp: number) => Promise<void>;
|
|
3
|
+
get: (key: string) => Promise<number | undefined>;
|
|
4
|
+
delete: (key: string) => Promise<void>;
|
|
5
|
+
}
|
|
1
6
|
interface TaskParams {
|
|
2
7
|
every: number;
|
|
3
|
-
task: () => void;
|
|
8
|
+
task: () => Promise<void> | void;
|
|
4
9
|
key: string;
|
|
5
10
|
}
|
|
6
|
-
export declare
|
|
7
|
-
|
|
11
|
+
export declare class RecurringTaskScheduler {
|
|
12
|
+
private readonly storage;
|
|
13
|
+
constructor(storage: RecurringTaskSchedulerStorage);
|
|
14
|
+
readonly registerTask: ({ every, task, key }: TaskParams) => Promise<void>;
|
|
15
|
+
readonly cancelTask: (taskKey: string) => Promise<void>;
|
|
16
|
+
}
|
|
8
17
|
export {};
|
|
9
18
|
//# sourceMappingURL=RecurringTaskScheduler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecurringTaskScheduler.d.ts","sourceRoot":"","sources":["../../../src/util/RecurringTaskScheduler/RecurringTaskScheduler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RecurringTaskScheduler.d.ts","sourceRoot":"","sources":["../../../src/util/RecurringTaskScheduler/RecurringTaskScheduler.ts"],"names":[],"mappings":"AAwBA,UAAU,6BAA6B;IACrC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,6BAA6B;IAEnE,SAAgB,YAAY,yBAA8B,UAAU,KAAG,QAAQ,IAAI,CAAC,CAwBlF;IAEF,SAAgB,UAAU,YAAmB,MAAM,KAAG,QAAQ,IAAI,CAAC,CAIjE;CACH"}
|
|
@@ -18,36 +18,43 @@
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.
|
|
21
|
+
exports.RecurringTaskScheduler = void 0;
|
|
22
22
|
const commons_1 = require("@wireapp/commons");
|
|
23
|
-
const RecurringTaskScheduler_store_1 = require("./RecurringTaskScheduler.store");
|
|
24
23
|
const LowPrecisionTaskScheduler_1 = require("../LowPrecisionTaskScheduler");
|
|
25
24
|
const TaskScheduler_1 = require("../TaskScheduler");
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
class RecurringTaskScheduler {
|
|
26
|
+
constructor(storage) {
|
|
27
|
+
this.storage = storage;
|
|
28
|
+
this.registerTask = async ({ every, task, key }) => {
|
|
29
|
+
const firingDate = (await this.storage.get(key)) || Date.now() + every;
|
|
30
|
+
await this.storage.set(key, firingDate);
|
|
31
|
+
const taskConfig = {
|
|
32
|
+
firingDate,
|
|
33
|
+
key,
|
|
34
|
+
task: async () => {
|
|
35
|
+
await this.storage.delete(key);
|
|
36
|
+
try {
|
|
37
|
+
await task();
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await this.registerTask({ every, task, key });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
if (every > commons_1.TimeUtil.TimeInMillis.DAY * 20) {
|
|
45
|
+
// If the firing date is in more that 20 days, we could switch to a lowPrecision scheduler that will avoid hitting the limit of setTimeout
|
|
46
|
+
// (see https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value)
|
|
47
|
+
LowPrecisionTaskScheduler_1.LowPrecisionTaskScheduler.addTask(Object.assign(Object.assign({}, taskConfig), { intervalDelay: commons_1.TimeUtil.TimeInMillis.MINUTE }));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
TaskScheduler_1.TaskScheduler.addTask(taskConfig);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
this.cancelTask = async (taskKey) => {
|
|
54
|
+
await this.storage.delete(taskKey);
|
|
55
|
+
TaskScheduler_1.TaskScheduler.cancelTask(taskKey);
|
|
56
|
+
LowPrecisionTaskScheduler_1.LowPrecisionTaskScheduler.cancelTask({ intervalDelay: commons_1.TimeUtil.TimeInMillis.MINUTE, key: taskKey });
|
|
57
|
+
};
|
|
42
58
|
}
|
|
43
|
-
else {
|
|
44
|
-
TaskScheduler_1.TaskScheduler.addTask(taskConfig);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
exports.registerRecurringTask = registerRecurringTask;
|
|
48
|
-
function cancelRecurringTask(taskKey) {
|
|
49
|
-
(0, RecurringTaskScheduler_store_1.deleteState)(taskKey);
|
|
50
|
-
TaskScheduler_1.TaskScheduler.cancelTask(taskKey);
|
|
51
|
-
LowPrecisionTaskScheduler_1.LowPrecisionTaskScheduler.cancelTask({ intervalDelay: commons_1.TimeUtil.TimeInMillis.MINUTE, key: taskKey });
|
|
52
59
|
}
|
|
53
|
-
exports.
|
|
60
|
+
exports.RecurringTaskScheduler = RecurringTaskScheduler;
|
|
@@ -20,6 +20,23 @@
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
const commons_1 = require("@wireapp/commons");
|
|
22
22
|
const RecurringTaskScheduler_1 = require("./RecurringTaskScheduler");
|
|
23
|
+
const testUtils_1 = require("../../testUtils");
|
|
24
|
+
const mockedStore = {
|
|
25
|
+
storage: new Map(),
|
|
26
|
+
set: async (key, timestamp) => {
|
|
27
|
+
mockedStore.storage.set(key, timestamp);
|
|
28
|
+
},
|
|
29
|
+
get: async (key) => {
|
|
30
|
+
return mockedStore.storage.get(key);
|
|
31
|
+
},
|
|
32
|
+
delete: async (key) => {
|
|
33
|
+
mockedStore.storage.delete(key);
|
|
34
|
+
},
|
|
35
|
+
clearAll: async () => {
|
|
36
|
+
mockedStore.storage.clear();
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const recurringTaskScheduler = new RecurringTaskScheduler_1.RecurringTaskScheduler(mockedStore);
|
|
23
40
|
describe('RecurringTaskScheduler', () => {
|
|
24
41
|
beforeEach(() => {
|
|
25
42
|
jest.useFakeTimers();
|
|
@@ -28,58 +45,58 @@ describe('RecurringTaskScheduler', () => {
|
|
|
28
45
|
afterEach(() => {
|
|
29
46
|
jest.useRealTimers();
|
|
30
47
|
});
|
|
31
|
-
it('executes a task periodically', () => {
|
|
48
|
+
it('executes a task periodically', async () => {
|
|
32
49
|
const task = jest.fn();
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
await recurringTaskScheduler.registerTask({ every: commons_1.TimeUtil.TimeInMillis.MINUTE, task, key: 'test-task' });
|
|
51
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE + 1);
|
|
35
52
|
expect(task).toHaveBeenCalledTimes(1);
|
|
36
|
-
|
|
53
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE + 1);
|
|
37
54
|
expect(task).toHaveBeenCalledTimes(2);
|
|
38
55
|
});
|
|
39
|
-
it('resumes a task after re-registering a recurring task', () => {
|
|
56
|
+
it('resumes a task after re-registering a recurring task', async () => {
|
|
40
57
|
const task = jest.fn();
|
|
41
58
|
// it should fire in a minute
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
await recurringTaskScheduler.registerTask({ every: commons_1.TimeUtil.TimeInMillis.MINUTE, task, key: 'test-task2' });
|
|
60
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE / 2);
|
|
44
61
|
// re-register the task
|
|
45
|
-
|
|
62
|
+
await recurringTaskScheduler.registerTask({ every: commons_1.TimeUtil.TimeInMillis.MINUTE, task, key: 'test-task2' });
|
|
46
63
|
// only 30s have passed, so the task should not have fired yet
|
|
47
64
|
expect(task).toHaveBeenCalledTimes(0);
|
|
48
65
|
// advance the timer by another 30s (so we have 1 minute in total)
|
|
49
|
-
|
|
66
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE / 2);
|
|
50
67
|
// the task should have fired once after a minute from the beginning even if we re-registered it
|
|
51
68
|
expect(task).toHaveBeenCalledTimes(1);
|
|
52
69
|
});
|
|
53
|
-
it('cancel a task before it is run', () => {
|
|
70
|
+
it('cancel a task before it is run', async () => {
|
|
54
71
|
const task = jest.fn();
|
|
55
72
|
const testKey = 'test-task-1';
|
|
56
|
-
|
|
73
|
+
await recurringTaskScheduler.registerTask({
|
|
57
74
|
key: testKey,
|
|
58
75
|
every: commons_1.TimeUtil.TimeInMillis.MINUTE,
|
|
59
76
|
task,
|
|
60
77
|
});
|
|
61
|
-
|
|
78
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE - 1);
|
|
62
79
|
expect(task).not.toHaveBeenCalled();
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
await recurringTaskScheduler.cancelTask(testKey);
|
|
81
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE);
|
|
65
82
|
expect(task).not.toHaveBeenCalled();
|
|
66
83
|
});
|
|
67
|
-
it('adds multiple tasks to schedule and runs it after given delay', () => {
|
|
84
|
+
it('adds multiple tasks to schedule and runs it after given delay', async () => {
|
|
68
85
|
const mockedTask1 = jest.fn();
|
|
69
86
|
const mockedTask2 = jest.fn();
|
|
70
|
-
|
|
87
|
+
await recurringTaskScheduler.registerTask({
|
|
71
88
|
key: 'test1-key',
|
|
72
89
|
every: commons_1.TimeUtil.TimeInMillis.MINUTE,
|
|
73
90
|
task: mockedTask1,
|
|
74
91
|
});
|
|
75
|
-
|
|
92
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE + 1);
|
|
76
93
|
expect(mockedTask1).toHaveBeenCalledTimes(1);
|
|
77
|
-
|
|
94
|
+
await recurringTaskScheduler.registerTask({
|
|
78
95
|
key: 'test2-key',
|
|
79
96
|
every: commons_1.TimeUtil.TimeInMillis.MINUTE,
|
|
80
97
|
task: mockedTask2,
|
|
81
98
|
});
|
|
82
|
-
|
|
99
|
+
await (0, testUtils_1.advanceJestTimersWithPromise)(commons_1.TimeUtil.TimeInMillis.MINUTE + 1);
|
|
83
100
|
expect(mockedTask1).toHaveBeenCalledTimes(2);
|
|
84
101
|
expect(mockedTask2).toHaveBeenCalledTimes(1);
|
|
85
102
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskScheduler.d.ts","sourceRoot":"","sources":["../../../src/util/TaskScheduler/TaskScheduler.ts"],"names":[],"mappings":"AA4BA,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"TaskScheduler.d.ts","sourceRoot":"","sources":["../../../src/util/TaskScheduler/TaskScheduler.ts"],"names":[],"mappings":"AA4BA,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAoEF,eAAO,MAAM,aAAa;kDAzDiC,kBAAkB;sBAoCpD,MAAM;kCAcI,KAAK,kBAAkB,EAAE,YAAY,GAAG,SAAS,CAAC;;CAYpF,CAAC"}
|
package/package.json
CHANGED