@juzi/wechaty 1.0.160 → 1.0.162
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/package-json.js +2 -2
- package/dist/cjs/src/user-modules/call.d.ts +24 -0
- package/dist/cjs/src/user-modules/call.d.ts.map +1 -1
- package/dist/cjs/src/user-modules/call.js +65 -0
- package/dist/cjs/src/user-modules/call.js.map +1 -1
- package/dist/cjs/src/user-modules/call.spec.js +171 -0
- package/dist/cjs/src/user-modules/call.spec.js.map +1 -1
- package/dist/cjs/src/wechaty-mixins/misc-mixin.d.ts +0 -6
- package/dist/cjs/src/wechaty-mixins/misc-mixin.d.ts.map +1 -1
- package/dist/cjs/src/wechaty-mixins/puppet-mixin.d.ts +4 -4
- package/dist/cjs/src/wechaty-mixins/puppet-mixin.d.ts.map +1 -1
- package/dist/cjs/src/wechaty-mixins/puppet-mixin.js +15 -41
- package/dist/cjs/src/wechaty-mixins/puppet-mixin.js.map +1 -1
- package/dist/esm/src/package-json.js +2 -2
- package/dist/esm/src/user-modules/call.d.ts +24 -0
- package/dist/esm/src/user-modules/call.d.ts.map +1 -1
- package/dist/esm/src/user-modules/call.js +65 -0
- package/dist/esm/src/user-modules/call.js.map +1 -1
- package/dist/esm/src/user-modules/call.spec.js +171 -0
- package/dist/esm/src/user-modules/call.spec.js.map +1 -1
- package/dist/esm/src/wechaty-mixins/misc-mixin.d.ts +0 -6
- package/dist/esm/src/wechaty-mixins/misc-mixin.d.ts.map +1 -1
- package/dist/esm/src/wechaty-mixins/puppet-mixin.d.ts +4 -4
- package/dist/esm/src/wechaty-mixins/puppet-mixin.d.ts.map +1 -1
- package/dist/esm/src/wechaty-mixins/puppet-mixin.js +15 -41
- package/dist/esm/src/wechaty-mixins/puppet-mixin.js.map +1 -1
- package/package.json +1 -1
- package/src/package-json.ts +2 -2
- package/src/user-modules/call.spec.ts +203 -0
- package/src/user-modules/call.ts +71 -0
- package/src/wechaty-mixins/puppet-mixin.ts +19 -36
- package/dist/cjs/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.d.ts +0 -3
- package/dist/cjs/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.d.ts.map +0 -1
- package/dist/cjs/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.js +0 -121
- package/dist/cjs/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.js.map +0 -1
- package/dist/esm/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.d.ts +0 -3
- package/dist/esm/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.d.ts.map +0 -1
- package/dist/esm/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.js +0 -96
- package/dist/esm/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.js.map +0 -1
- package/src/wechaty-mixins/puppet-mixin-dirty-pool.spec.ts +0 -144
|
@@ -931,3 +931,206 @@ test('dirty(Call) refreshes user-layer payload so getters see new value', async
|
|
|
931
931
|
await wechaty.stop()
|
|
932
932
|
sandbox.restore()
|
|
933
933
|
})
|
|
934
|
+
|
|
935
|
+
// ---------------------------------------------------------------------------
|
|
936
|
+
// 12. end() — universal terminator dispatches by state
|
|
937
|
+
// ---------------------------------------------------------------------------
|
|
938
|
+
|
|
939
|
+
test('call.end() on outgoing calling invokes puppet.callCancel and ends', async t => {
|
|
940
|
+
const { puppet, wechaty } = buildWechaty()
|
|
941
|
+
await startAndLogin(puppet, wechaty)
|
|
942
|
+
|
|
943
|
+
puppet.callInvite = sandbox.stub().resolves('call-id-end-cancel')
|
|
944
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
945
|
+
id,
|
|
946
|
+
starter : 'bot-self',
|
|
947
|
+
participants : [ 'bot-self', 'peer' ],
|
|
948
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
949
|
+
startTime : 1,
|
|
950
|
+
}))
|
|
951
|
+
const cancelStub = sandbox.stub().resolves(undefined)
|
|
952
|
+
const hangupStub = sandbox.stub().resolves(undefined)
|
|
953
|
+
puppet.callCancel = cancelStub
|
|
954
|
+
puppet.callHangup = hangupStub
|
|
955
|
+
|
|
956
|
+
const contact = (wechaty.Contact as typeof ContactImpl).load('peer')
|
|
957
|
+
const call = await contact.call()
|
|
958
|
+
t.equal(call.status(), 'calling', 'prerequisite: outgoing call starts as calling')
|
|
959
|
+
|
|
960
|
+
await call.end('demo')
|
|
961
|
+
t.same(cancelStub.firstCall.args, [ call.id ], 'callCancel should be invoked with callId')
|
|
962
|
+
t.equal(hangupStub.callCount, 0, 'callHangup should not be touched')
|
|
963
|
+
t.equal(call.status(), 'ended', 'status should be ended')
|
|
964
|
+
t.equal((wechaty as any).__callPool.has(call.id), false, 'pool should be evicted')
|
|
965
|
+
|
|
966
|
+
await call.end('again')
|
|
967
|
+
t.equal(cancelStub.callCount, 1, 'second end() should be a no-op')
|
|
968
|
+
|
|
969
|
+
await wechaty.stop()
|
|
970
|
+
sandbox.restore()
|
|
971
|
+
})
|
|
972
|
+
|
|
973
|
+
test('call.end() on connected call invokes puppet.callHangup with reason', async t => {
|
|
974
|
+
const { puppet, wechaty } = buildWechaty()
|
|
975
|
+
await startAndLogin(puppet, wechaty)
|
|
976
|
+
|
|
977
|
+
puppet.callInvite = sandbox.stub().resolves('call-id-end-hangup')
|
|
978
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
979
|
+
id,
|
|
980
|
+
starter : 'bot-self',
|
|
981
|
+
participants : [ 'bot-self', 'peer' ],
|
|
982
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
983
|
+
startTime : 1,
|
|
984
|
+
}))
|
|
985
|
+
const cancelStub = sandbox.stub().resolves(undefined)
|
|
986
|
+
const hangupStub = sandbox.stub().resolves(undefined)
|
|
987
|
+
puppet.callCancel = cancelStub
|
|
988
|
+
puppet.callHangup = hangupStub
|
|
989
|
+
|
|
990
|
+
const contact = (wechaty.Contact as typeof ContactImpl).load('peer')
|
|
991
|
+
const call = await contact.call()
|
|
992
|
+
|
|
993
|
+
;(puppet as any).emit('call', {
|
|
994
|
+
callId : call.id,
|
|
995
|
+
signal : PUPPET.types.CallSignal.Accept,
|
|
996
|
+
contactId : 'peer',
|
|
997
|
+
timestamp : 2,
|
|
998
|
+
} as PUPPET.payloads.EventCall)
|
|
999
|
+
await flush()
|
|
1000
|
+
t.equal(call.status(), 'connected', 'prerequisite: call should be connected')
|
|
1001
|
+
|
|
1002
|
+
await call.end('bye')
|
|
1003
|
+
t.same(hangupStub.firstCall.args, [ call.id, 'bye' ], 'callHangup args should be [callId, reason]')
|
|
1004
|
+
t.equal(cancelStub.callCount, 0, 'callCancel should not be touched')
|
|
1005
|
+
t.equal(call.status(), 'ended', 'status should be ended')
|
|
1006
|
+
|
|
1007
|
+
await wechaty.stop()
|
|
1008
|
+
sandbox.restore()
|
|
1009
|
+
})
|
|
1010
|
+
|
|
1011
|
+
test('call.end() on incoming ringing invokes puppet.callReject with reason', async t => {
|
|
1012
|
+
const { puppet, wechaty } = buildWechaty()
|
|
1013
|
+
await startAndLogin(puppet, wechaty)
|
|
1014
|
+
|
|
1015
|
+
const CALL_ID = 'call-id-end-reject'
|
|
1016
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
1017
|
+
id,
|
|
1018
|
+
starter : 'peer',
|
|
1019
|
+
participants : [ 'peer', 'bot-self' ],
|
|
1020
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
1021
|
+
startTime : 1,
|
|
1022
|
+
}))
|
|
1023
|
+
const rejectStub = sandbox.stub().resolves(undefined)
|
|
1024
|
+
puppet.callReject = rejectStub
|
|
1025
|
+
|
|
1026
|
+
let incoming: CallInterface | undefined
|
|
1027
|
+
;(wechaty as any).on('call', (c: CallInterface) => { incoming = c })
|
|
1028
|
+
;(puppet as any).emit('call', {
|
|
1029
|
+
callId : CALL_ID,
|
|
1030
|
+
signal : PUPPET.types.CallSignal.Invite,
|
|
1031
|
+
contactId : 'peer',
|
|
1032
|
+
timestamp : 1,
|
|
1033
|
+
} as PUPPET.payloads.EventCall)
|
|
1034
|
+
await flush()
|
|
1035
|
+
t.ok(incoming, 'prerequisite: incoming call should surface via bot.on(call)')
|
|
1036
|
+
t.equal(incoming!.status(), 'ringing', 'prerequisite: incoming call should be ringing')
|
|
1037
|
+
|
|
1038
|
+
await incoming!.end('busy')
|
|
1039
|
+
t.same(rejectStub.firstCall.args, [ CALL_ID, 'busy' ], 'callReject args should be [callId, reason]')
|
|
1040
|
+
t.equal(incoming!.status(), 'ended', 'status should be ended')
|
|
1041
|
+
|
|
1042
|
+
await wechaty.stop()
|
|
1043
|
+
sandbox.restore()
|
|
1044
|
+
})
|
|
1045
|
+
|
|
1046
|
+
test('call.end() falls back to callHangup when callCancel is UNIMPLEMENTED', async t => {
|
|
1047
|
+
const { puppet, wechaty } = buildWechaty()
|
|
1048
|
+
await startAndLogin(puppet, wechaty)
|
|
1049
|
+
|
|
1050
|
+
puppet.callInvite = sandbox.stub().resolves('call-id-end-fallback')
|
|
1051
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
1052
|
+
id,
|
|
1053
|
+
starter : 'bot-self',
|
|
1054
|
+
participants : [ 'bot-self', 'peer' ],
|
|
1055
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
1056
|
+
startTime : 1,
|
|
1057
|
+
}))
|
|
1058
|
+
const cancelStub = sandbox.stub().rejects(new Error('12 UNIMPLEMENTED: CallCancel is not supported'))
|
|
1059
|
+
const hangupStub = sandbox.stub().resolves(undefined)
|
|
1060
|
+
puppet.callCancel = cancelStub
|
|
1061
|
+
puppet.callHangup = hangupStub
|
|
1062
|
+
|
|
1063
|
+
const contact = (wechaty.Contact as typeof ContactImpl).load('peer')
|
|
1064
|
+
const call = await contact.call()
|
|
1065
|
+
|
|
1066
|
+
await call.end('timeout')
|
|
1067
|
+
t.equal(cancelStub.callCount, 1, 'callCancel should be attempted first')
|
|
1068
|
+
t.same(hangupStub.firstCall.args, [ call.id, 'timeout' ], 'should retry via callHangup')
|
|
1069
|
+
t.equal(call.status(), 'ended', 'status should be ended')
|
|
1070
|
+
|
|
1071
|
+
await wechaty.stop()
|
|
1072
|
+
sandbox.restore()
|
|
1073
|
+
})
|
|
1074
|
+
|
|
1075
|
+
test('call.end() retries via callHangup when peer accepts during in-flight cancel', async t => {
|
|
1076
|
+
const { puppet, wechaty } = buildWechaty()
|
|
1077
|
+
await startAndLogin(puppet, wechaty)
|
|
1078
|
+
|
|
1079
|
+
puppet.callInvite = sandbox.stub().resolves('call-id-end-race')
|
|
1080
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
1081
|
+
id,
|
|
1082
|
+
starter : 'bot-self',
|
|
1083
|
+
participants : [ 'bot-self', 'peer' ],
|
|
1084
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
1085
|
+
startTime : 1,
|
|
1086
|
+
}))
|
|
1087
|
+
const hangupStub = sandbox.stub().resolves(undefined)
|
|
1088
|
+
puppet.callHangup = hangupStub
|
|
1089
|
+
puppet.callCancel = sandbox.stub().callsFake(async (callId: string) => {
|
|
1090
|
+
;(puppet as any).emit('call', {
|
|
1091
|
+
callId,
|
|
1092
|
+
signal : PUPPET.types.CallSignal.Accept,
|
|
1093
|
+
contactId : 'peer',
|
|
1094
|
+
timestamp : 2,
|
|
1095
|
+
} as PUPPET.payloads.EventCall)
|
|
1096
|
+
await flush()
|
|
1097
|
+
throw new Error('call already answered')
|
|
1098
|
+
})
|
|
1099
|
+
|
|
1100
|
+
const contact = (wechaty.Contact as typeof ContactImpl).load('peer')
|
|
1101
|
+
const call = await contact.call()
|
|
1102
|
+
|
|
1103
|
+
await call.end('too late to cancel')
|
|
1104
|
+
t.same(hangupStub.firstCall.args, [ call.id, 'too late to cancel' ], 'should retry via callHangup after accept race')
|
|
1105
|
+
t.equal(call.status(), 'ended', 'status should be ended')
|
|
1106
|
+
|
|
1107
|
+
await wechaty.stop()
|
|
1108
|
+
sandbox.restore()
|
|
1109
|
+
})
|
|
1110
|
+
|
|
1111
|
+
test('call.end() rethrows non-recoverable pre-connect failures but still finalizes', async t => {
|
|
1112
|
+
const { puppet, wechaty } = buildWechaty()
|
|
1113
|
+
await startAndLogin(puppet, wechaty)
|
|
1114
|
+
|
|
1115
|
+
puppet.callInvite = sandbox.stub().resolves('call-id-end-fatal')
|
|
1116
|
+
stubCallPayload(puppet, (id: string) => ({
|
|
1117
|
+
id,
|
|
1118
|
+
starter : 'bot-self',
|
|
1119
|
+
participants : [ 'bot-self', 'peer' ],
|
|
1120
|
+
media : PUPPET.types.CallMediaType.Audio,
|
|
1121
|
+
startTime : 1,
|
|
1122
|
+
}))
|
|
1123
|
+
const hangupStub = sandbox.stub().resolves(undefined)
|
|
1124
|
+
puppet.callCancel = sandbox.stub().rejects(new Error('network error'))
|
|
1125
|
+
puppet.callHangup = hangupStub
|
|
1126
|
+
|
|
1127
|
+
const contact = (wechaty.Contact as typeof ContactImpl).load('peer')
|
|
1128
|
+
const call = await contact.call()
|
|
1129
|
+
|
|
1130
|
+
await t.rejects(call.end(), /network error/, 'end() should re-throw transport failures')
|
|
1131
|
+
t.equal(hangupStub.callCount, 0, 'no hangup retry for transport failures')
|
|
1132
|
+
t.equal(call.status(), 'ended', 'status should still finalize')
|
|
1133
|
+
|
|
1134
|
+
await wechaty.stop()
|
|
1135
|
+
sandbox.restore()
|
|
1136
|
+
})
|
package/src/user-modules/call.ts
CHANGED
|
@@ -29,6 +29,18 @@ interface CallConstructorOptions {
|
|
|
29
29
|
|
|
30
30
|
const CallMixinBase = wechatifyMixin(CallEventEmitter)
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Whether a puppet rejection means "this verb is not supported by the
|
|
34
|
+
* implementation" (gRPC UNIMPLEMENTED, or an explicit not-supported error),
|
|
35
|
+
* as opposed to a transport/business failure. Message-based on purpose:
|
|
36
|
+
* puppet errors cross the service boundary as GError and no structured
|
|
37
|
+
* status code survives the trip.
|
|
38
|
+
*/
|
|
39
|
+
function isVerbUnsupportedError (e: unknown): boolean {
|
|
40
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
41
|
+
return /UNIMPLEMENTED|not\s+(?:supported|implemented)|unsupported/i.test(message)
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
/**
|
|
33
45
|
* Call – a live, stateful call-control session abstraction.
|
|
34
46
|
*
|
|
@@ -224,6 +236,65 @@ class CallMixin extends CallMixinBase {
|
|
|
224
236
|
}
|
|
225
237
|
}
|
|
226
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Universal terminator (the "red button"): end the call from whatever
|
|
241
|
+
* state it is in, dispatching to the state-appropriate verb —
|
|
242
|
+
*
|
|
243
|
+
* connected → puppet.callHangup(reason)
|
|
244
|
+
* incoming + ringing → puppet.callReject(reason)
|
|
245
|
+
* outgoing + calling / ringing → puppet.callCancel()
|
|
246
|
+
* ended → no-op (idempotent)
|
|
247
|
+
*
|
|
248
|
+
* Unlike the precise verbs (cancel/reject/hangup), which throw on any state
|
|
249
|
+
* mismatch, end() absorbs the two failure modes inherent to check-then-act
|
|
250
|
+
* termination, retrying ONCE via callHangup when:
|
|
251
|
+
*
|
|
252
|
+
* - the peer accepts while our pre-connect verb is in flight (the verb
|
|
253
|
+
* comes back rejected but the session is now connected, so hangup is
|
|
254
|
+
* the correct verb by the time we retry), or
|
|
255
|
+
* - the puppet does not implement the chosen verb (protocols whose
|
|
256
|
+
* transport folds cancel/reject into a single hangup action).
|
|
257
|
+
*
|
|
258
|
+
* Local state always finalizes, matching cancel/reject/hangup semantics:
|
|
259
|
+
* whichever side actually terminated the session, the protocol-side record
|
|
260
|
+
* is the arbiter and its verdict arrives via the terminal signal path.
|
|
261
|
+
*/
|
|
262
|
+
async end (reason?: string): Promise<void> {
|
|
263
|
+
if (this.__status === 'ended') {
|
|
264
|
+
this.log.verbose('Call', 'end() no-op: already ended, callId=%s', this.id)
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
if (this.__status === 'connected') {
|
|
270
|
+
await this.wechaty.puppet.callHangup(this.id, reason)
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
if (this.__direction === 'incoming') {
|
|
276
|
+
await this.wechaty.puppet.callReject(this.id, reason)
|
|
277
|
+
} else {
|
|
278
|
+
await this.wechaty.puppet.callCancel(this.id)
|
|
279
|
+
}
|
|
280
|
+
} catch (e) {
|
|
281
|
+
const acceptedMeanwhile = this.status() === 'connected'
|
|
282
|
+
if (!acceptedMeanwhile && !isVerbUnsupportedError(e)) {
|
|
283
|
+
throw e
|
|
284
|
+
}
|
|
285
|
+
this.log.verbose(
|
|
286
|
+
'Call',
|
|
287
|
+
'end() pre-connect verb failed (%s), retrying via callHangup, callId=%s',
|
|
288
|
+
acceptedMeanwhile ? 'accepted meanwhile' : 'verb unsupported',
|
|
289
|
+
this.id,
|
|
290
|
+
)
|
|
291
|
+
await this.wechaty.puppet.callHangup(this.id, reason)
|
|
292
|
+
}
|
|
293
|
+
} finally {
|
|
294
|
+
this.__finalize()
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
227
298
|
/**
|
|
228
299
|
* Invite additional contacts to a live call (group-call growth).
|
|
229
300
|
*/
|
|
@@ -18,8 +18,12 @@ import type {
|
|
|
18
18
|
CallImpl,
|
|
19
19
|
ContactImpl,
|
|
20
20
|
ContactInterface,
|
|
21
|
+
MessageImpl,
|
|
22
|
+
RoomImpl,
|
|
21
23
|
TagGroupInterface,
|
|
22
24
|
TagInterface,
|
|
25
|
+
WxxdOrderImpl,
|
|
26
|
+
WxxdProductImpl,
|
|
23
27
|
} from '../user-modules/mod.js'
|
|
24
28
|
|
|
25
29
|
import type {
|
|
@@ -724,46 +728,26 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
|
|
|
724
728
|
case 'dirty':
|
|
725
729
|
/**
|
|
726
730
|
* https://github.com/wechaty/wechaty-puppet-service/issues/43
|
|
727
|
-
*
|
|
728
|
-
* `dirty` semantics: the puppet-service told us the cached payload
|
|
729
|
-
* for this id is stale. It is NOT a request to load the payload.
|
|
730
|
-
*
|
|
731
|
-
* The old handler used `this.Xxx.find({ id })` which, on pool miss,
|
|
732
|
-
* constructs a fresh user-layer instance AND calls `.ready()` — a
|
|
733
|
-
* puppet-side gRPC round-trip. For a `dirty` event about an id
|
|
734
|
-
* that no business code has ever touched, this turned a passive
|
|
735
|
-
* "invalidate if cached" signal into an active fetch, amplifying
|
|
736
|
-
* dirty-event bursts (e.g. during message storms) into extra
|
|
737
|
-
* puppet-service QPS.
|
|
738
|
-
*
|
|
739
|
-
* Fix: for pooled user-modules, look the instance up in the pool
|
|
740
|
-
* directly and only call `.ready(true)` when it is already there.
|
|
741
|
-
* The Call branch (below) already follows this shape via
|
|
742
|
-
* `__callPool.get(...)`. Message has no pool, so its branch is a
|
|
743
|
-
* no-op break (any caller wanting a Message must load it itself).
|
|
744
731
|
*/
|
|
745
732
|
puppet.on('dirty', async ({ payloadType, payloadId }) => {
|
|
746
733
|
try {
|
|
747
734
|
switch (payloadType) {
|
|
748
735
|
case PUPPET.types.Payload.Contact: {
|
|
749
|
-
const
|
|
750
|
-
|
|
736
|
+
const contact = await this.Contact.find({ id: payloadId }) as unknown as undefined | ContactImpl
|
|
737
|
+
await contact?.ready(true)
|
|
751
738
|
break
|
|
752
739
|
}
|
|
753
740
|
case PUPPET.types.Payload.Room: {
|
|
754
|
-
const
|
|
755
|
-
|
|
741
|
+
const room = await this.Room.find({ id: payloadId }) as unknown as undefined | RoomImpl
|
|
742
|
+
await room?.ready(true)
|
|
756
743
|
break
|
|
757
744
|
}
|
|
758
745
|
case PUPPET.types.Payload.RoomMember: {
|
|
759
746
|
if (payloadId.includes(PUPPET.STRING_SPLITTER)) {
|
|
760
747
|
break
|
|
761
748
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
// a new Room here.
|
|
765
|
-
const cached = this.Room.pool.get(payloadId)
|
|
766
|
-
if (cached) await cached.ready()
|
|
749
|
+
const room = await this.Room.find({ id: payloadId }) as unknown as undefined | RoomImpl
|
|
750
|
+
await room?.ready()
|
|
767
751
|
break
|
|
768
752
|
}
|
|
769
753
|
|
|
@@ -773,13 +757,12 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
|
|
|
773
757
|
case PUPPET.types.Payload.Friendship:
|
|
774
758
|
// Friendship has no payload
|
|
775
759
|
break
|
|
776
|
-
case PUPPET.types.Payload.Message:
|
|
777
|
-
// Message
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
// cache-mixin listener still invalidates the puppet-side
|
|
781
|
-
// payload cache alongside this handler.
|
|
760
|
+
case PUPPET.types.Payload.Message: {
|
|
761
|
+
// Message does not need to dirty (?)
|
|
762
|
+
const message = await this.Message.find({ id: payloadId }) as unknown as undefined | MessageImpl
|
|
763
|
+
await message?.ready(true)
|
|
782
764
|
break
|
|
765
|
+
}
|
|
783
766
|
case PUPPET.types.Payload.Tag:
|
|
784
767
|
break
|
|
785
768
|
case PUPPET.types.Payload.TagGroup:
|
|
@@ -787,13 +770,13 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
|
|
|
787
770
|
case PUPPET.types.Payload.Post:
|
|
788
771
|
break
|
|
789
772
|
case PUPPET.types.Payload.WxxdProduct: {
|
|
790
|
-
const
|
|
791
|
-
|
|
773
|
+
const product = await this.WxxdProduct.find({ id: payloadId }) as unknown as undefined | WxxdProductImpl
|
|
774
|
+
await product?.ready(true)
|
|
792
775
|
break
|
|
793
776
|
}
|
|
794
777
|
case PUPPET.types.Payload.WxxdOrder: {
|
|
795
|
-
const
|
|
796
|
-
|
|
778
|
+
const order = await this.WxxdOrder.find({ id: payloadId }) as unknown as undefined | WxxdOrderImpl
|
|
779
|
+
await order?.ready(true)
|
|
797
780
|
break
|
|
798
781
|
}
|
|
799
782
|
case PUPPET.types.Payload.Call: {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"puppet-mixin-dirty-pool.spec.d.ts","sourceRoot":"","sources":["../../../../src/wechaty-mixins/puppet-mixin-dirty-pool.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
-
"use strict";
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
20
|
-
if (mod && mod.__esModule) return mod;
|
|
21
|
-
var result = {};
|
|
22
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
23
|
-
__setModuleDefault(result, mod);
|
|
24
|
-
return result;
|
|
25
|
-
};
|
|
26
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
const tstest_1 = require("tstest");
|
|
28
|
-
const PUPPET = __importStar(require("@juzi/wechaty-puppet"));
|
|
29
|
-
const wechaty_puppet_mock_1 = require("@juzi/wechaty-puppet-mock");
|
|
30
|
-
const wechaty_builder_js_1 = require("../wechaty-builder.js");
|
|
31
|
-
/**
|
|
32
|
-
* Regression: the `dirty` event handler for pooled user-modules
|
|
33
|
-
* (Contact / Room / WxxdProduct / WxxdOrder) used to call
|
|
34
|
-
* `this.Xxx.find({ id }).ready(true)`. `find({ id })` on a pool miss
|
|
35
|
-
* constructs a fresh instance and calls `ready()` — a puppet-side gRPC
|
|
36
|
-
* round-trip — turning a passive "invalidate if cached" signal into an
|
|
37
|
-
* active fetch for ids no business code has touched.
|
|
38
|
-
*
|
|
39
|
-
* The fix looks the id up in the pool directly and only calls
|
|
40
|
-
* `.ready(true)` when the instance is already pooled.
|
|
41
|
-
*/
|
|
42
|
-
async function delay(ms) {
|
|
43
|
-
await new Promise(resolve => setTimeout(resolve, ms));
|
|
44
|
-
}
|
|
45
|
-
(0, tstest_1.test)('dirty handler does not fetch payload for un-pooled ids, but still refreshes pooled ones', async (t) => {
|
|
46
|
-
const puppet = new wechaty_puppet_mock_1.PuppetMock();
|
|
47
|
-
const wechaty = wechaty_builder_js_1.WechatyBuilder.build({ puppet });
|
|
48
|
-
const botContact = puppet.mocker.createContact({ name: 'test-bot' });
|
|
49
|
-
await wechaty.start();
|
|
50
|
-
await puppet.mocker.login(botContact);
|
|
51
|
-
// --- Case 1: un-pooled Contact id must not trigger contactRawPayload ---
|
|
52
|
-
let contactRawPayloadCalls = 0;
|
|
53
|
-
const originalContactRawPayload = puppet.contactRawPayload.bind(puppet);
|
|
54
|
-
puppet.contactRawPayload = async (id) => {
|
|
55
|
-
contactRawPayloadCalls++;
|
|
56
|
-
return originalContactRawPayload(id);
|
|
57
|
-
};
|
|
58
|
-
puppet.emit('dirty', {
|
|
59
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
60
|
-
payloadId: 'never-loaded-contact-id',
|
|
61
|
-
});
|
|
62
|
-
await delay(50);
|
|
63
|
-
t.equal(contactRawPayloadCalls, 0, `dirty(Contact) for un-pooled id must not trigger contactRawPayload; got ${contactRawPayloadCalls} call(s)`);
|
|
64
|
-
// --- Case 2: un-pooled Room id must not trigger roomRawPayload ---
|
|
65
|
-
let roomRawPayloadCalls = 0;
|
|
66
|
-
const originalRoomRawPayload = puppet.roomRawPayload.bind(puppet);
|
|
67
|
-
puppet.roomRawPayload = async (id) => {
|
|
68
|
-
roomRawPayloadCalls++;
|
|
69
|
-
return originalRoomRawPayload(id);
|
|
70
|
-
};
|
|
71
|
-
puppet.emit('dirty', {
|
|
72
|
-
payloadType: PUPPET.types.Payload.Room,
|
|
73
|
-
payloadId: 'never-loaded-room-id',
|
|
74
|
-
});
|
|
75
|
-
await delay(50);
|
|
76
|
-
t.equal(roomRawPayloadCalls, 0, `dirty(Room) for un-pooled id must not trigger roomRawPayload; got ${roomRawPayloadCalls} call(s)`);
|
|
77
|
-
// --- Case 3: Message dirty must not trigger messageRawPayload (Message has no user-layer pool) ---
|
|
78
|
-
let messageRawPayloadCalls = 0;
|
|
79
|
-
const originalMessageRawPayload = puppet.messageRawPayload.bind(puppet);
|
|
80
|
-
puppet.messageRawPayload = async (id) => {
|
|
81
|
-
messageRawPayloadCalls++;
|
|
82
|
-
return originalMessageRawPayload(id);
|
|
83
|
-
};
|
|
84
|
-
puppet.emit('dirty', {
|
|
85
|
-
payloadType: PUPPET.types.Payload.Message,
|
|
86
|
-
payloadId: 'some-message-id',
|
|
87
|
-
});
|
|
88
|
-
await delay(50);
|
|
89
|
-
t.equal(messageRawPayloadCalls, 0, `dirty(Message) must not trigger messageRawPayload at the user layer; got ${messageRawPayloadCalls} call(s)`);
|
|
90
|
-
// --- Case 4: un-pooled Contact still emits the user-facing dirty event ---
|
|
91
|
-
let wechatyDirtyEmits = 0;
|
|
92
|
-
wechaty.on('dirty', () => {
|
|
93
|
-
wechatyDirtyEmits++;
|
|
94
|
-
});
|
|
95
|
-
puppet.emit('dirty', {
|
|
96
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
97
|
-
payloadId: 'yet-another-un-pooled-id',
|
|
98
|
-
});
|
|
99
|
-
await delay(50);
|
|
100
|
-
t.equal(wechatyDirtyEmits, 1, `wechaty.emit('dirty', ...) must fire once even when the id is not pooled; got ${wechatyDirtyEmits}`);
|
|
101
|
-
// --- Case 5: pooled Contact MUST re-fetch on dirty ---
|
|
102
|
-
const pooledContact = puppet.mocker.createContact({ name: 'pooled-contact' });
|
|
103
|
-
// Force the contact into the wechatified pool via find(). Payload gets
|
|
104
|
-
// loaded once as part of find()'s ready() call — subsequent counts we
|
|
105
|
-
// measure from AFTER this seed.
|
|
106
|
-
await wechaty.Contact.find({ id: pooledContact.id });
|
|
107
|
-
let contactPayloadCalls = 0;
|
|
108
|
-
const originalContactPayload = puppet.contactPayload.bind(puppet);
|
|
109
|
-
puppet.contactPayload = async (id) => {
|
|
110
|
-
contactPayloadCalls++;
|
|
111
|
-
return originalContactPayload(id);
|
|
112
|
-
};
|
|
113
|
-
puppet.emit('dirty', {
|
|
114
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
115
|
-
payloadId: pooledContact.id,
|
|
116
|
-
});
|
|
117
|
-
await delay(50);
|
|
118
|
-
t.ok(contactPayloadCalls >= 1, `dirty(Contact) for pooled id must trigger contactPayload via ready(true); got ${contactPayloadCalls} call(s)`);
|
|
119
|
-
await wechaty.stop();
|
|
120
|
-
});
|
|
121
|
-
//# sourceMappingURL=puppet-mixin-dirty-pool.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"puppet-mixin-dirty-pool.spec.js","sourceRoot":"","sources":["../../../../src/wechaty-mixins/puppet-mixin-dirty-pool.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"puppet-mixin-dirty-pool.spec.d.ts","sourceRoot":"","sources":["../../../../src/wechaty-mixins/puppet-mixin-dirty-pool.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
-
import { test } from 'tstest';
|
|
3
|
-
import * as PUPPET from '@juzi/wechaty-puppet';
|
|
4
|
-
import { PuppetMock } from '@juzi/wechaty-puppet-mock';
|
|
5
|
-
import { WechatyBuilder } from '../wechaty-builder.js';
|
|
6
|
-
/**
|
|
7
|
-
* Regression: the `dirty` event handler for pooled user-modules
|
|
8
|
-
* (Contact / Room / WxxdProduct / WxxdOrder) used to call
|
|
9
|
-
* `this.Xxx.find({ id }).ready(true)`. `find({ id })` on a pool miss
|
|
10
|
-
* constructs a fresh instance and calls `ready()` — a puppet-side gRPC
|
|
11
|
-
* round-trip — turning a passive "invalidate if cached" signal into an
|
|
12
|
-
* active fetch for ids no business code has touched.
|
|
13
|
-
*
|
|
14
|
-
* The fix looks the id up in the pool directly and only calls
|
|
15
|
-
* `.ready(true)` when the instance is already pooled.
|
|
16
|
-
*/
|
|
17
|
-
async function delay(ms) {
|
|
18
|
-
await new Promise(resolve => setTimeout(resolve, ms));
|
|
19
|
-
}
|
|
20
|
-
test('dirty handler does not fetch payload for un-pooled ids, but still refreshes pooled ones', async (t) => {
|
|
21
|
-
const puppet = new PuppetMock();
|
|
22
|
-
const wechaty = WechatyBuilder.build({ puppet });
|
|
23
|
-
const botContact = puppet.mocker.createContact({ name: 'test-bot' });
|
|
24
|
-
await wechaty.start();
|
|
25
|
-
await puppet.mocker.login(botContact);
|
|
26
|
-
// --- Case 1: un-pooled Contact id must not trigger contactRawPayload ---
|
|
27
|
-
let contactRawPayloadCalls = 0;
|
|
28
|
-
const originalContactRawPayload = puppet.contactRawPayload.bind(puppet);
|
|
29
|
-
puppet.contactRawPayload = async (id) => {
|
|
30
|
-
contactRawPayloadCalls++;
|
|
31
|
-
return originalContactRawPayload(id);
|
|
32
|
-
};
|
|
33
|
-
puppet.emit('dirty', {
|
|
34
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
35
|
-
payloadId: 'never-loaded-contact-id',
|
|
36
|
-
});
|
|
37
|
-
await delay(50);
|
|
38
|
-
t.equal(contactRawPayloadCalls, 0, `dirty(Contact) for un-pooled id must not trigger contactRawPayload; got ${contactRawPayloadCalls} call(s)`);
|
|
39
|
-
// --- Case 2: un-pooled Room id must not trigger roomRawPayload ---
|
|
40
|
-
let roomRawPayloadCalls = 0;
|
|
41
|
-
const originalRoomRawPayload = puppet.roomRawPayload.bind(puppet);
|
|
42
|
-
puppet.roomRawPayload = async (id) => {
|
|
43
|
-
roomRawPayloadCalls++;
|
|
44
|
-
return originalRoomRawPayload(id);
|
|
45
|
-
};
|
|
46
|
-
puppet.emit('dirty', {
|
|
47
|
-
payloadType: PUPPET.types.Payload.Room,
|
|
48
|
-
payloadId: 'never-loaded-room-id',
|
|
49
|
-
});
|
|
50
|
-
await delay(50);
|
|
51
|
-
t.equal(roomRawPayloadCalls, 0, `dirty(Room) for un-pooled id must not trigger roomRawPayload; got ${roomRawPayloadCalls} call(s)`);
|
|
52
|
-
// --- Case 3: Message dirty must not trigger messageRawPayload (Message has no user-layer pool) ---
|
|
53
|
-
let messageRawPayloadCalls = 0;
|
|
54
|
-
const originalMessageRawPayload = puppet.messageRawPayload.bind(puppet);
|
|
55
|
-
puppet.messageRawPayload = async (id) => {
|
|
56
|
-
messageRawPayloadCalls++;
|
|
57
|
-
return originalMessageRawPayload(id);
|
|
58
|
-
};
|
|
59
|
-
puppet.emit('dirty', {
|
|
60
|
-
payloadType: PUPPET.types.Payload.Message,
|
|
61
|
-
payloadId: 'some-message-id',
|
|
62
|
-
});
|
|
63
|
-
await delay(50);
|
|
64
|
-
t.equal(messageRawPayloadCalls, 0, `dirty(Message) must not trigger messageRawPayload at the user layer; got ${messageRawPayloadCalls} call(s)`);
|
|
65
|
-
// --- Case 4: un-pooled Contact still emits the user-facing dirty event ---
|
|
66
|
-
let wechatyDirtyEmits = 0;
|
|
67
|
-
wechaty.on('dirty', () => {
|
|
68
|
-
wechatyDirtyEmits++;
|
|
69
|
-
});
|
|
70
|
-
puppet.emit('dirty', {
|
|
71
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
72
|
-
payloadId: 'yet-another-un-pooled-id',
|
|
73
|
-
});
|
|
74
|
-
await delay(50);
|
|
75
|
-
t.equal(wechatyDirtyEmits, 1, `wechaty.emit('dirty', ...) must fire once even when the id is not pooled; got ${wechatyDirtyEmits}`);
|
|
76
|
-
// --- Case 5: pooled Contact MUST re-fetch on dirty ---
|
|
77
|
-
const pooledContact = puppet.mocker.createContact({ name: 'pooled-contact' });
|
|
78
|
-
// Force the contact into the wechatified pool via find(). Payload gets
|
|
79
|
-
// loaded once as part of find()'s ready() call — subsequent counts we
|
|
80
|
-
// measure from AFTER this seed.
|
|
81
|
-
await wechaty.Contact.find({ id: pooledContact.id });
|
|
82
|
-
let contactPayloadCalls = 0;
|
|
83
|
-
const originalContactPayload = puppet.contactPayload.bind(puppet);
|
|
84
|
-
puppet.contactPayload = async (id) => {
|
|
85
|
-
contactPayloadCalls++;
|
|
86
|
-
return originalContactPayload(id);
|
|
87
|
-
};
|
|
88
|
-
puppet.emit('dirty', {
|
|
89
|
-
payloadType: PUPPET.types.Payload.Contact,
|
|
90
|
-
payloadId: pooledContact.id,
|
|
91
|
-
});
|
|
92
|
-
await delay(50);
|
|
93
|
-
t.ok(contactPayloadCalls >= 1, `dirty(Contact) for pooled id must trigger contactPayload via ready(true); got ${contactPayloadCalls} call(s)`);
|
|
94
|
-
await wechaty.stop();
|
|
95
|
-
});
|
|
96
|
-
//# sourceMappingURL=puppet-mixin-dirty-pool.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"puppet-mixin-dirty-pool.spec.js","sourceRoot":"","sources":["../../../../src/wechaty-mixins/puppet-mixin-dirty-pool.spec.ts"],"names":[],"mappings":"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"}
|