@juzi/wechaty-puppet-service 1.0.129 → 1.0.131
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/cjs/src/auth/call-cred.d.ts +2 -2
- package/dist/cjs/src/auth/call-cred.d.ts.map +1 -1
- package/dist/cjs/src/auth/call-cred.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.d.ts +27 -2
- package/dist/cjs/src/client/puppet-service.d.ts.map +1 -1
- package/dist/cjs/src/client/puppet-service.js +431 -124
- package/dist/cjs/src/client/puppet-service.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.spec.js +107 -0
- package/dist/cjs/src/client/puppet-service.spec.js.map +1 -1
- package/dist/cjs/src/client/room-cache-coordinator.d.ts +14 -0
- package/dist/cjs/src/client/room-cache-coordinator.d.ts.map +1 -0
- package/dist/cjs/src/client/room-cache-coordinator.js +53 -0
- package/dist/cjs/src/client/room-cache-coordinator.js.map +1 -0
- package/dist/cjs/src/client/room-member-cache.spec.d.ts +2 -0
- package/dist/cjs/src/client/room-member-cache.spec.d.ts.map +1 -0
- package/dist/cjs/src/client/room-member-cache.spec.js +417 -0
- package/dist/cjs/src/client/room-member-cache.spec.js.map +1 -0
- package/dist/cjs/src/client/room-member-load.spec.d.ts +2 -0
- package/dist/cjs/src/client/room-member-load.spec.d.ts.map +1 -0
- package/dist/cjs/src/client/room-member-load.spec.js +324 -0
- package/dist/cjs/src/client/room-member-load.spec.js.map +1 -0
- package/dist/cjs/src/package-json.js +4 -4
- package/dist/cjs/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/cjs/src/server/event-stream-manager.js +30 -0
- package/dist/cjs/src/server/event-stream-manager.js.map +1 -1
- package/dist/cjs/src/server/event-stream-manager.spec.d.ts +3 -0
- package/dist/cjs/src/server/event-stream-manager.spec.d.ts.map +1 -0
- package/dist/cjs/src/server/event-stream-manager.spec.js +22 -0
- package/dist/cjs/src/server/event-stream-manager.spec.js.map +1 -0
- package/dist/cjs/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.js +135 -28
- package/dist/cjs/src/server/puppet-implementation.js.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.spec.js +98 -0
- package/dist/cjs/src/server/puppet-implementation.spec.js.map +1 -1
- package/dist/cjs/src/utils/pb-payload-helper.d.ts +10 -0
- package/dist/cjs/src/utils/pb-payload-helper.d.ts.map +1 -1
- package/dist/cjs/src/utils/pb-payload-helper.js +180 -1
- package/dist/cjs/src/utils/pb-payload-helper.js.map +1 -1
- package/dist/cjs/src/utils/room-member-load.spec.d.ts +2 -0
- package/dist/cjs/src/utils/room-member-load.spec.d.ts.map +1 -0
- package/dist/cjs/src/utils/room-member-load.spec.js +83 -0
- package/dist/cjs/src/utils/room-member-load.spec.js.map +1 -0
- package/dist/esm/src/auth/call-cred.d.ts +2 -2
- package/dist/esm/src/auth/call-cred.d.ts.map +1 -1
- package/dist/esm/src/auth/call-cred.js.map +1 -1
- package/dist/esm/src/client/puppet-service.d.ts +27 -2
- package/dist/esm/src/client/puppet-service.d.ts.map +1 -1
- package/dist/esm/src/client/puppet-service.js +432 -125
- package/dist/esm/src/client/puppet-service.js.map +1 -1
- package/dist/esm/src/client/puppet-service.spec.js +107 -0
- package/dist/esm/src/client/puppet-service.spec.js.map +1 -1
- package/dist/esm/src/client/room-cache-coordinator.d.ts +14 -0
- package/dist/esm/src/client/room-cache-coordinator.d.ts.map +1 -0
- package/dist/esm/src/client/room-cache-coordinator.js +49 -0
- package/dist/esm/src/client/room-cache-coordinator.js.map +1 -0
- package/dist/esm/src/client/room-member-cache.spec.d.ts +2 -0
- package/dist/esm/src/client/room-member-cache.spec.d.ts.map +1 -0
- package/dist/esm/src/client/room-member-cache.spec.js +415 -0
- package/dist/esm/src/client/room-member-cache.spec.js.map +1 -0
- package/dist/esm/src/client/room-member-load.spec.d.ts +2 -0
- package/dist/esm/src/client/room-member-load.spec.d.ts.map +1 -0
- package/dist/esm/src/client/room-member-load.spec.js +296 -0
- package/dist/esm/src/client/room-member-load.spec.js.map +1 -0
- package/dist/esm/src/package-json.js +4 -4
- package/dist/esm/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/esm/src/server/event-stream-manager.js +30 -0
- package/dist/esm/src/server/event-stream-manager.js.map +1 -1
- package/dist/esm/src/server/event-stream-manager.spec.d.ts +3 -0
- package/dist/esm/src/server/event-stream-manager.spec.d.ts.map +1 -0
- package/dist/esm/src/server/event-stream-manager.spec.js +20 -0
- package/dist/esm/src/server/event-stream-manager.spec.js.map +1 -0
- package/dist/esm/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/esm/src/server/puppet-implementation.js +136 -29
- package/dist/esm/src/server/puppet-implementation.js.map +1 -1
- package/dist/esm/src/server/puppet-implementation.spec.js +98 -0
- package/dist/esm/src/server/puppet-implementation.spec.js.map +1 -1
- package/dist/esm/src/utils/pb-payload-helper.d.ts +10 -0
- package/dist/esm/src/utils/pb-payload-helper.d.ts.map +1 -1
- package/dist/esm/src/utils/pb-payload-helper.js +169 -0
- package/dist/esm/src/utils/pb-payload-helper.js.map +1 -1
- package/dist/esm/src/utils/room-member-load.spec.d.ts +2 -0
- package/dist/esm/src/utils/room-member-load.spec.d.ts.map +1 -0
- package/dist/esm/src/utils/room-member-load.spec.js +58 -0
- package/dist/esm/src/utils/room-member-load.spec.js.map +1 -0
- package/package.json +4 -4
- package/src/auth/call-cred.ts +1 -1
- package/src/client/puppet-service.spec.ts +147 -0
- package/src/client/puppet-service.ts +378 -138
- package/src/client/room-cache-coordinator.ts +50 -0
- package/src/client/room-member-cache.spec.ts +448 -0
- package/src/client/room-member-load.spec.ts +319 -0
- package/src/package-json.ts +4 -4
- package/src/server/event-stream-manager.spec.ts +30 -0
- package/src/server/event-stream-manager.ts +29 -0
- package/src/server/puppet-implementation.spec.ts +127 -0
- package/src/server/puppet-implementation.ts +144 -29
- package/src/utils/pb-payload-helper.ts +150 -0
- package/src/utils/room-member-load.spec.ts +67 -0
|
@@ -57,6 +57,7 @@ const event_type_rev_js_1 = require("../event-type-rev.js");
|
|
|
57
57
|
const package_json_js_1 = require("../package-json.js");
|
|
58
58
|
const grpc_manager_js_1 = require("./grpc-manager.js");
|
|
59
59
|
const payload_store_js_1 = require("./payload-store.js");
|
|
60
|
+
const room_cache_coordinator_js_1 = require("./room-cache-coordinator.js");
|
|
60
61
|
const pb_payload_helper_js_1 = require("../utils/pb-payload-helper.js");
|
|
61
62
|
const call_media_mapping_js_1 = require("../utils/call-media-mapping.js");
|
|
62
63
|
const gerror_1 = require("gerror");
|
|
@@ -76,6 +77,15 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
76
77
|
options;
|
|
77
78
|
static VERSION = config_js_1.VERSION;
|
|
78
79
|
_payloadStore;
|
|
80
|
+
roomCache = new room_cache_coordinator_js_1.RoomCacheCoordinator();
|
|
81
|
+
eventQueue = Promise.resolve();
|
|
82
|
+
eventEpoch = 0;
|
|
83
|
+
eventsBlocked = false;
|
|
84
|
+
failedEventSeq;
|
|
85
|
+
activeEventSeq;
|
|
86
|
+
pendingEventSeq;
|
|
87
|
+
checkpointQueue = Promise.resolve();
|
|
88
|
+
pendingCheckpointRollback;
|
|
79
89
|
timeoutMilliseconds;
|
|
80
90
|
_grpcManager;
|
|
81
91
|
get grpcManager() {
|
|
@@ -129,6 +139,8 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
129
139
|
this.log.verbose('PuppetService', 'onStart()');
|
|
130
140
|
this.waitingForLogin = false;
|
|
131
141
|
this.waitingForReady = false;
|
|
142
|
+
this.suspendEventProcessing();
|
|
143
|
+
this.eventsBlocked = false;
|
|
132
144
|
if (this._grpcManager) {
|
|
133
145
|
this.log.warn('PuppetService', 'onStart() found this.grpc is already existed. dropped.');
|
|
134
146
|
this._grpcManager = undefined;
|
|
@@ -145,7 +157,7 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
145
157
|
this.bridgeGrpcEventStream(grpcManager);
|
|
146
158
|
this.log.info('PuppetService', 'start() setting up bridge grpc event stream ... done');
|
|
147
159
|
this.log.info('PuppetService', 'start() starting grpc manager...');
|
|
148
|
-
const { lastEventSeq, accountId } = await this.
|
|
160
|
+
const { lastEventSeq, accountId } = await this.eventResumePosition();
|
|
149
161
|
await grpcManager.start(lastEventSeq, accountId);
|
|
150
162
|
this.log.info('PuppetService', 'start() starting grpc manager... done');
|
|
151
163
|
this.log.info('PuppetService', 'start healthCheck');
|
|
@@ -154,6 +166,8 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
154
166
|
}
|
|
155
167
|
async onStop() {
|
|
156
168
|
this.log.info('PuppetService', 'onStop()');
|
|
169
|
+
this.suspendEventProcessing();
|
|
170
|
+
await this.checkpointQueue;
|
|
157
171
|
if (this._grpcManager) {
|
|
158
172
|
this.log.info('PuppetService', 'onStop() stopping grpc manager ...');
|
|
159
173
|
const grpcManager = this._grpcManager;
|
|
@@ -189,7 +203,41 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
189
203
|
bridgeGrpcEventStream(client) {
|
|
190
204
|
this.log.verbose('PuppetService', 'bridgeGrpcEventStream(client)');
|
|
191
205
|
client
|
|
192
|
-
.on('data',
|
|
206
|
+
.on('data', (event) => {
|
|
207
|
+
if (client !== this._grpcManager || this.eventsBlocked) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const epoch = this.eventEpoch;
|
|
211
|
+
this.eventQueue = this.eventQueue.then(async () => {
|
|
212
|
+
if (!this.ownsEventWorker(client, epoch)) {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
this.activeEventSeq = event.getSeq();
|
|
216
|
+
try {
|
|
217
|
+
if (this.failedEventSeq !== undefined && event.getSeq() > this.failedEventSeq) {
|
|
218
|
+
throw new Error(`Replay skipped failed event ${this.failedEventSeq}; stream halted until reset`);
|
|
219
|
+
}
|
|
220
|
+
await this.onGrpcStreamEvent(event, epoch);
|
|
221
|
+
if (!this.ownsEventWorker(client, epoch)) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
if (event.getSeq() === this.failedEventSeq) {
|
|
225
|
+
this.failedEventSeq = undefined;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (!this.ownsEventWorker(client, epoch)) {
|
|
230
|
+
this.log.error('PuppetService', 'superseded event worker failed: %s', error);
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
this.haltEventStream(client, event, error);
|
|
234
|
+
}
|
|
235
|
+
if (epoch === this.eventEpoch) {
|
|
236
|
+
this.activeEventSeq = undefined;
|
|
237
|
+
}
|
|
238
|
+
return undefined;
|
|
239
|
+
}).catch((error) => { this.reportStreamError(error); });
|
|
240
|
+
})
|
|
193
241
|
.on('end', () => {
|
|
194
242
|
this.log.verbose('PuppetService', 'bridgeGrpcEventStream() eventStream.on(end)');
|
|
195
243
|
})
|
|
@@ -214,7 +262,128 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
214
262
|
this.log.verbose('PuppetService', 'bridgeGrpcEventStream() eventStream.on(cancel), %s', JSON.stringify(args));
|
|
215
263
|
});
|
|
216
264
|
}
|
|
217
|
-
|
|
265
|
+
suspendEventProcessing() {
|
|
266
|
+
if (this.activeEventSeq) {
|
|
267
|
+
this.pendingEventSeq ??= this.activeEventSeq;
|
|
268
|
+
}
|
|
269
|
+
this.eventEpoch++;
|
|
270
|
+
this.eventsBlocked = true;
|
|
271
|
+
this.activeEventSeq = undefined;
|
|
272
|
+
this.eventQueue = Promise.resolve();
|
|
273
|
+
}
|
|
274
|
+
ownsEventWorker(manager, epoch) {
|
|
275
|
+
return manager === this._grpcManager && this.isEventEpochCurrent(epoch);
|
|
276
|
+
}
|
|
277
|
+
isEventEpochCurrent(epoch) {
|
|
278
|
+
return epoch === this.eventEpoch && !this.eventsBlocked;
|
|
279
|
+
}
|
|
280
|
+
async eventResumePosition(epoch = this.eventEpoch) {
|
|
281
|
+
return this.withEventCheckpoint(async () => {
|
|
282
|
+
if (this.pendingCheckpointRollback) {
|
|
283
|
+
await this.restoreEventMetadata(this.pendingCheckpointRollback);
|
|
284
|
+
this.pendingCheckpointRollback = undefined;
|
|
285
|
+
}
|
|
286
|
+
const lastEventSeq = await this._payloadStore.miscellaneous?.get('lastEventSeq');
|
|
287
|
+
if (epoch !== this.eventEpoch) {
|
|
288
|
+
return { lastEventSeq };
|
|
289
|
+
}
|
|
290
|
+
if (this.pendingEventSeq !== undefined && this.pendingEventSeq > Number(lastEventSeq ?? 0)) {
|
|
291
|
+
this.failedEventSeq ??= this.pendingEventSeq;
|
|
292
|
+
}
|
|
293
|
+
this.pendingEventSeq = undefined;
|
|
294
|
+
return { lastEventSeq, accountId: await this._payloadStore.miscellaneous?.get('accountId') };
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async withEventCheckpoint(operation) {
|
|
298
|
+
const result = this.checkpointQueue.then(operation);
|
|
299
|
+
this.checkpointQueue = result.then(() => undefined, () => undefined);
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
async restoreEventMetadata(previous) {
|
|
303
|
+
for (const [key, value] of previous) {
|
|
304
|
+
if (value === undefined) {
|
|
305
|
+
await this._payloadStore.miscellaneous?.delete(key);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
await this._payloadStore.miscellaneous?.set(key, value);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async writeEventMetadata(changes, epoch) {
|
|
313
|
+
const isCurrent = () => epoch === undefined || this.isEventEpochCurrent(epoch);
|
|
314
|
+
if (!isCurrent()) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const previous = new Map();
|
|
318
|
+
for (const key of changes.keys()) {
|
|
319
|
+
previous.set(key, await this._payloadStore.miscellaneous?.get(key));
|
|
320
|
+
}
|
|
321
|
+
if (!isCurrent()) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
for (const [key, value] of changes) {
|
|
326
|
+
if (value === undefined) {
|
|
327
|
+
await this._payloadStore.miscellaneous?.delete(key);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
await this._payloadStore.miscellaneous?.set(key, value);
|
|
331
|
+
}
|
|
332
|
+
if (!isCurrent()) {
|
|
333
|
+
await this.restoreEventMetadata(previous);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
try {
|
|
340
|
+
await this.restoreEventMetadata(previous);
|
|
341
|
+
}
|
|
342
|
+
catch (rollbackError) {
|
|
343
|
+
this.pendingCheckpointRollback = previous;
|
|
344
|
+
this.log.error('PuppetService', 'checkpoint rollback failed: %s', rollbackError);
|
|
345
|
+
}
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async commitEventCheckpoint(seq, timestamp, epoch) {
|
|
350
|
+
await this.withEventCheckpoint(async () => {
|
|
351
|
+
if (!this.isEventEpochCurrent(epoch)) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const lastEventSeq = await this._payloadStore.miscellaneous?.get('lastEventSeq');
|
|
355
|
+
if (lastEventSeq && seq <= Number(lastEventSeq) && seq !== 1) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
await this.writeEventMetadata(new Map([
|
|
359
|
+
['lastEventTimestamp', timestamp], ['lastEventSeq', String(seq)],
|
|
360
|
+
]), epoch);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
reportStreamError(error) {
|
|
364
|
+
this.log.error('PuppetService', 'event processing failed: %s', error);
|
|
365
|
+
try {
|
|
366
|
+
this.emit('error', error);
|
|
367
|
+
}
|
|
368
|
+
catch (listenerError) {
|
|
369
|
+
this.log.error('PuppetService', 'error listener failed: %s', listenerError);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
haltEventStream(manager, event, error) {
|
|
373
|
+
this.failedEventSeq ??= event.getSeq();
|
|
374
|
+
this.suspendEventProcessing();
|
|
375
|
+
try {
|
|
376
|
+
manager.stopStream();
|
|
377
|
+
}
|
|
378
|
+
catch (stopError) {
|
|
379
|
+
this.log.error('PuppetService', 'stopping failed event stream failed: %s', stopError);
|
|
380
|
+
}
|
|
381
|
+
this.reportStreamError(error);
|
|
382
|
+
}
|
|
383
|
+
async onGrpcStreamEvent(event, epoch = this.eventEpoch) {
|
|
384
|
+
if (!this.isEventEpochCurrent(epoch)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
218
387
|
const type = event.getType();
|
|
219
388
|
const payload = event.getPayload();
|
|
220
389
|
const seq = event.getSeq();
|
|
@@ -228,15 +397,6 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
228
397
|
data: `onGrpcStreamEvent(${event_type_rev_js_1.EventTypeRev[type]})`,
|
|
229
398
|
});
|
|
230
399
|
}
|
|
231
|
-
if (seq && !config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
232
|
-
const { lastEventSeq } = await this.getMiscellaneousStoreData();
|
|
233
|
-
if (!lastEventSeq || (seq > Number(lastEventSeq) || seq === 1)) {
|
|
234
|
-
await this.setMiscellaneousStoreData({
|
|
235
|
-
lastEventSeq: seq.toString(),
|
|
236
|
-
lastEventTimestamp: timestamp,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
400
|
switch (type) {
|
|
241
401
|
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_DONG:
|
|
242
402
|
this.emit('dong', JSON.parse(payload));
|
|
@@ -259,11 +419,14 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
259
419
|
const loginPayload = JSON.parse(payload);
|
|
260
420
|
if (!config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
261
421
|
const { accountId } = await this.getMiscellaneousStoreData();
|
|
422
|
+
if (!this.isEventEpochCurrent(epoch)) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
262
425
|
if (accountId !== loginPayload.contactId) {
|
|
263
|
-
await this.resetMiscellaneousStoreData();
|
|
426
|
+
await this.resetMiscellaneousStoreData(epoch);
|
|
264
427
|
await this.setMiscellaneousStoreData({
|
|
265
428
|
accountId: loginPayload.contactId,
|
|
266
|
-
});
|
|
429
|
+
}, epoch);
|
|
267
430
|
}
|
|
268
431
|
}
|
|
269
432
|
(async () => this.login(loginPayload.contactId))().catch(e => this.log.error('PuppetService', 'onGrpcStreamEvent() this.login() rejection %s', e.message));
|
|
@@ -273,7 +436,7 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
273
436
|
{
|
|
274
437
|
const logoutPayload = JSON.parse(payload);
|
|
275
438
|
if (!config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
276
|
-
await this.resetMiscellaneousStoreData();
|
|
439
|
+
await this.resetMiscellaneousStoreData(epoch);
|
|
277
440
|
}
|
|
278
441
|
;
|
|
279
442
|
(async () => this.logout(logoutPayload.data))().catch(e => this.log.error('PuppetService', 'onGrpcStreamEvent() this.logout() rejection %s', e.message));
|
|
@@ -281,8 +444,25 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
281
444
|
break;
|
|
282
445
|
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_DIRTY:
|
|
283
446
|
await this.fastDirty(JSON.parse(payload));
|
|
447
|
+
if (!this.isEventEpochCurrent(epoch)) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
284
450
|
this.emit('dirty', JSON.parse(payload));
|
|
285
451
|
break;
|
|
452
|
+
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_ROOM_MEMBER_LOAD: {
|
|
453
|
+
const loadPayload = JSON.parse(payload);
|
|
454
|
+
(0, pb_payload_helper_js_1.validateRoomMemberLoadState)(loadPayload);
|
|
455
|
+
this.roomCache.invalidate(loadPayload.roomId);
|
|
456
|
+
await this.roomCache.run(loadPayload.roomId, async () => {
|
|
457
|
+
await this._payloadStore.room?.delete(loadPayload.roomId);
|
|
458
|
+
await this._payloadStore.roomMember?.delete(loadPayload.roomId);
|
|
459
|
+
});
|
|
460
|
+
if (!this.isEventEpochCurrent(epoch)) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
this.emit('room-member-load', loadPayload);
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
286
466
|
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_MESSAGE:
|
|
287
467
|
this.emit('message', JSON.parse(payload));
|
|
288
468
|
break;
|
|
@@ -345,10 +525,19 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
345
525
|
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_CALL:
|
|
346
526
|
this.emit('call', JSON.parse(payload));
|
|
347
527
|
break;
|
|
528
|
+
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_ORG_BROADCAST_CREATED:
|
|
529
|
+
this.emit('org-broadcast-created', JSON.parse(payload));
|
|
530
|
+
break;
|
|
531
|
+
case wechaty_grpc_1.puppet.EventType.EVENT_TYPE_ORG_BROADCAST_SENT:
|
|
532
|
+
this.emit('org-broadcast-sent', JSON.parse(payload));
|
|
533
|
+
break;
|
|
348
534
|
default:
|
|
349
535
|
// Huan(202003): in default, the `type` type should be `never`, please check.
|
|
350
536
|
this.log.error(`eventType ${type} unsupported! data: ${payload}`);
|
|
351
537
|
}
|
|
538
|
+
if (seq && this.isEventEpochCurrent(epoch) && !config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
539
|
+
await this.commitEventCheckpoint(seq, timestamp, epoch);
|
|
540
|
+
}
|
|
352
541
|
}
|
|
353
542
|
async logout(reason) {
|
|
354
543
|
this.log.verbose('PuppetService', 'logout(%s)', reason ? `"${reason}"` : '');
|
|
@@ -404,8 +593,14 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
404
593
|
[PUPPET.types.Dirty.Friendship]: async (_) => { },
|
|
405
594
|
[PUPPET.types.Dirty.Message]: async (_) => { },
|
|
406
595
|
[PUPPET.types.Dirty.Post]: async (_) => { },
|
|
407
|
-
[PUPPET.types.Dirty.Room]: async (id) =>
|
|
408
|
-
|
|
596
|
+
[PUPPET.types.Dirty.Room]: async (id) => {
|
|
597
|
+
this.roomCache.invalidate(id);
|
|
598
|
+
return this.roomCache.run(id, async () => this._payloadStore.room?.delete(id));
|
|
599
|
+
},
|
|
600
|
+
[PUPPET.types.Dirty.RoomMember]: async (id) => {
|
|
601
|
+
this.roomCache.invalidate(id);
|
|
602
|
+
return this.roomCache.run(id, async () => this._payloadStore.roomMember?.delete(id));
|
|
603
|
+
},
|
|
409
604
|
[PUPPET.types.Dirty.Tag]: async (id) => this._payloadStore.tag?.delete(id),
|
|
410
605
|
[PUPPET.types.Dirty.TagGroup]: async (id) => this._payloadStore.tagGroup?.delete(id),
|
|
411
606
|
[PUPPET.types.Dirty.Unspecified]: async (id) => { throw new Error('Unspecified type with id: ' + id); },
|
|
@@ -1574,8 +1769,9 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1574
1769
|
*/
|
|
1575
1770
|
async roomRawPayload(id) {
|
|
1576
1771
|
this.log.verbose('PuppetService', 'roomRawPayload(%s)', id);
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1772
|
+
const generation = this.roomCache.generation(id);
|
|
1773
|
+
const cachedPayload = await this.roomCache.run(id, async () => this._payloadStore.room?.get(id));
|
|
1774
|
+
if (cachedPayload && generation === this.roomCache.generation(id)) {
|
|
1579
1775
|
this.log.silly('PuppetService', 'roomRawPayload(%s) cache HIT', id);
|
|
1580
1776
|
return cachedPayload;
|
|
1581
1777
|
}
|
|
@@ -1583,26 +1779,52 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1583
1779
|
request.setId(id);
|
|
1584
1780
|
const response = await util_1.default.promisify(this.grpcManager.client.roomPayload
|
|
1585
1781
|
.bind(this.grpcManager.client))(request);
|
|
1586
|
-
const payload =
|
|
1587
|
-
|
|
1588
|
-
avatar: response.getAvatar(),
|
|
1589
|
-
handle: response.getHandle(),
|
|
1590
|
-
id: response.getId(),
|
|
1591
|
-
memberIdList: response.getMemberIdsList(),
|
|
1592
|
-
ownerId: response.getOwnerId(),
|
|
1593
|
-
topic: response.getTopic(),
|
|
1594
|
-
additionalInfo: response.getAdditionalInfo(),
|
|
1595
|
-
remark: response.getRoomRemark(),
|
|
1596
|
-
external: response.getExternal(),
|
|
1597
|
-
};
|
|
1598
|
-
const createTime = response.getCreateTime();
|
|
1599
|
-
if (createTime) {
|
|
1600
|
-
payload.createTime = (0, timestamp_js_1.millisecondsFromTimestamp)(createTime);
|
|
1601
|
-
}
|
|
1602
|
-
await this._payloadStore.room?.set(id, payload);
|
|
1782
|
+
const payload = (0, pb_payload_helper_js_1.roomPbToPayload)(response);
|
|
1783
|
+
await this.roomCache.commit(id, generation, async () => this._payloadStore.room?.set(id, payload));
|
|
1603
1784
|
this.log.silly('PuppetService', 'roomRawPayload(%s) cache SET', id);
|
|
1604
1785
|
return payload;
|
|
1605
1786
|
}
|
|
1787
|
+
async roomMemberSync(roomId, options) {
|
|
1788
|
+
if (!roomId) {
|
|
1789
|
+
throw new Error('roomId is required');
|
|
1790
|
+
}
|
|
1791
|
+
const request = new wechaty_grpc_1.puppet.RoomMemberSyncRequest();
|
|
1792
|
+
request.setId(roomId);
|
|
1793
|
+
if (options?.force !== undefined) {
|
|
1794
|
+
request.setForce(options.force);
|
|
1795
|
+
}
|
|
1796
|
+
const response = await util_1.default.promisify(this.grpcManager.client.roomMemberSync.bind(this.grpcManager.client))(request);
|
|
1797
|
+
return (0, pb_payload_helper_js_1.roomMemberLoadStatePbToPayload)(response, roomId);
|
|
1798
|
+
}
|
|
1799
|
+
async roomMemberLoadState(roomId) {
|
|
1800
|
+
if (!roomId) {
|
|
1801
|
+
throw new Error('roomId is required');
|
|
1802
|
+
}
|
|
1803
|
+
const request = new wechaty_grpc_1.puppet.RoomMemberLoadStateRequest();
|
|
1804
|
+
request.setId(roomId);
|
|
1805
|
+
const response = await util_1.default.promisify(this.grpcManager.client.roomMemberLoadState.bind(this.grpcManager.client))(request);
|
|
1806
|
+
return (0, pb_payload_helper_js_1.roomMemberLoadStatePbToPayload)(response, roomId);
|
|
1807
|
+
}
|
|
1808
|
+
async roomMemberSnapshot(roomId, revision, options) {
|
|
1809
|
+
if (!roomId) {
|
|
1810
|
+
throw new Error('roomId is required');
|
|
1811
|
+
}
|
|
1812
|
+
(0, pb_payload_helper_js_1.validateRoomMemberRevision)(revision);
|
|
1813
|
+
const request = new wechaty_grpc_1.puppet.RoomMemberSnapshotRequest();
|
|
1814
|
+
request.setId(roomId);
|
|
1815
|
+
request.setRevision(revision);
|
|
1816
|
+
if (options?.pageToken !== undefined) {
|
|
1817
|
+
request.setPageToken(options.pageToken);
|
|
1818
|
+
}
|
|
1819
|
+
if (options?.pageSize !== undefined) {
|
|
1820
|
+
if (!Number.isInteger(options.pageSize) || options.pageSize < 0 || options.pageSize > 500) {
|
|
1821
|
+
throw new Error('pageSize must be an integer between 0 and 500');
|
|
1822
|
+
}
|
|
1823
|
+
request.setPageSize(options.pageSize);
|
|
1824
|
+
}
|
|
1825
|
+
const response = await util_1.default.promisify(this.grpcManager.client.roomMemberSnapshot.bind(this.grpcManager.client))(request);
|
|
1826
|
+
return (0, pb_payload_helper_js_1.roomMemberSnapshotPbToPayload)(response, roomId, revision);
|
|
1827
|
+
}
|
|
1606
1828
|
async roomRawPayloadParser(payload) {
|
|
1607
1829
|
// this.log.silly('PuppetService', 'roomRawPayloadParser({id:%s})', payload.id)
|
|
1608
1830
|
// passthrough
|
|
@@ -1612,10 +1834,11 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1612
1834
|
this.log.verbose('PuppetService', 'batchRoomRawPayload(%s)', roomIdList);
|
|
1613
1835
|
const result = new Map();
|
|
1614
1836
|
const roomIdSet = new Set(roomIdList);
|
|
1837
|
+
const generations = new Map(Array.from(roomIdSet, id => [id, this.roomCache.generation(id)]));
|
|
1615
1838
|
const needGetSet = new Set();
|
|
1616
1839
|
for (const roomId of roomIdSet) {
|
|
1617
|
-
const cachedRoomPayload = await this._payloadStore.room?.get(roomId);
|
|
1618
|
-
if (cachedRoomPayload) {
|
|
1840
|
+
const cachedRoomPayload = await this.roomCache.run(roomId, async () => this._payloadStore.room?.get(roomId));
|
|
1841
|
+
if (cachedRoomPayload && generations.get(roomId) === this.roomCache.generation(roomId)) {
|
|
1619
1842
|
result.set(roomId, cachedRoomPayload);
|
|
1620
1843
|
}
|
|
1621
1844
|
else {
|
|
@@ -1631,27 +1854,18 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1631
1854
|
const payloads = response.getRoomPayloadsList();
|
|
1632
1855
|
for (const payload of payloads) {
|
|
1633
1856
|
const roomId = payload.getId();
|
|
1634
|
-
const puppetPayload =
|
|
1635
|
-
adminIdList: payload.getAdminIdsList(),
|
|
1636
|
-
avatar: payload.getAvatar(),
|
|
1637
|
-
handle: payload.getHandle(),
|
|
1638
|
-
id: payload.getId(),
|
|
1639
|
-
memberIdList: payload.getMemberIdsList(),
|
|
1640
|
-
ownerId: payload.getOwnerId(),
|
|
1641
|
-
topic: payload.getTopic(),
|
|
1642
|
-
additionalInfo: payload.getAdditionalInfo(),
|
|
1643
|
-
remark: payload.getRoomRemark(),
|
|
1644
|
-
external: payload.getExternal(),
|
|
1645
|
-
};
|
|
1646
|
-
const createTime = payload.getCreateTime();
|
|
1647
|
-
if (createTime) {
|
|
1648
|
-
puppetPayload.createTime = (0, timestamp_js_1.millisecondsFromTimestamp)(createTime);
|
|
1649
|
-
}
|
|
1857
|
+
const puppetPayload = (0, pb_payload_helper_js_1.roomPbToPayload)(payload);
|
|
1650
1858
|
result.set(roomId, puppetPayload);
|
|
1651
|
-
|
|
1859
|
+
const generation = generations.get(roomId);
|
|
1860
|
+
if (generation !== undefined) {
|
|
1861
|
+
await this.roomCache.commit(roomId, generation, async () => this._payloadStore.room?.set(roomId, puppetPayload));
|
|
1862
|
+
}
|
|
1652
1863
|
}
|
|
1653
1864
|
}
|
|
1654
1865
|
catch (e) {
|
|
1866
|
+
if (e instanceof room_cache_coordinator_js_1.RoomCacheOperationError) {
|
|
1867
|
+
throw e;
|
|
1868
|
+
}
|
|
1655
1869
|
this.log.error('PuppetService', 'batchRoomRawPayload(%s, %s) error: %s, use one by one method', roomIdList, needGetSet, e);
|
|
1656
1870
|
let fallbackSuccessCount = 0;
|
|
1657
1871
|
for (const roomId of needGetSet) {
|
|
@@ -1837,9 +2051,10 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1837
2051
|
}
|
|
1838
2052
|
async roomMemberRawPayload(roomId, contactId) {
|
|
1839
2053
|
this.log.verbose('PuppetService', 'roomMemberRawPayload(%s, %s)', roomId, contactId);
|
|
1840
|
-
const
|
|
2054
|
+
const generation = this.roomCache.generation(roomId);
|
|
2055
|
+
const cachedPayload = await this.roomCache.run(roomId, async () => this._payloadStore.roomMember?.get(roomId));
|
|
1841
2056
|
const cachedRoomMemberPayload = cachedPayload && cachedPayload[contactId];
|
|
1842
|
-
if (cachedRoomMemberPayload) {
|
|
2057
|
+
if (cachedRoomMemberPayload && generation === this.roomCache.generation(roomId)) {
|
|
1843
2058
|
this.log.silly('PuppetService', 'roomMemberRawPayload(%s, %s) cache HIT', roomId, contactId);
|
|
1844
2059
|
return cachedRoomMemberPayload;
|
|
1845
2060
|
}
|
|
@@ -1858,9 +2073,9 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1858
2073
|
joinScene: response.getJoinScene(),
|
|
1859
2074
|
joinTime: response.getJoinTime(),
|
|
1860
2075
|
};
|
|
1861
|
-
await this.
|
|
1862
|
-
|
|
1863
|
-
[contactId]: payload
|
|
2076
|
+
await this.roomCache.commit(roomId, generation, async () => {
|
|
2077
|
+
const current = await this._payloadStore.roomMember?.get(roomId);
|
|
2078
|
+
await this._payloadStore.roomMember?.set(roomId, { ...current, [contactId]: payload });
|
|
1864
2079
|
});
|
|
1865
2080
|
this.log.silly('PuppetService', 'roomMemberRawPayload(%s, %s) cache SET', roomId, contactId);
|
|
1866
2081
|
return payload;
|
|
@@ -1872,10 +2087,12 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1872
2087
|
}
|
|
1873
2088
|
async batchRoomMemberRawPayload(roomId, contactIdList) {
|
|
1874
2089
|
this.log.verbose('PuppetService', 'batchRoomMemberRawPayload(%s, %s)', roomId, contactIdList);
|
|
2090
|
+
const generation = this.roomCache.generation(roomId);
|
|
1875
2091
|
const result = new Map();
|
|
1876
2092
|
const contactIdSet = new Set(contactIdList);
|
|
1877
2093
|
let needGetSet = new Set();
|
|
1878
|
-
const
|
|
2094
|
+
const cached = await this.roomCache.run(roomId, async () => this._payloadStore.roomMember?.get(roomId));
|
|
2095
|
+
const cachedPayload = generation === this.roomCache.generation(roomId) ? cached || {} : {};
|
|
1879
2096
|
if (Object.keys(cachedPayload).length > 0) {
|
|
1880
2097
|
for (const contactId of contactIdSet) {
|
|
1881
2098
|
const cachedRoomMemberPayload = cachedPayload[contactId];
|
|
@@ -1898,15 +2115,22 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1898
2115
|
const response = await util_1.default.promisify(this.grpcManager.client.batchRoomMemberPayload
|
|
1899
2116
|
.bind(this.grpcManager.client))(request);
|
|
1900
2117
|
const payloads = response.getMemberPayloadsList();
|
|
2118
|
+
const fetched = {};
|
|
1901
2119
|
for (const payload of payloads) {
|
|
1902
2120
|
const contactId = payload.getId();
|
|
1903
2121
|
const puppetPayload = (0, pb_payload_helper_js_1.roomMemberPbToPayload)(payload);
|
|
1904
2122
|
result.set(contactId, puppetPayload);
|
|
1905
|
-
|
|
2123
|
+
fetched[contactId] = puppetPayload;
|
|
1906
2124
|
}
|
|
1907
|
-
await this.
|
|
2125
|
+
await this.roomCache.commit(roomId, generation, async () => {
|
|
2126
|
+
const current = await this._payloadStore.roomMember?.get(roomId);
|
|
2127
|
+
await this._payloadStore.roomMember?.set(roomId, { ...current, ...fetched });
|
|
2128
|
+
});
|
|
1908
2129
|
}
|
|
1909
2130
|
catch (e) {
|
|
2131
|
+
if (e instanceof room_cache_coordinator_js_1.RoomCacheOperationError) {
|
|
2132
|
+
throw e;
|
|
2133
|
+
}
|
|
1910
2134
|
this.log.error('PuppetService', 'batchRoomMemberRawPayload(%s, %s) error: %s, use one by one method', roomId, needGetSet, e);
|
|
1911
2135
|
for (const contactId of needGetSet) {
|
|
1912
2136
|
const payload = await this.roomMemberRawPayload(roomId, contactId);
|
|
@@ -2597,6 +2821,42 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
2597
2821
|
}
|
|
2598
2822
|
return result;
|
|
2599
2823
|
}
|
|
2824
|
+
async orgBroadcastPayload(orgBroadcastId) {
|
|
2825
|
+
this.log.verbose('PuppetService', 'orgBroadcastPayload(%s)', orgBroadcastId);
|
|
2826
|
+
const request = new wechaty_grpc_1.puppet.OrgBroadcastPayloadRequest();
|
|
2827
|
+
request.setId(orgBroadcastId);
|
|
2828
|
+
const response = await util_1.default.promisify(this.grpcManager.client.orgBroadcastPayload.bind(this.grpcManager.client))(request);
|
|
2829
|
+
return {
|
|
2830
|
+
id: response.getId(),
|
|
2831
|
+
sendType: response.getSendType(),
|
|
2832
|
+
conversationType: response.getConversationType(),
|
|
2833
|
+
creatorId: response.getCreatorId() || undefined,
|
|
2834
|
+
execTime: response.getExecTime(),
|
|
2835
|
+
status: response.getStatus(),
|
|
2836
|
+
canCancel: response.getCanCancel(),
|
|
2837
|
+
allowSelect: response.getAllowSelect(),
|
|
2838
|
+
sent: response.getSent(),
|
|
2839
|
+
totalCount: response.getTotalCount(),
|
|
2840
|
+
sentCount: response.getSentCount(),
|
|
2841
|
+
contentListJson: response.getContentListJson(),
|
|
2842
|
+
targets: response.getTargetsList().map(targetPb => ({
|
|
2843
|
+
contactId: targetPb.getContactId() || undefined,
|
|
2844
|
+
roomId: targetPb.getRoomId() || undefined,
|
|
2845
|
+
status: targetPb.getStatus(),
|
|
2846
|
+
})),
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
async orgBroadcastExecute(orgBroadcastId, targetIds) {
|
|
2850
|
+
this.log.verbose('PuppetService', 'orgBroadcastExecute(%s, %s)', orgBroadcastId, targetIds?.length);
|
|
2851
|
+
// on the wire an empty target_ids means all targets, so an explicit empty list must not pass through
|
|
2852
|
+
if (targetIds && targetIds.length === 0) {
|
|
2853
|
+
throw new Error('targetIds is empty, omit it to send to all targets of the org broadcast');
|
|
2854
|
+
}
|
|
2855
|
+
const request = new wechaty_grpc_1.puppet.OrgBroadcastExecuteRequest();
|
|
2856
|
+
request.setId(orgBroadcastId);
|
|
2857
|
+
request.setTargetIdsList(targetIds ?? []);
|
|
2858
|
+
await util_1.default.promisify(this.grpcManager.client.orgBroadcastExecute.bind(this.grpcManager.client))(request);
|
|
2859
|
+
}
|
|
2600
2860
|
healthCheckInterval;
|
|
2601
2861
|
startHealthCheck() {
|
|
2602
2862
|
this.healthCheckInterval = setInterval(() => {
|
|
@@ -2612,23 +2872,40 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
2612
2872
|
waitingForReady = false;
|
|
2613
2873
|
reconnectIndicator;
|
|
2614
2874
|
async reset() {
|
|
2615
|
-
if (!this._grpcManager) {
|
|
2616
|
-
this.log.warn('PuppetService', 'grpc manager not constructed, perform regular reset');
|
|
2617
|
-
return super.reset();
|
|
2618
|
-
}
|
|
2619
|
-
if (!this.isLoggedIn) {
|
|
2620
|
-
this.log.warn('PuppetService', 'puppet not logged in, perform regular reset');
|
|
2621
|
-
return super.reset();
|
|
2622
|
-
}
|
|
2623
2875
|
if (this.reconnectIndicator.value()) {
|
|
2624
2876
|
this.log.warn('PuppetService', 'already trying to reconnect, pass this one');
|
|
2625
2877
|
return;
|
|
2626
2878
|
}
|
|
2627
2879
|
this.reconnectIndicator.value(true);
|
|
2628
|
-
this.
|
|
2629
|
-
const
|
|
2880
|
+
this.suspendEventProcessing();
|
|
2881
|
+
const epoch = this.eventEpoch;
|
|
2882
|
+
const manager = this._grpcManager;
|
|
2883
|
+
try {
|
|
2884
|
+
await this.checkpointQueue;
|
|
2885
|
+
if (epoch !== this.eventEpoch) {
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
if (!manager || !this.isLoggedIn) {
|
|
2889
|
+
this.log.warn('PuppetService', 'grpc manager unavailable or puppet logged out, perform regular reset');
|
|
2890
|
+
return await super.reset();
|
|
2891
|
+
}
|
|
2892
|
+
await this.resetEventStream(manager, epoch);
|
|
2893
|
+
}
|
|
2894
|
+
finally {
|
|
2895
|
+
this.reconnectIndicator.value(false);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
async resetEventStream(manager, epoch) {
|
|
2899
|
+
manager.stopStream();
|
|
2900
|
+
const { lastEventSeq, accountId } = await this.eventResumePosition(epoch);
|
|
2901
|
+
if (epoch !== this.eventEpoch || manager !== this._grpcManager) {
|
|
2902
|
+
return;
|
|
2903
|
+
}
|
|
2630
2904
|
const onLoginResolve = (resolve) => {
|
|
2631
2905
|
const onLogin = (event) => {
|
|
2906
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2632
2909
|
const type = event.getType();
|
|
2633
2910
|
const payload = event.getPayload();
|
|
2634
2911
|
if (this.waitingForLogin && type === wechaty_grpc_1.puppet.EventType.EVENT_TYPE_LOGIN) {
|
|
@@ -2644,6 +2921,9 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
2644
2921
|
};
|
|
2645
2922
|
const onReadyResolve = (resolve) => {
|
|
2646
2923
|
const onReady = (event) => {
|
|
2924
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2647
2927
|
const type = event.getType();
|
|
2648
2928
|
if (this.waitingForReady && type === wechaty_grpc_1.puppet.EventType.EVENT_TYPE_READY) {
|
|
2649
2929
|
this.waitingForReady = false;
|
|
@@ -2652,60 +2932,85 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
2652
2932
|
};
|
|
2653
2933
|
return onReady;
|
|
2654
2934
|
};
|
|
2655
|
-
|
|
2656
|
-
let onReady;
|
|
2935
|
+
const removeListeners = [];
|
|
2657
2936
|
const loginFuture = new Promise(resolve => {
|
|
2658
|
-
onLogin = onLoginResolve(resolve);
|
|
2659
|
-
|
|
2937
|
+
const onLogin = onLoginResolve(resolve);
|
|
2938
|
+
manager.on('data', onLogin);
|
|
2939
|
+
removeListeners.push(() => { manager.off('data', onLogin); });
|
|
2660
2940
|
});
|
|
2661
2941
|
const readyFuture = new Promise(resolve => {
|
|
2662
|
-
onReady = onReadyResolve(resolve);
|
|
2663
|
-
|
|
2942
|
+
const onReady = onReadyResolve(resolve);
|
|
2943
|
+
manager.on('data', onReady);
|
|
2944
|
+
removeListeners.push(() => { manager.off('data', onReady); });
|
|
2664
2945
|
});
|
|
2665
2946
|
const startTime = Date.now();
|
|
2666
2947
|
const timeoutMilliseconds = this.timeoutMilliseconds / 10; // 2 min default, 4 min xiaoju-bot
|
|
2667
|
-
|
|
2948
|
+
this.waitingForLogin = true;
|
|
2949
|
+
this.waitingForReady = true;
|
|
2950
|
+
this.eventsBlocked = false;
|
|
2951
|
+
try {
|
|
2952
|
+
while (true) {
|
|
2953
|
+
try {
|
|
2954
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
await (0, gerror_1.timeoutPromise)(manager.startStream(lastEventSeq, accountId), 30 * 1000);
|
|
2958
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
break;
|
|
2962
|
+
}
|
|
2963
|
+
catch (e) {
|
|
2964
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
if (Date.now() - startTime < timeoutMilliseconds) {
|
|
2968
|
+
this.log.warn('failed to start stream, will try again in 15 seconds');
|
|
2969
|
+
await new Promise(resolve => {
|
|
2970
|
+
setTimeout(resolve, 5000);
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
else {
|
|
2974
|
+
this.log.warn('failed to start stream and reaches timeout, will perform regular reset');
|
|
2975
|
+
return super.reset();
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2668
2979
|
try {
|
|
2669
|
-
await (0, gerror_1.timeoutPromise)(
|
|
2670
|
-
|
|
2980
|
+
await (0, gerror_1.timeoutPromise)(loginFuture, ResetLoginTimeout)
|
|
2981
|
+
.finally(() => {
|
|
2982
|
+
if (epoch === this.eventEpoch) {
|
|
2983
|
+
this.waitingForLogin = false;
|
|
2984
|
+
}
|
|
2985
|
+
});
|
|
2671
2986
|
}
|
|
2672
2987
|
catch (e) {
|
|
2673
|
-
if (
|
|
2674
|
-
|
|
2675
|
-
await new Promise(resolve => {
|
|
2676
|
-
setTimeout(resolve, 5000);
|
|
2677
|
-
});
|
|
2678
|
-
}
|
|
2679
|
-
else {
|
|
2680
|
-
this.log.warn('failed to start stream and reaches timeout, will perform regular reset');
|
|
2681
|
-
this.reconnectIndicator.value(false);
|
|
2682
|
-
return super.reset();
|
|
2988
|
+
if (!this.ownsEventWorker(manager, epoch)) {
|
|
2989
|
+
return;
|
|
2683
2990
|
}
|
|
2991
|
+
this.log.warn('PuppetService', 'waiting for event reset login error, will perform regular reset');
|
|
2992
|
+
return super.reset();
|
|
2993
|
+
}
|
|
2994
|
+
try {
|
|
2995
|
+
await (0, gerror_1.timeoutPromise)(readyFuture, ResetReadyTimeout)
|
|
2996
|
+
.finally(() => {
|
|
2997
|
+
if (epoch === this.eventEpoch) {
|
|
2998
|
+
this.waitingForReady = false;
|
|
2999
|
+
}
|
|
3000
|
+
});
|
|
3001
|
+
}
|
|
3002
|
+
catch (e) {
|
|
3003
|
+
this.log.warn('PuppetService', 'waiting for event reset ready error, will do nothing');
|
|
2684
3004
|
}
|
|
2685
3005
|
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
3006
|
+
finally {
|
|
3007
|
+
for (const removeListener of removeListeners) {
|
|
3008
|
+
removeListener();
|
|
3009
|
+
}
|
|
3010
|
+
if (epoch === this.eventEpoch) {
|
|
2691
3011
|
this.waitingForLogin = false;
|
|
2692
|
-
this.reconnectIndicator.value(false);
|
|
2693
|
-
this.grpcManager.off('data', onLogin);
|
|
2694
|
-
});
|
|
2695
|
-
}
|
|
2696
|
-
catch (e) {
|
|
2697
|
-
this.log.warn('PuppetService', 'waiting for event reset login error, will perform regular reset');
|
|
2698
|
-
return super.reset();
|
|
2699
|
-
}
|
|
2700
|
-
try {
|
|
2701
|
-
await (0, gerror_1.timeoutPromise)(readyFuture, ResetReadyTimeout)
|
|
2702
|
-
.finally(() => {
|
|
2703
3012
|
this.waitingForReady = false;
|
|
2704
|
-
|
|
2705
|
-
});
|
|
2706
|
-
}
|
|
2707
|
-
catch (e) {
|
|
2708
|
-
this.log.warn('PuppetService', 'waiting for event reset ready error, will do nothing');
|
|
3013
|
+
}
|
|
2709
3014
|
}
|
|
2710
3015
|
}
|
|
2711
3016
|
async getMiscellaneousStoreData() {
|
|
@@ -2729,27 +3034,29 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
2729
3034
|
accountId,
|
|
2730
3035
|
};
|
|
2731
3036
|
}
|
|
2732
|
-
async setMiscellaneousStoreData(data) {
|
|
3037
|
+
async setMiscellaneousStoreData(data, epoch) {
|
|
2733
3038
|
if (config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
2734
3039
|
return;
|
|
2735
3040
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
3041
|
+
const changes = new Map();
|
|
3042
|
+
if (data.lastEventTimestamp !== undefined) {
|
|
3043
|
+
changes.set('lastEventTimestamp', data.lastEventTimestamp);
|
|
2738
3044
|
}
|
|
2739
|
-
if (
|
|
2740
|
-
|
|
3045
|
+
if (data.accountId !== undefined) {
|
|
3046
|
+
changes.set('accountId', data.accountId);
|
|
2741
3047
|
}
|
|
2742
|
-
if (
|
|
2743
|
-
|
|
3048
|
+
if (data.lastEventSeq !== undefined) {
|
|
3049
|
+
changes.set('lastEventSeq', data.lastEventSeq);
|
|
2744
3050
|
}
|
|
3051
|
+
await this.withEventCheckpoint(async () => this.writeEventMetadata(changes, epoch));
|
|
2745
3052
|
}
|
|
2746
|
-
async resetMiscellaneousStoreData() {
|
|
3053
|
+
async resetMiscellaneousStoreData(epoch) {
|
|
2747
3054
|
if (config_js_1.envVars.WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE()) {
|
|
2748
3055
|
return;
|
|
2749
3056
|
}
|
|
2750
|
-
await this.
|
|
2751
|
-
|
|
2752
|
-
|
|
3057
|
+
await this.withEventCheckpoint(async () => this.writeEventMetadata(new Map([
|
|
3058
|
+
['lastEventSeq', undefined], ['lastEventTimestamp', undefined], ['accountId', undefined],
|
|
3059
|
+
]), epoch));
|
|
2753
3060
|
}
|
|
2754
3061
|
}
|
|
2755
3062
|
exports.PuppetService = PuppetService;
|