@juzi/wechaty-puppet-service 1.0.123 → 1.0.125
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/client/grpc-manager.d.ts +1 -0
- package/dist/cjs/src/client/grpc-manager.d.ts.map +1 -1
- package/dist/cjs/src/client/grpc-manager.js +49 -47
- package/dist/cjs/src/client/grpc-manager.js.map +1 -1
- package/dist/cjs/src/client/payload-store.d.ts +3 -0
- package/dist/cjs/src/client/payload-store.d.ts.map +1 -1
- package/dist/cjs/src/client/payload-store.js +8 -6
- package/dist/cjs/src/client/payload-store.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.d.ts.map +1 -1
- package/dist/cjs/src/client/puppet-service.js +336 -227
- package/dist/cjs/src/client/puppet-service.js.map +1 -1
- package/dist/cjs/src/package-json.d.ts.map +1 -1
- package/dist/cjs/src/package-json.js +4 -3
- package/dist/cjs/src/package-json.js.map +1 -1
- package/dist/cjs/tests/dirty-gen-guard.spec.d.ts +3 -0
- package/dist/cjs/tests/dirty-gen-guard.spec.d.ts.map +1 -0
- package/dist/cjs/tests/dirty-gen-guard.spec.js +206 -0
- package/dist/cjs/tests/dirty-gen-guard.spec.js.map +1 -0
- package/dist/esm/src/client/grpc-manager.d.ts +1 -0
- package/dist/esm/src/client/grpc-manager.d.ts.map +1 -1
- package/dist/esm/src/client/grpc-manager.js +50 -48
- package/dist/esm/src/client/grpc-manager.js.map +1 -1
- package/dist/esm/src/client/payload-store.d.ts +3 -0
- package/dist/esm/src/client/payload-store.d.ts.map +1 -1
- package/dist/esm/src/client/payload-store.js +8 -6
- package/dist/esm/src/client/payload-store.js.map +1 -1
- package/dist/esm/src/client/puppet-service.d.ts.map +1 -1
- package/dist/esm/src/client/puppet-service.js +336 -227
- package/dist/esm/src/client/puppet-service.js.map +1 -1
- package/dist/esm/src/package-json.d.ts.map +1 -1
- package/dist/esm/src/package-json.js +4 -3
- package/dist/esm/src/package-json.js.map +1 -1
- package/dist/esm/tests/dirty-gen-guard.spec.d.ts +3 -0
- package/dist/esm/tests/dirty-gen-guard.spec.d.ts.map +1 -0
- package/dist/esm/tests/dirty-gen-guard.spec.js +178 -0
- package/dist/esm/tests/dirty-gen-guard.spec.js.map +1 -0
- package/package.json +4 -3
- package/src/client/grpc-manager.ts +54 -48
- package/src/client/payload-store.ts +13 -7
- package/src/client/puppet-service.ts +337 -228
- package/src/package-json.ts +4 -3
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
/**
|
|
3
|
+
* Regression tests for the FlashStore write-back generation guard.
|
|
4
|
+
*
|
|
5
|
+
* `_payloadStore` (FlashStore, on disk) is a cache layer independent of
|
|
6
|
+
* the puppet-side LRU. Before this fix it had no protection against the
|
|
7
|
+
* "dirty lands during a raw fetch" race:
|
|
8
|
+
*
|
|
9
|
+
* 1. A raw fetch (e.g. `contactRawPayload`) starts a gRPC round-trip.
|
|
10
|
+
* 2. An EVENT_TYPE_DIRTY arrives; `fastDirty` deletes the FlashStore row.
|
|
11
|
+
* 3. The in-flight fetch resolves and writes the *pre-dirty* payload
|
|
12
|
+
* back into the FlashStore -- re-poisoning the row that was just
|
|
13
|
+
* cleared. The value then only refreshes after a *second* dirty.
|
|
14
|
+
*
|
|
15
|
+
* The fix snapshots a per-(type, id) generation counter before the raw
|
|
16
|
+
* fetch and re-checks it with `isFreshWrite` before every FlashStore
|
|
17
|
+
* write-back; the EVENT_TYPE_DIRTY handler bumps that counter before it
|
|
18
|
+
* even awaits `fastDirty`, so the whole delete window is covered.
|
|
19
|
+
*/
|
|
20
|
+
import { test } from 'tstest';
|
|
21
|
+
import os from 'os';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
import fs from 'fs';
|
|
24
|
+
import * as PUPPET from '@juzi/wechaty-puppet';
|
|
25
|
+
import { puppet as grpcPuppet } from '@juzi/wechaty-grpc';
|
|
26
|
+
import { PuppetService } from '../src/mod.js';
|
|
27
|
+
const makePuppet = async () => {
|
|
28
|
+
const token = `puppet_service_test_${Date.now()}_${Math.floor(Math.random() * 1e6)}`;
|
|
29
|
+
const puppet = new PuppetService({ token });
|
|
30
|
+
const accountId = 'acct-test';
|
|
31
|
+
await puppet._payloadStore.start(accountId);
|
|
32
|
+
return { puppet, token };
|
|
33
|
+
};
|
|
34
|
+
const cleanup = async (puppet, token) => {
|
|
35
|
+
await puppet._payloadStore.stop();
|
|
36
|
+
try {
|
|
37
|
+
await fs.promises.rm(path.join(os.homedir(), '.wechaty', 'wechaty-puppet-service', token), { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
catch (_) { /* ignore */ }
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A one-shot gate for a fake gRPC method. The method resolves `entered`
|
|
43
|
+
* as soon as it is invoked (by which point the caller's gen snapshot has
|
|
44
|
+
* already been taken, since the snapshot precedes the fetch call), then
|
|
45
|
+
* holds its callback until `release()` is called. This lets the test slot
|
|
46
|
+
* a dirty deterministically between the fetch start (gen snapshot) and
|
|
47
|
+
* the fetch resolution (write-back) -- no timers, no flakiness.
|
|
48
|
+
*/
|
|
49
|
+
const makeGate = () => {
|
|
50
|
+
let release = () => { };
|
|
51
|
+
let markEntered = () => { };
|
|
52
|
+
const gate = new Promise(resolve => { release = resolve; });
|
|
53
|
+
const entered = new Promise(resolve => { markEntered = resolve; });
|
|
54
|
+
return { gate, entered, enter: () => markEntered(), release: () => release() };
|
|
55
|
+
};
|
|
56
|
+
test('contactRawPayload: a dirty mid-fetch skips the stale FlashStore write-back', async (t) => {
|
|
57
|
+
const { puppet, token } = await makePuppet();
|
|
58
|
+
const contactId = 'contact-race';
|
|
59
|
+
const response = new grpcPuppet.ContactPayloadResponse();
|
|
60
|
+
response.setId(contactId);
|
|
61
|
+
response.setName('stale-name-from-inflight-fetch');
|
|
62
|
+
const { gate, entered, enter, release } = makeGate();
|
|
63
|
+
puppet._grpcManager = {
|
|
64
|
+
client: {
|
|
65
|
+
contactPayload: (_req, cb) => {
|
|
66
|
+
enter();
|
|
67
|
+
void (async () => {
|
|
68
|
+
await gate;
|
|
69
|
+
cb(null, response);
|
|
70
|
+
})();
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
// Start the fetch: it snapshots the gen, then blocks on the gate.
|
|
75
|
+
const fetchPromise = puppet.contactRawPayload(contactId);
|
|
76
|
+
// Deterministic: once the fake method is entered, the snapshot is taken.
|
|
77
|
+
await entered;
|
|
78
|
+
// A dirty arrives while the fetch is in flight: bump gen + clear store,
|
|
79
|
+
// exactly as the EVENT_TYPE_DIRTY handler does.
|
|
80
|
+
puppet.cache.bumpGen(PUPPET.types.Dirty.Contact, contactId);
|
|
81
|
+
await puppet.fastDirty({ payloadType: PUPPET.types.Dirty.Contact, payloadId: contactId });
|
|
82
|
+
// Now let the stale fetch resolve into the write-back path.
|
|
83
|
+
release();
|
|
84
|
+
const returned = await fetchPromise;
|
|
85
|
+
t.equal(returned.id, contactId, 'raw fetch still returns its payload to the caller');
|
|
86
|
+
const stored = await puppet._payloadStore.contact.get(contactId);
|
|
87
|
+
t.notOk(stored, 'stale in-flight fetch must NOT re-poison the FlashStore after the dirty');
|
|
88
|
+
await cleanup(puppet, token);
|
|
89
|
+
});
|
|
90
|
+
test('contactRawPayload: no dirty means the write-back proceeds as usual', async (t) => {
|
|
91
|
+
const { puppet, token } = await makePuppet();
|
|
92
|
+
const contactId = 'contact-happy';
|
|
93
|
+
const response = new grpcPuppet.ContactPayloadResponse();
|
|
94
|
+
response.setId(contactId);
|
|
95
|
+
response.setName('fresh-name');
|
|
96
|
+
puppet._grpcManager = {
|
|
97
|
+
client: {
|
|
98
|
+
contactPayload: (_req, cb) => cb(null, response),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
const returned = await puppet.contactRawPayload(contactId);
|
|
102
|
+
t.equal(returned.id, contactId, 'raw fetch returns its payload');
|
|
103
|
+
const stored = await puppet._payloadStore.contact.get(contactId);
|
|
104
|
+
t.ok(stored, 'without a racing dirty the payload is written to the FlashStore');
|
|
105
|
+
t.equal(stored && stored.id, contactId, 'stored payload matches the fetched id');
|
|
106
|
+
await cleanup(puppet, token);
|
|
107
|
+
});
|
|
108
|
+
test('EVENT_TYPE_DIRTY bumps gen before awaiting fastDirty so pre-event snapshots are stale', async (t) => {
|
|
109
|
+
const { puppet, token } = await makePuppet();
|
|
110
|
+
const contactId = 'contact-bump';
|
|
111
|
+
// A getter that snapshotted just before the event arrived.
|
|
112
|
+
const snapshot = puppet.cache.snapshotGen(PUPPET.types.Dirty.Contact, contactId);
|
|
113
|
+
const dirtyJson = JSON.stringify({
|
|
114
|
+
payloadType: PUPPET.types.Dirty.Contact,
|
|
115
|
+
payloadId: contactId,
|
|
116
|
+
});
|
|
117
|
+
await puppet.onGrpcStreamEvent({
|
|
118
|
+
getType: () => grpcPuppet.EventType.EVENT_TYPE_DIRTY,
|
|
119
|
+
getPayload: () => dirtyJson,
|
|
120
|
+
getSeq: () => 0,
|
|
121
|
+
});
|
|
122
|
+
t.notOk(puppet.cache.isFreshWrite(PUPPET.types.Dirty.Contact, contactId, snapshot), 'a snapshot taken before the dirty event must be judged stale afterwards');
|
|
123
|
+
await cleanup(puppet, token);
|
|
124
|
+
});
|
|
125
|
+
test('EVENT_TYPE_DIRTY compound RoomMember bumps both the compound and the room-level gen', async (t) => {
|
|
126
|
+
const { puppet, token } = await makePuppet();
|
|
127
|
+
const roomId = 'room-bump';
|
|
128
|
+
const memberId = 'member-bump';
|
|
129
|
+
const compoundId = `${roomId}${PUPPET.STRING_SPLITTER}${memberId}`;
|
|
130
|
+
const compoundSnap = puppet.cache.snapshotGen(PUPPET.types.Dirty.RoomMember, compoundId);
|
|
131
|
+
const roomSnap = puppet.cache.snapshotGen(PUPPET.types.Dirty.RoomMember, roomId);
|
|
132
|
+
const dirtyJson = JSON.stringify({
|
|
133
|
+
payloadType: PUPPET.types.Dirty.RoomMember,
|
|
134
|
+
payloadId: compoundId,
|
|
135
|
+
});
|
|
136
|
+
await puppet.onGrpcStreamEvent({
|
|
137
|
+
getType: () => grpcPuppet.EventType.EVENT_TYPE_DIRTY,
|
|
138
|
+
getPayload: () => dirtyJson,
|
|
139
|
+
getSeq: () => 0,
|
|
140
|
+
});
|
|
141
|
+
t.notOk(puppet.cache.isFreshWrite(PUPPET.types.Dirty.RoomMember, compoundId, compoundSnap), 'the compound (roomId+SEP+memberId) key must be bumped');
|
|
142
|
+
t.notOk(puppet.cache.isFreshWrite(PUPPET.types.Dirty.RoomMember, roomId, roomSnap), 'the bare room-level key must also be bumped so row-level write-backs are guarded');
|
|
143
|
+
await cleanup(puppet, token);
|
|
144
|
+
});
|
|
145
|
+
test('roomMemberRawPayload: a room-level dirty mid-fetch skips the row write-back', async (t) => {
|
|
146
|
+
const { puppet, token } = await makePuppet();
|
|
147
|
+
const roomId = 'room-member-race';
|
|
148
|
+
const contactId = 'member-race';
|
|
149
|
+
const response = new grpcPuppet.RoomMemberPayloadResponse();
|
|
150
|
+
response.setId(contactId);
|
|
151
|
+
response.setName('stale-member-from-inflight-fetch');
|
|
152
|
+
const { gate, entered, enter, release } = makeGate();
|
|
153
|
+
puppet._grpcManager = {
|
|
154
|
+
client: {
|
|
155
|
+
roomMemberPayload: (_req, cb) => {
|
|
156
|
+
enter();
|
|
157
|
+
void (async () => {
|
|
158
|
+
await gate;
|
|
159
|
+
cb(null, response);
|
|
160
|
+
})();
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
// Start the fetch: it snapshots the room-level gen before reading the
|
|
165
|
+
// row, then blocks on the gate.
|
|
166
|
+
const fetchPromise = puppet.roomMemberRawPayload(roomId, contactId);
|
|
167
|
+
await entered;
|
|
168
|
+
// A bare-roomId dirty lands mid-fetch: the whole member set is stale.
|
|
169
|
+
puppet.cache.bumpGen(PUPPET.types.Dirty.RoomMember, roomId);
|
|
170
|
+
await puppet.fastDirty({ payloadType: PUPPET.types.Dirty.RoomMember, payloadId: roomId });
|
|
171
|
+
release();
|
|
172
|
+
const returned = await fetchPromise;
|
|
173
|
+
t.equal(returned.id, contactId, 'raw fetch still returns its member payload to the caller');
|
|
174
|
+
const stored = await puppet._payloadStore.roomMember.get(roomId);
|
|
175
|
+
t.notOk(stored, 'stale in-flight member fetch must NOT re-create the row after the dirty');
|
|
176
|
+
await cleanup(puppet, token);
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=dirty-gen-guard.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dirty-gen-guard.spec.js","sourceRoot":"","sources":["../../../tests/dirty-gen-guard.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juzi/wechaty-puppet-service",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.125",
|
|
4
4
|
"description": "Puppet Service for Wechaty",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -51,11 +51,12 @@
|
|
|
51
51
|
"@chatie/eslint-config": "^1.0.4",
|
|
52
52
|
"@chatie/semver": "^0.4.7",
|
|
53
53
|
"@chatie/tsconfig": "^4.6.3",
|
|
54
|
-
"@juzi/wechaty-puppet": "^1.0.
|
|
54
|
+
"@juzi/wechaty-puppet": "^1.0.150",
|
|
55
55
|
"@juzi/wechaty-puppet-mock": "^1.0.1",
|
|
56
56
|
"@swc/core": "1.3.39",
|
|
57
57
|
"@types/google-protobuf": "^3.15.5",
|
|
58
58
|
"@types/lru-cache": "^7.5.0",
|
|
59
|
+
"@types/node": "^20",
|
|
59
60
|
"@types/semver": "^7.3.9",
|
|
60
61
|
"@types/temp": "^0.9.1",
|
|
61
62
|
"@types/uuid": "^8.3.4",
|
|
@@ -70,7 +71,7 @@
|
|
|
70
71
|
"why-is-node-running": "^2.2.1"
|
|
71
72
|
},
|
|
72
73
|
"peerDependencies": {
|
|
73
|
-
"@juzi/wechaty-puppet": "^1.0.
|
|
74
|
+
"@juzi/wechaty-puppet": "^1.0.150"
|
|
74
75
|
},
|
|
75
76
|
"dependencies": {
|
|
76
77
|
"@juzi/wechaty-grpc": "^1.0.106",
|
|
@@ -21,7 +21,10 @@ import util from 'util'
|
|
|
21
21
|
import EventEmitter from 'events'
|
|
22
22
|
import crypto from 'crypto'
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
log,
|
|
26
|
+
type LoggerLike,
|
|
27
|
+
} from '@juzi/wechaty-puppet'
|
|
25
28
|
import {
|
|
26
29
|
grpc,
|
|
27
30
|
puppet,
|
|
@@ -78,14 +81,17 @@ class GrpcManager extends EventEmitter {
|
|
|
78
81
|
serverName : string
|
|
79
82
|
token : WechatyToken
|
|
80
83
|
|
|
84
|
+
private readonly _log: LoggerLike
|
|
85
|
+
|
|
81
86
|
constructor (private options: PuppetServiceOptions) {
|
|
82
87
|
super()
|
|
83
|
-
|
|
88
|
+
this._log = options.logger ?? log
|
|
89
|
+
this._log.verbose('GrpcManager', 'constructor(%s)', JSON.stringify(options))
|
|
84
90
|
|
|
85
91
|
this.caCert = Buffer.from(
|
|
86
92
|
envVars.WECHATY_PUPPET_SERVICE_TLS_CA_CERT(this.options.tls?.caCert) || TLS_CA_CERT,
|
|
87
93
|
)
|
|
88
|
-
|
|
94
|
+
this._log.verbose('GrpcManager', 'constructor() tlsRootCert(hash): "%s"',
|
|
89
95
|
crypto.createHash('sha256')
|
|
90
96
|
.update(this.caCert)
|
|
91
97
|
.digest('hex'),
|
|
@@ -97,7 +103,7 @@ class GrpcManager extends EventEmitter {
|
|
|
97
103
|
this.token = new WechatyToken(
|
|
98
104
|
envVars.WECHATY_PUPPET_SERVICE_TOKEN(this.options.token),
|
|
99
105
|
)
|
|
100
|
-
|
|
106
|
+
this._log.verbose('GrpcManager', 'constructor() token: "%s"', this.token)
|
|
101
107
|
|
|
102
108
|
this.endpoint = envVars.WECHATY_PUPPET_SERVICE_ENDPOINT(this.options.endpoint)
|
|
103
109
|
/**
|
|
@@ -110,13 +116,13 @@ class GrpcManager extends EventEmitter {
|
|
|
110
116
|
'/',
|
|
111
117
|
this.token,
|
|
112
118
|
].join('')
|
|
113
|
-
|
|
119
|
+
this._log.verbose('GrpcManager', 'constructor() endpoint: "%s"', this.endpoint)
|
|
114
120
|
|
|
115
121
|
/**
|
|
116
122
|
* Disable TLS
|
|
117
123
|
*/
|
|
118
124
|
this.disableTls = envVars.WECHATY_PUPPET_SERVICE_NO_TLS_INSECURE_CLIENT(this.options.tls?.disable)
|
|
119
|
-
|
|
125
|
+
this._log.verbose('GrpcManager', 'constructor() disableTls: "%s"', this.disableTls)
|
|
120
126
|
|
|
121
127
|
/**
|
|
122
128
|
* for Node.js TLS SNI
|
|
@@ -141,59 +147,59 @@ class GrpcManager extends EventEmitter {
|
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
this.serverName = serverNameIndication
|
|
144
|
-
|
|
150
|
+
this._log.verbose('GrpcManager', 'constructor() serverName(SNI): "%s"', this.serverName)
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
async start (lastEventSeq?: string, accountId?: string): Promise<void> {
|
|
148
|
-
|
|
154
|
+
this._log.verbose('GrpcManager', 'start()')
|
|
149
155
|
|
|
150
156
|
/**
|
|
151
157
|
* 1. Init grpc client
|
|
152
158
|
*/
|
|
153
|
-
|
|
159
|
+
this._log.verbose('GrpcManager', 'start() initializing client ...')
|
|
154
160
|
await this.initClient()
|
|
155
|
-
|
|
161
|
+
this._log.verbose('GrpcManager', 'start() initializing client ... done')
|
|
156
162
|
|
|
157
163
|
/**
|
|
158
164
|
* 2. Connect to stream
|
|
159
165
|
*/
|
|
160
|
-
|
|
166
|
+
this._log.verbose('GrpcManager', 'start() starting stream ...')
|
|
161
167
|
await this.startStream(lastEventSeq, accountId)
|
|
162
|
-
|
|
168
|
+
this._log.verbose('GrpcManager', 'start() starting stream ... done')
|
|
163
169
|
|
|
164
170
|
/**
|
|
165
171
|
* 3. Start the puppet
|
|
166
172
|
*/
|
|
167
|
-
|
|
173
|
+
this._log.verbose('GrpcManager', 'start() calling grpc server: start() ...')
|
|
168
174
|
await util.promisify(
|
|
169
175
|
this.client.start
|
|
170
176
|
.bind(this.client),
|
|
171
177
|
)(new puppet.StartRequest())
|
|
172
|
-
|
|
178
|
+
this._log.verbose('GrpcManager', 'start() calling grpc server: start() ... done')
|
|
173
179
|
|
|
174
|
-
|
|
180
|
+
this._log.verbose('GrpcManager', 'start() ... done')
|
|
175
181
|
}
|
|
176
182
|
|
|
177
183
|
async stop (): Promise<void> {
|
|
178
|
-
|
|
184
|
+
this._log.verbose('GrpcManager', 'stop()')
|
|
179
185
|
|
|
180
186
|
/**
|
|
181
187
|
* 1. Disconnect from stream
|
|
182
188
|
*/
|
|
183
|
-
|
|
189
|
+
this._log.verbose('GrpcManager', 'stop() stop stream ...')
|
|
184
190
|
this.stopStream()
|
|
185
|
-
|
|
191
|
+
this._log.verbose('GrpcManager', 'stop() stop stream ... done')
|
|
186
192
|
|
|
187
193
|
/**
|
|
188
194
|
* 2. Stop the puppet
|
|
189
195
|
*/
|
|
190
196
|
try {
|
|
191
|
-
|
|
197
|
+
this._log.verbose('GrpcManager', 'stop() stop client ...')
|
|
192
198
|
await util.promisify(
|
|
193
199
|
this.client.stop
|
|
194
200
|
.bind(this.client),
|
|
195
201
|
)(new puppet.StopRequest())
|
|
196
|
-
|
|
202
|
+
this._log.verbose('GrpcManager', 'stop() stop client ... done')
|
|
197
203
|
} catch (e) {
|
|
198
204
|
this.emit('error', e)
|
|
199
205
|
}
|
|
@@ -202,18 +208,18 @@ class GrpcManager extends EventEmitter {
|
|
|
202
208
|
* 3. Destroy grpc client
|
|
203
209
|
*/
|
|
204
210
|
try {
|
|
205
|
-
|
|
211
|
+
this._log.verbose('GrpcManager', 'stop() destroy client ...')
|
|
206
212
|
this.destroyClient()
|
|
207
|
-
|
|
213
|
+
this._log.verbose('GrpcManager', 'stop() destroy client ... done')
|
|
208
214
|
} catch (e) {
|
|
209
215
|
this.emit('error', e)
|
|
210
216
|
}
|
|
211
217
|
|
|
212
|
-
|
|
218
|
+
this._log.verbose('GrpcManager', 'stop() ... done')
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
protected async initClient (): Promise<void> {
|
|
216
|
-
|
|
222
|
+
this._log.verbose('GrpcManager', 'initClient()')
|
|
217
223
|
|
|
218
224
|
/**
|
|
219
225
|
* Huan(202108): for maximum compatible with the non-tls community servers/clients,
|
|
@@ -222,10 +228,10 @@ class GrpcManager extends EventEmitter {
|
|
|
222
228
|
*/
|
|
223
229
|
let credential
|
|
224
230
|
if (this.disableTls) {
|
|
225
|
-
|
|
231
|
+
this._log.warn('GrpcManager', 'initClient() TLS: disabled (INSECURE)')
|
|
226
232
|
credential = grpc.credentials.createInsecure()
|
|
227
233
|
} else {
|
|
228
|
-
|
|
234
|
+
this._log.verbose('GrpcManager', 'initClient() TLS: enabled')
|
|
229
235
|
const callCred = callCredToken(this.token.token)
|
|
230
236
|
const channelCred = grpc.credentials.createSsl(this.caCert)
|
|
231
237
|
const combCreds = grpc.credentials.combineChannelCredentials(channelCred, callCred)
|
|
@@ -252,7 +258,7 @@ class GrpcManager extends EventEmitter {
|
|
|
252
258
|
}
|
|
253
259
|
|
|
254
260
|
if (this._client) {
|
|
255
|
-
|
|
261
|
+
this._log.warn('GrpcManager', 'initClient() this.#client exists? Old client has been dropped.')
|
|
256
262
|
this._client = undefined
|
|
257
263
|
}
|
|
258
264
|
|
|
@@ -262,14 +268,14 @@ class GrpcManager extends EventEmitter {
|
|
|
262
268
|
clientOptions,
|
|
263
269
|
)
|
|
264
270
|
|
|
265
|
-
|
|
271
|
+
this._log.verbose('GrpcManager', 'initClient() ... done')
|
|
266
272
|
}
|
|
267
273
|
|
|
268
274
|
protected destroyClient (): void {
|
|
269
|
-
|
|
275
|
+
this._log.verbose('GrpcManager', 'destroyClient()')
|
|
270
276
|
|
|
271
277
|
if (!this._client) {
|
|
272
|
-
|
|
278
|
+
this._log.warn('GrpcManager', 'destroyClient() this.#client not exist')
|
|
273
279
|
return
|
|
274
280
|
}
|
|
275
281
|
|
|
@@ -283,19 +289,19 @@ class GrpcManager extends EventEmitter {
|
|
|
283
289
|
try {
|
|
284
290
|
client.close()
|
|
285
291
|
} catch (e) {
|
|
286
|
-
|
|
292
|
+
this._log.error('GrpcManager', 'destroyClient() client.close() rejection: %s\n%s', e && (e as Error).message, (e as Error).stack)
|
|
287
293
|
}
|
|
288
294
|
}
|
|
289
295
|
|
|
290
296
|
async startStream (lastEventSeq?: string, accountId?: string): Promise<void> {
|
|
291
|
-
|
|
297
|
+
this._log.verbose('GrpcManager', 'startStream()')
|
|
292
298
|
|
|
293
299
|
if (this.eventStream) {
|
|
294
|
-
|
|
300
|
+
this._log.verbose('GrpcManager', 'startStream() this.eventStream exists, dropped.')
|
|
295
301
|
this.eventStream = undefined
|
|
296
302
|
}
|
|
297
303
|
|
|
298
|
-
|
|
304
|
+
this._log.verbose('GrpcManager', 'startStream() grpc -> event() ...')
|
|
299
305
|
|
|
300
306
|
const eventRequest = new puppet.EventRequest()
|
|
301
307
|
if (lastEventSeq) {
|
|
@@ -304,10 +310,10 @@ class GrpcManager extends EventEmitter {
|
|
|
304
310
|
if (accountId) {
|
|
305
311
|
eventRequest.setAccountId(accountId)
|
|
306
312
|
}
|
|
307
|
-
|
|
313
|
+
this._log.info('GrpcManager', `startStream() connecting event stream with account ${accountId} and seq ${lastEventSeq}`)
|
|
308
314
|
|
|
309
315
|
const eventStream = this.client.event(eventRequest)
|
|
310
|
-
|
|
316
|
+
this._log.verbose('GrpcManager', 'startStream() grpc -> event() ... done')
|
|
311
317
|
|
|
312
318
|
/**
|
|
313
319
|
* Store the event data from the stream when we test connection,
|
|
@@ -374,13 +380,13 @@ class GrpcManager extends EventEmitter {
|
|
|
374
380
|
* if a puppet service provider is coming from the community, it might not follow the protocol specification.
|
|
375
381
|
* So we need a timeout for compatible with those providers
|
|
376
382
|
*/
|
|
377
|
-
|
|
383
|
+
this._log.verbose('GrpcManager', 'startStream() grpc -> event peeking data or timeout ...')
|
|
378
384
|
try {
|
|
379
385
|
await timeoutPromise(future, 5 * 1000) // 5 seconds
|
|
380
386
|
} catch (_) {
|
|
381
|
-
|
|
387
|
+
this._log.verbose('GrpcManager', 'startStream() grpc -> event peeking data or timeout ... timeout')
|
|
382
388
|
}
|
|
383
|
-
|
|
389
|
+
this._log.verbose('GrpcManager', 'startStream() grpc -> event peeking data or timeout ... data peeked')
|
|
384
390
|
|
|
385
391
|
/**
|
|
386
392
|
* Bridge the events
|
|
@@ -389,7 +395,7 @@ class GrpcManager extends EventEmitter {
|
|
|
389
395
|
* so that if there's any `error` event,
|
|
390
396
|
* it will be triggered already.
|
|
391
397
|
*/
|
|
392
|
-
|
|
398
|
+
this._log.verbose('GrpcManager', 'startStream() initializing event stream ...')
|
|
393
399
|
eventStream
|
|
394
400
|
.on('cancel', (...args) => this.emit('cancel', ...args))
|
|
395
401
|
.on('data', (...args) => this.emit('data', ...args))
|
|
@@ -399,26 +405,26 @@ class GrpcManager extends EventEmitter {
|
|
|
399
405
|
.on('status', (...args) => this.emit('status', ...args))
|
|
400
406
|
|
|
401
407
|
this.eventStream = eventStream
|
|
402
|
-
|
|
408
|
+
this._log.verbose('GrpcManager', 'startStream() initializing event stream ... done')
|
|
403
409
|
|
|
404
410
|
/**
|
|
405
411
|
* Re-emit the peeked data if there' s any
|
|
406
412
|
*/
|
|
407
413
|
if (peekedData) {
|
|
408
|
-
|
|
414
|
+
this._log.verbose('GrpcManager', 'startStream() sending back the peeked data ...')
|
|
409
415
|
this.emit('data', peekedData)
|
|
410
416
|
peekedData = undefined
|
|
411
|
-
|
|
417
|
+
this._log.verbose('GrpcManager', 'startStream() sending back the peeked data ... done')
|
|
412
418
|
}
|
|
413
419
|
|
|
414
|
-
|
|
420
|
+
this._log.verbose('GrpcManager', 'startStream() ... done')
|
|
415
421
|
}
|
|
416
422
|
|
|
417
423
|
stopStream (): void {
|
|
418
|
-
|
|
424
|
+
this._log.verbose('GrpcManager', 'stopStream()')
|
|
419
425
|
|
|
420
426
|
if (!this.eventStream) {
|
|
421
|
-
|
|
427
|
+
this._log.verbose('GrpcManager', 'stopStream() no eventStream when stop, skip destroy.')
|
|
422
428
|
return
|
|
423
429
|
}
|
|
424
430
|
/**
|
|
@@ -436,9 +442,9 @@ class GrpcManager extends EventEmitter {
|
|
|
436
442
|
// this.eventStream.cancel()
|
|
437
443
|
|
|
438
444
|
try {
|
|
439
|
-
|
|
445
|
+
this._log.verbose('GrpcManager', 'stopStream() destroying event stream ...')
|
|
440
446
|
eventStream.destroy()
|
|
441
|
-
|
|
447
|
+
this._log.verbose('GrpcManager', 'stopStream() destroying event stream ... done')
|
|
442
448
|
} catch (e) {
|
|
443
449
|
this.emit('error', e)
|
|
444
450
|
}
|
|
@@ -33,10 +33,13 @@ import {
|
|
|
33
33
|
} from '../config.js'
|
|
34
34
|
import { WECHATY_PUPPET_SERVICE_DISABLE_EVENT_CACHE } from '../env-vars.js'
|
|
35
35
|
|
|
36
|
+
type LoggerLike = PUPPET.LoggerLike
|
|
37
|
+
|
|
36
38
|
const { major, minor } = semverPkg
|
|
37
39
|
|
|
38
40
|
interface PayloadStoreOptions {
|
|
39
|
-
token: string
|
|
41
|
+
token : string
|
|
42
|
+
logger? : LoggerLike
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
interface StoreRoomMemberPayload {
|
|
@@ -57,8 +60,11 @@ class PayloadStore {
|
|
|
57
60
|
protected storeDir: string
|
|
58
61
|
protected accountId?: string
|
|
59
62
|
|
|
63
|
+
private readonly _log: LoggerLike
|
|
64
|
+
|
|
60
65
|
constructor (private options: PayloadStoreOptions) {
|
|
61
|
-
|
|
66
|
+
this._log = options.logger ?? log
|
|
67
|
+
this._log.verbose('PayloadStore', 'constructor(%s)', JSON.stringify(options))
|
|
62
68
|
|
|
63
69
|
this.storeDir = path.join(
|
|
64
70
|
os.homedir(),
|
|
@@ -67,7 +73,7 @@ class PayloadStore {
|
|
|
67
73
|
this.options.token,
|
|
68
74
|
`v${major(VERSION)}.${minor(VERSION)}`,
|
|
69
75
|
)
|
|
70
|
-
|
|
76
|
+
this._log.silly('PayloadStore', 'constructor() storeDir: "%s"', this.storeDir)
|
|
71
77
|
|
|
72
78
|
if (!fs.existsSync(this.storeDir)) {
|
|
73
79
|
fs.mkdirSync(this.storeDir, { recursive: true })
|
|
@@ -83,7 +89,7 @@ class PayloadStore {
|
|
|
83
89
|
* so that we can save the payloads under a specific account folder.
|
|
84
90
|
*/
|
|
85
91
|
async start (accountId: string): Promise<void> {
|
|
86
|
-
|
|
92
|
+
this._log.verbose('PayloadStore', 'start(%s)', accountId)
|
|
87
93
|
|
|
88
94
|
if (this.accountId) {
|
|
89
95
|
throw new Error('PayloadStore should be stop() before start() again.')
|
|
@@ -112,7 +118,7 @@ class PayloadStore {
|
|
|
112
118
|
*/
|
|
113
119
|
// const lruOptions: LRU.Options<string, MessagePayload> = {
|
|
114
120
|
// dispose (key, val) {
|
|
115
|
-
//
|
|
121
|
+
// this._log.silly('PayloadStore', `constructor() lruOptions.dispose(${key}, ${JSON.stringify(val)})`)
|
|
116
122
|
// },
|
|
117
123
|
// max : 1000, // 1000 messages
|
|
118
124
|
// maxAge : 60 * 60 * 1000, // 1 hour
|
|
@@ -121,7 +127,7 @@ class PayloadStore {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
async stop (): Promise<void> {
|
|
124
|
-
|
|
130
|
+
this._log.verbose('PayloadStore', 'stop()')
|
|
125
131
|
|
|
126
132
|
const contactStore = this.contact
|
|
127
133
|
const roomMemberStore = this.roomMember
|
|
@@ -153,7 +159,7 @@ class PayloadStore {
|
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
async destroy (): Promise<void> {
|
|
156
|
-
|
|
162
|
+
this._log.verbose('PayloadStore', 'destroy()')
|
|
157
163
|
if (this.accountId) {
|
|
158
164
|
throw new Error('Can not destroy() a start()-ed store. Call stop() to stop it first')
|
|
159
165
|
}
|