@juzi/wechaty-puppet-service 1.0.113 → 1.0.115
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/call-raw-payload-parser.spec.d.ts +3 -0
- package/dist/cjs/src/client/call-raw-payload-parser.spec.d.ts.map +1 -0
- package/dist/cjs/src/client/call-raw-payload-parser.spec.js +128 -0
- package/dist/cjs/src/client/call-raw-payload-parser.spec.js.map +1 -0
- package/dist/cjs/src/client/payload-store.js +2 -2
- package/dist/cjs/src/client/payload-store.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.d.ts +21 -0
- package/dist/cjs/src/client/puppet-service.d.ts.map +1 -1
- package/dist/cjs/src/client/puppet-service.js +230 -1
- package/dist/cjs/src/client/puppet-service.js.map +1 -1
- package/dist/cjs/src/client/puppet-service.spec.js.map +1 -1
- package/dist/cjs/src/package-json.js +4 -4
- package/dist/cjs/src/package-json.js.map +1 -1
- package/dist/cjs/src/pure-functions/timestamp.d.ts +15 -1
- package/dist/cjs/src/pure-functions/timestamp.d.ts.map +1 -1
- package/dist/cjs/src/pure-functions/timestamp.js +10 -1
- package/dist/cjs/src/pure-functions/timestamp.js.map +1 -1
- package/dist/cjs/src/pure-functions/timestamp.spec.d.ts +3 -0
- package/dist/cjs/src/pure-functions/timestamp.spec.d.ts.map +1 -0
- package/dist/cjs/src/pure-functions/timestamp.spec.js +48 -0
- package/dist/cjs/src/pure-functions/timestamp.spec.js.map +1 -0
- package/dist/cjs/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/cjs/src/server/event-stream-manager.js +7 -0
- package/dist/cjs/src/server/event-stream-manager.js.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/cjs/src/server/puppet-implementation.js +296 -2
- package/dist/cjs/src/server/puppet-implementation.js.map +1 -1
- package/dist/cjs/src/utils/call-media-mapping.d.ts +17 -0
- package/dist/cjs/src/utils/call-media-mapping.d.ts.map +1 -0
- package/dist/cjs/src/utils/call-media-mapping.js +60 -0
- package/dist/cjs/src/utils/call-media-mapping.js.map +1 -0
- package/dist/cjs/src/utils/call-media-mapping.spec.d.ts +3 -0
- package/dist/cjs/src/utils/call-media-mapping.spec.d.ts.map +1 -0
- package/dist/cjs/src/utils/call-media-mapping.spec.js +65 -0
- package/dist/cjs/src/utils/call-media-mapping.spec.js.map +1 -0
- package/dist/esm/src/client/call-raw-payload-parser.spec.d.ts +3 -0
- package/dist/esm/src/client/call-raw-payload-parser.spec.d.ts.map +1 -0
- package/dist/esm/src/client/call-raw-payload-parser.spec.js +103 -0
- package/dist/esm/src/client/call-raw-payload-parser.spec.js.map +1 -0
- package/dist/esm/src/client/payload-store.js +2 -2
- package/dist/esm/src/client/payload-store.js.map +1 -1
- package/dist/esm/src/client/puppet-service.d.ts +21 -0
- package/dist/esm/src/client/puppet-service.d.ts.map +1 -1
- package/dist/esm/src/client/puppet-service.js +232 -3
- package/dist/esm/src/client/puppet-service.js.map +1 -1
- package/dist/esm/src/client/puppet-service.spec.js +1 -1
- package/dist/esm/src/client/puppet-service.spec.js.map +1 -1
- package/dist/esm/src/package-json.js +4 -4
- package/dist/esm/src/package-json.js.map +1 -1
- package/dist/esm/src/pure-functions/timestamp.d.ts +15 -1
- package/dist/esm/src/pure-functions/timestamp.d.ts.map +1 -1
- package/dist/esm/src/pure-functions/timestamp.js +9 -1
- package/dist/esm/src/pure-functions/timestamp.js.map +1 -1
- package/dist/esm/src/pure-functions/timestamp.spec.d.ts +3 -0
- package/dist/esm/src/pure-functions/timestamp.spec.d.ts.map +1 -0
- package/dist/esm/src/pure-functions/timestamp.spec.js +46 -0
- package/dist/esm/src/pure-functions/timestamp.spec.js.map +1 -0
- package/dist/esm/src/server/event-stream-manager.d.ts.map +1 -1
- package/dist/esm/src/server/event-stream-manager.js +7 -0
- package/dist/esm/src/server/event-stream-manager.js.map +1 -1
- package/dist/esm/src/server/puppet-implementation.d.ts.map +1 -1
- package/dist/esm/src/server/puppet-implementation.js +296 -2
- package/dist/esm/src/server/puppet-implementation.js.map +1 -1
- package/dist/esm/src/utils/call-media-mapping.d.ts +17 -0
- package/dist/esm/src/utils/call-media-mapping.d.ts.map +1 -0
- package/dist/esm/src/utils/call-media-mapping.js +32 -0
- package/dist/esm/src/utils/call-media-mapping.js.map +1 -0
- package/dist/esm/src/utils/call-media-mapping.spec.d.ts +3 -0
- package/dist/esm/src/utils/call-media-mapping.spec.d.ts.map +1 -0
- package/dist/esm/src/utils/call-media-mapping.spec.js +40 -0
- package/dist/esm/src/utils/call-media-mapping.spec.js.map +1 -0
- package/package.json +4 -4
- package/src/client/call-raw-payload-parser.spec.ts +131 -0
- package/src/client/payload-store.ts +2 -2
- package/src/client/puppet-service.spec.ts +3 -1
- package/src/client/puppet-service.ts +438 -4
- package/src/package-json.ts +4 -4
- package/src/pure-functions/timestamp.spec.ts +56 -0
- package/src/pure-functions/timestamp.ts +19 -0
- package/src/server/event-stream-manager.ts +7 -0
- package/src/server/puppet-implementation.ts +384 -3
- package/src/utils/call-media-mapping.spec.ts +53 -0
- package/src/utils/call-media-mapping.ts +35 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm
|
|
2
|
+
|
|
3
|
+
import { test } from 'tstest'
|
|
4
|
+
import * as PUPPET from '@juzi/wechaty-puppet'
|
|
5
|
+
import { puppet as grpcPuppet } from '@juzi/wechaty-grpc'
|
|
6
|
+
|
|
7
|
+
import { PuppetService } from './puppet-service.js'
|
|
8
|
+
import { timestampFromMilliseconds } from '../pure-functions/timestamp.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The parser only reads `rawPayload.*` and a module-level `log` — it never
|
|
12
|
+
* touches `this`. Invoke it via `prototype.call({}, raw)` to avoid building a
|
|
13
|
+
* full PuppetService instance for unit-level tests.
|
|
14
|
+
*/
|
|
15
|
+
const callParser = async (raw: grpcPuppet.CallPayloadResponse.AsObject) =>
|
|
16
|
+
PuppetService.prototype.callRawPayloadParser.call({} as PuppetService, raw)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 1. Full payload with starter, participants, media=VOICE, startTime, endTime
|
|
20
|
+
* parses every field, mapping VOICE -> CallMediaType.Audio.
|
|
21
|
+
*/
|
|
22
|
+
test('callRawPayloadParser parses a complete payload', async t => {
|
|
23
|
+
const startMs = 1_700_000_000_000
|
|
24
|
+
const endMs = 1_700_000_030_000
|
|
25
|
+
|
|
26
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
27
|
+
pb.setId('call-1')
|
|
28
|
+
pb.setStarter('alice')
|
|
29
|
+
pb.setParticipantsList([ 'alice', 'bob' ])
|
|
30
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_VOICE)
|
|
31
|
+
pb.setStartTime(timestampFromMilliseconds(startMs))
|
|
32
|
+
pb.setEndTime(timestampFromMilliseconds(endMs))
|
|
33
|
+
|
|
34
|
+
const payload = await callParser(pb.toObject())
|
|
35
|
+
|
|
36
|
+
t.equal(payload.id, 'call-1', 'id propagated')
|
|
37
|
+
t.equal(payload.starter, 'alice', 'starter propagated')
|
|
38
|
+
t.same(payload.participants, [ 'alice', 'bob' ], 'participants propagated')
|
|
39
|
+
t.equal(payload.media, PUPPET.types.CallMediaType.Audio, 'VOICE maps to Audio')
|
|
40
|
+
t.equal(payload.startTime, startMs, 'startTime parsed')
|
|
41
|
+
t.equal(payload.endTime, endMs, 'endTime parsed')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 2. Empty starter string -> parser omits `starter` from the resulting payload.
|
|
46
|
+
* (Mirrors the server, which only `setStarter` when the value is truthy.)
|
|
47
|
+
*/
|
|
48
|
+
test('callRawPayloadParser omits starter when starter is an empty string', async t => {
|
|
49
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
50
|
+
pb.setId('call-2')
|
|
51
|
+
pb.setParticipantsList([ 'alice' ])
|
|
52
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_VIDEO)
|
|
53
|
+
pb.setStartTime(timestampFromMilliseconds(1_700_000_000_000))
|
|
54
|
+
// no setStarter -> default proto3 string '' on the wire
|
|
55
|
+
|
|
56
|
+
const payload = await callParser(pb.toObject())
|
|
57
|
+
|
|
58
|
+
t.equal(payload.starter, undefined, 'starter is undefined when empty on the wire')
|
|
59
|
+
t.equal(payload.media, PUPPET.types.CallMediaType.Video, 'VIDEO maps to Video')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 3. endTime not set (no setEndTime) -> payload.endTime === undefined.
|
|
64
|
+
*/
|
|
65
|
+
test('callRawPayloadParser leaves endTime undefined when endTime is not set', async t => {
|
|
66
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
67
|
+
pb.setId('call-3')
|
|
68
|
+
pb.setStarter('alice')
|
|
69
|
+
pb.setParticipantsList([ 'alice', 'bob' ])
|
|
70
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_VOICE)
|
|
71
|
+
pb.setStartTime(timestampFromMilliseconds(1_700_000_000_000))
|
|
72
|
+
// no setEndTime
|
|
73
|
+
|
|
74
|
+
const payload = await callParser(pb.toObject())
|
|
75
|
+
|
|
76
|
+
t.equal(payload.endTime, undefined, 'endTime is undefined when not set on the wire')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 4. media = CALL_TYPE_UNKNOWN -> throw, error mentions "media".
|
|
81
|
+
*/
|
|
82
|
+
test('callRawPayloadParser throws when media is CALL_TYPE_UNKNOWN', async t => {
|
|
83
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
84
|
+
pb.setId('call-4')
|
|
85
|
+
pb.setParticipantsList([ 'alice' ])
|
|
86
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_UNKNOWN)
|
|
87
|
+
pb.setStartTime(timestampFromMilliseconds(1_700_000_000_000))
|
|
88
|
+
|
|
89
|
+
await t.rejects(
|
|
90
|
+
callParser(pb.toObject()),
|
|
91
|
+
/media/,
|
|
92
|
+
'rejects with a message that mentions media',
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 5. startTime not set -> throw, error mentions "startTime".
|
|
98
|
+
*/
|
|
99
|
+
test('callRawPayloadParser throws when startTime is not set', async t => {
|
|
100
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
101
|
+
pb.setId('call-5')
|
|
102
|
+
pb.setParticipantsList([ 'alice' ])
|
|
103
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_VOICE)
|
|
104
|
+
// no setStartTime
|
|
105
|
+
|
|
106
|
+
await t.rejects(
|
|
107
|
+
callParser(pb.toObject()),
|
|
108
|
+
/startTime/,
|
|
109
|
+
'rejects with a message that mentions startTime',
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 6. endTime explicitly set to epoch 0 -> payload.endTime === 0.
|
|
115
|
+
* proto3 `setEndTime(timestamp(0))` is a legal "ended at epoch-0" value
|
|
116
|
+
* (extreme short session / test stub) and must not be swallowed by a
|
|
117
|
+
* truthy guard. Presence is what matters, not the numeric value.
|
|
118
|
+
*/
|
|
119
|
+
test('callRawPayloadParser preserves endTime when it is set to epoch zero', async t => {
|
|
120
|
+
const pb = new grpcPuppet.CallPayloadResponse()
|
|
121
|
+
pb.setId('call-6')
|
|
122
|
+
pb.setStarter('alice')
|
|
123
|
+
pb.setParticipantsList([ 'alice', 'bob' ])
|
|
124
|
+
pb.setMedia(grpcPuppet.CallType.CALL_TYPE_VOICE)
|
|
125
|
+
pb.setStartTime(timestampFromMilliseconds(1_700_000_000_000))
|
|
126
|
+
pb.setEndTime(timestampFromMilliseconds(0))
|
|
127
|
+
|
|
128
|
+
const payload = await callParser(pb.toObject())
|
|
129
|
+
|
|
130
|
+
t.equal(payload.endTime, 0, 'endTime is 0 when explicitly set to epoch zero on the wire')
|
|
131
|
+
})
|
|
@@ -164,8 +164,8 @@ class PayloadStore {
|
|
|
164
164
|
* Huan(202108): `fs.rm` was introduced from Node.js v14.14
|
|
165
165
|
* https://nodejs.org/api/fs.html#fs_fspromises_rm_path_options
|
|
166
166
|
*/
|
|
167
|
-
await fs.promises.
|
|
168
|
-
|
|
167
|
+
await fs.promises.rm(this.storeDir, {
|
|
168
|
+
force: true,
|
|
169
169
|
recursive: true,
|
|
170
170
|
})
|
|
171
171
|
}
|
|
@@ -31,7 +31,10 @@ import {
|
|
|
31
31
|
|
|
32
32
|
// import type { Subscription } from 'rxjs'
|
|
33
33
|
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
millisecondsFromTimestamp,
|
|
36
|
+
millisecondsFromTimestampObject,
|
|
37
|
+
} from '../pure-functions/timestamp.js'
|
|
35
38
|
|
|
36
39
|
import {
|
|
37
40
|
uuidifyFileBoxGrpc,
|
|
@@ -50,7 +53,8 @@ import { packageJson } from '../package-json.js'
|
|
|
50
53
|
|
|
51
54
|
import { GrpcManager } from './grpc-manager.js'
|
|
52
55
|
import { PayloadStore } from './payload-store.js'
|
|
53
|
-
import { OptionalBooleanUnwrapper, OptionalBooleanWrapper, callRecordPbToPayload, channelPayloadToPb, channelPbToPayload, chatHistoryPbToPayload, contactPbToPayload, postPayloadToPb, roomMemberPbToPayload, urlLinkPbToPayload, channelCardPayloadToPb, channelCardPbToPayload } from '../utils/pb-payload-helper.js'
|
|
56
|
+
import { OptionalBooleanUnwrapper, OptionalBooleanWrapper, callRecordPbToPayload, channelPayloadToPb, channelPbToPayload, chatHistoryPbToPayload, contactPbToPayload, postPayloadToPb, roomMemberPbToPayload, urlLinkPbToPayload, channelCardPayloadToPb, channelCardPbToPayload, miniProgramPayloadToPb, urlLinkPayloadToPb, locationPayloadToPb } from '../utils/pb-payload-helper.js'
|
|
57
|
+
import { puppetCallMediaTypeToGrpc, grpcCallTypeToPuppetMedia } from '../utils/call-media-mapping.js'
|
|
54
58
|
import type { MessageBroadcastTargets } from '@juzi/wechaty-puppet/dist/esm/src/schemas/message.js'
|
|
55
59
|
import { timeoutPromise } from 'gerror'
|
|
56
60
|
import { BooleanIndicator } from 'state-switch'
|
|
@@ -72,6 +76,34 @@ export type PuppetServiceOptions = PUPPET.PuppetOptions & {
|
|
|
72
76
|
const ResetLoginTimeout = 30 * 1000
|
|
73
77
|
const ResetReadyTimeout = 20 * 1000 // normally ready comes 15 seconds after login
|
|
74
78
|
|
|
79
|
+
type MessageBatchSendResponse = Awaited<ReturnType<PUPPET.impls.PuppetInterface['messageBatchSendText']>>
|
|
80
|
+
|
|
81
|
+
type GrpcUnaryMethod<Request, Response> = {
|
|
82
|
+
(request: Request, callback: (error: Error | null, response: Response) => void): unknown,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type GrpcBatchResult = {
|
|
86
|
+
getConversationId(): string,
|
|
87
|
+
getError(): string,
|
|
88
|
+
getId(): string,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
type GrpcBatchResponse<Result extends GrpcBatchResult> = {
|
|
92
|
+
getResultsList(): Result[],
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function grpcBatchResultsToPayload<Result extends GrpcBatchResult> (
|
|
96
|
+
response: GrpcBatchResponse<Result>,
|
|
97
|
+
): MessageBatchSendResponse {
|
|
98
|
+
return {
|
|
99
|
+
results: response.getResultsList().map(result => ({
|
|
100
|
+
conversationId : result.getConversationId(),
|
|
101
|
+
error : result.getError() || undefined,
|
|
102
|
+
id : result.getId() || undefined,
|
|
103
|
+
})),
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
75
107
|
class PuppetService extends PUPPET.Puppet {
|
|
76
108
|
|
|
77
109
|
static override readonly VERSION = VERSION
|
|
@@ -125,6 +157,17 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
125
157
|
return JSON.stringify(normalizedFileBox)
|
|
126
158
|
}
|
|
127
159
|
|
|
160
|
+
private async grpcUnary<Request, Response> (
|
|
161
|
+
method : GrpcUnaryMethod<Request, Response>,
|
|
162
|
+
request : Request,
|
|
163
|
+
): Promise<Response> {
|
|
164
|
+
const promisified = util.promisify(
|
|
165
|
+
method.bind(this.grpcManager.client),
|
|
166
|
+
) as (request: Request) => Promise<Response>
|
|
167
|
+
|
|
168
|
+
return promisified(request)
|
|
169
|
+
}
|
|
170
|
+
|
|
128
171
|
override name () {
|
|
129
172
|
return packageJson.name || 'wechaty-puppet-service'
|
|
130
173
|
}
|
|
@@ -384,6 +427,9 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
384
427
|
case grpcPuppet.EventType.EVENT_TYPE_VERIFY_SLIDE:
|
|
385
428
|
this.emit('verify-slide', JSON.parse(payload) as PUPPET.payloads.EventVerifySlide)
|
|
386
429
|
break
|
|
430
|
+
case grpcPuppet.EventType.EVENT_TYPE_CALL:
|
|
431
|
+
this.emit('call', JSON.parse(payload) as PUPPET.payloads.EventCall)
|
|
432
|
+
break
|
|
387
433
|
|
|
388
434
|
default:
|
|
389
435
|
// Huan(202003): in default, the `type` type should be `never`, please check.
|
|
@@ -461,7 +507,7 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
461
507
|
): Promise<void> {
|
|
462
508
|
log.verbose('PuppetService', 'fastDirty(%s<%s>, %s)', PUPPET.types.Dirty[payloadType], payloadType, payloadId)
|
|
463
509
|
|
|
464
|
-
const dirtyMap = {
|
|
510
|
+
const dirtyMap: Partial<Record<PUPPET.types.Dirty, (id: string) => Promise<unknown>>> = {
|
|
465
511
|
[PUPPET.types.Dirty.Contact]: async (id: string) => this._payloadStore.contact?.delete(id),
|
|
466
512
|
[PUPPET.types.Dirty.Friendship]: async (_: string) => {},
|
|
467
513
|
[PUPPET.types.Dirty.Message]: async (_: string) => {},
|
|
@@ -474,7 +520,7 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
474
520
|
}
|
|
475
521
|
|
|
476
522
|
try {
|
|
477
|
-
await dirtyMap[payloadType](payloadId)
|
|
523
|
+
await dirtyMap[payloadType]?.(payloadId)
|
|
478
524
|
} catch (error) {
|
|
479
525
|
this.emit('error', error)
|
|
480
526
|
}
|
|
@@ -1114,6 +1160,189 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1114
1160
|
return payload
|
|
1115
1161
|
}
|
|
1116
1162
|
|
|
1163
|
+
override async callInvite (
|
|
1164
|
+
contactIds: string[],
|
|
1165
|
+
media: PUPPET.types.CallMediaType,
|
|
1166
|
+
): Promise<string> {
|
|
1167
|
+
log.verbose('PuppetService', 'callInvite(%s, %s)', contactIds, media)
|
|
1168
|
+
|
|
1169
|
+
const request = new grpcPuppet.CallInviteRequest()
|
|
1170
|
+
request.setContactIdsList(contactIds)
|
|
1171
|
+
request.setMedia(puppetCallMediaTypeToGrpc(media))
|
|
1172
|
+
|
|
1173
|
+
const response = await util.promisify(
|
|
1174
|
+
this.grpcManager.client.callInvite
|
|
1175
|
+
.bind(this.grpcManager.client),
|
|
1176
|
+
)(request)
|
|
1177
|
+
|
|
1178
|
+
const callId = response.getCallId()
|
|
1179
|
+
if (!callId) {
|
|
1180
|
+
throw new Error('callInvite: puppet server returned empty call_id')
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
return callId
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
override async callAdd (
|
|
1187
|
+
callId: string,
|
|
1188
|
+
contactIds: string[],
|
|
1189
|
+
): Promise<void> {
|
|
1190
|
+
log.verbose('PuppetService', 'callAdd(%s, %s)', callId, contactIds)
|
|
1191
|
+
|
|
1192
|
+
const request = new grpcPuppet.CallAddRequest()
|
|
1193
|
+
request.setCallId(callId)
|
|
1194
|
+
request.setContactIdsList(contactIds)
|
|
1195
|
+
|
|
1196
|
+
await this.grpcUnary(
|
|
1197
|
+
this.grpcManager.client.callAdd,
|
|
1198
|
+
request,
|
|
1199
|
+
)
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
override async callAccept (
|
|
1203
|
+
callId: string,
|
|
1204
|
+
): Promise<void> {
|
|
1205
|
+
log.verbose('PuppetService', 'callAccept(%s)', callId)
|
|
1206
|
+
|
|
1207
|
+
const request = new grpcPuppet.CallAcceptRequest()
|
|
1208
|
+
request.setCallId(callId)
|
|
1209
|
+
|
|
1210
|
+
await this.grpcUnary(
|
|
1211
|
+
this.grpcManager.client.callAccept,
|
|
1212
|
+
request,
|
|
1213
|
+
)
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
override async callReject (
|
|
1217
|
+
callId: string,
|
|
1218
|
+
reason?: string,
|
|
1219
|
+
): Promise<void> {
|
|
1220
|
+
log.verbose('PuppetService', 'callReject(%s, %s)', callId, reason)
|
|
1221
|
+
|
|
1222
|
+
const request = new grpcPuppet.CallRejectRequest()
|
|
1223
|
+
request.setCallId(callId)
|
|
1224
|
+
if (reason !== undefined && reason !== '') {
|
|
1225
|
+
request.setReason(reason)
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
await this.grpcUnary(
|
|
1229
|
+
this.grpcManager.client.callReject,
|
|
1230
|
+
request,
|
|
1231
|
+
)
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
override async callCancel (
|
|
1235
|
+
callId: string,
|
|
1236
|
+
): Promise<void> {
|
|
1237
|
+
log.verbose('PuppetService', 'callCancel(%s)', callId)
|
|
1238
|
+
|
|
1239
|
+
const request = new grpcPuppet.CallCancelRequest()
|
|
1240
|
+
request.setCallId(callId)
|
|
1241
|
+
|
|
1242
|
+
await this.grpcUnary(
|
|
1243
|
+
this.grpcManager.client.callCancel,
|
|
1244
|
+
request,
|
|
1245
|
+
)
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
override async callHangup (
|
|
1249
|
+
callId: string,
|
|
1250
|
+
reason?: string,
|
|
1251
|
+
): Promise<void> {
|
|
1252
|
+
log.verbose('PuppetService', 'callHangup(%s, %s)', callId, reason)
|
|
1253
|
+
|
|
1254
|
+
const request = new grpcPuppet.CallHangupRequest()
|
|
1255
|
+
request.setCallId(callId)
|
|
1256
|
+
if (reason !== undefined && reason !== '') {
|
|
1257
|
+
request.setReason(reason)
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
await this.grpcUnary(
|
|
1261
|
+
this.grpcManager.client.callHangup,
|
|
1262
|
+
request,
|
|
1263
|
+
)
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
override async callMediaEndpoint (
|
|
1267
|
+
callId: string,
|
|
1268
|
+
): Promise<PUPPET.payloads.CallMediaEndpoint> {
|
|
1269
|
+
log.verbose('PuppetService', 'callMediaEndpoint(%s)', callId)
|
|
1270
|
+
|
|
1271
|
+
const request = new grpcPuppet.CallMediaEndpointRequest()
|
|
1272
|
+
request.setCallId(callId)
|
|
1273
|
+
|
|
1274
|
+
const response = await util.promisify(
|
|
1275
|
+
this.grpcManager.client.callMediaEndpoint
|
|
1276
|
+
.bind(this.grpcManager.client),
|
|
1277
|
+
)(request)
|
|
1278
|
+
|
|
1279
|
+
const url = response.getUrl()
|
|
1280
|
+
const token = response.getToken()
|
|
1281
|
+
if (!url || !token) {
|
|
1282
|
+
throw new Error('callMediaEndpoint: puppet server returned empty url or token')
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
const payload: PUPPET.payloads.CallMediaEndpoint = {
|
|
1286
|
+
url,
|
|
1287
|
+
token,
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (response.hasExpiresAt()) {
|
|
1291
|
+
payload.expiresAt = millisecondsFromTimestamp(response.getExpiresAt()!)
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
const protocol = response.getProtocol()
|
|
1295
|
+
if (protocol) {
|
|
1296
|
+
payload.protocol = protocol
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
return payload
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
override async callRawPayload (callId: string): Promise<grpcPuppet.CallPayloadResponse.AsObject> {
|
|
1303
|
+
log.verbose('PuppetService', 'callRawPayload(%s)', callId)
|
|
1304
|
+
|
|
1305
|
+
const request = new grpcPuppet.CallPayloadRequest()
|
|
1306
|
+
request.setId(callId)
|
|
1307
|
+
|
|
1308
|
+
const response = await util.promisify(
|
|
1309
|
+
this.grpcManager.client.callPayload
|
|
1310
|
+
.bind(this.grpcManager.client),
|
|
1311
|
+
)(request)
|
|
1312
|
+
|
|
1313
|
+
return response.toObject()
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
override async callRawPayloadParser (rawPayload: grpcPuppet.CallPayloadResponse.AsObject): Promise<PUPPET.payloads.Call> {
|
|
1317
|
+
log.verbose('PuppetService', 'callRawPayloadParser({id:%s})', rawPayload.id)
|
|
1318
|
+
|
|
1319
|
+
const media = grpcCallTypeToPuppetMedia(rawPayload.media)
|
|
1320
|
+
if (media === undefined) {
|
|
1321
|
+
throw new Error('callRawPayloadParser: media is required (got CALL_TYPE_UNKNOWN on the wire)')
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
if (rawPayload.startTime === undefined) {
|
|
1325
|
+
throw new Error('callRawPayloadParser: startTime is required')
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
const payload: PUPPET.payloads.Call = {
|
|
1329
|
+
id : rawPayload.id,
|
|
1330
|
+
participants : rawPayload.participantsList,
|
|
1331
|
+
media,
|
|
1332
|
+
startTime : millisecondsFromTimestampObject(rawPayload.startTime),
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
if (rawPayload.starter) {
|
|
1336
|
+
payload.starter = rawPayload.starter
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
if (rawPayload.endTime !== undefined) {
|
|
1340
|
+
payload.endTime = millisecondsFromTimestampObject(rawPayload.endTime)
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
return payload
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1117
1346
|
override async messageChatHistory (
|
|
1118
1347
|
messageId: string,
|
|
1119
1348
|
): Promise<PUPPET.payloads.ChatHistory[]> {
|
|
@@ -1487,6 +1716,211 @@ class PuppetService extends PUPPET.Puppet {
|
|
|
1487
1716
|
}
|
|
1488
1717
|
}
|
|
1489
1718
|
|
|
1719
|
+
override async messageBatchSendText (
|
|
1720
|
+
conversationIds : string[],
|
|
1721
|
+
text : string,
|
|
1722
|
+
batchTaskId? : string,
|
|
1723
|
+
): Promise<MessageBatchSendResponse> {
|
|
1724
|
+
log.verbose('PuppetService', 'messageBatchSendText(%s)', conversationIds.join(','))
|
|
1725
|
+
|
|
1726
|
+
const request = new grpcPuppet.MessageBatchSendTextRequest()
|
|
1727
|
+
request.setConversationIdsList(conversationIds)
|
|
1728
|
+
request.setText(text)
|
|
1729
|
+
if (batchTaskId) {
|
|
1730
|
+
request.setBatchTaskId(batchTaskId)
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendTextRequest, grpcPuppet.MessageBatchSendTextResponse>(
|
|
1734
|
+
this.grpcManager.client.messageBatchSendText,
|
|
1735
|
+
request,
|
|
1736
|
+
)
|
|
1737
|
+
|
|
1738
|
+
return grpcBatchResultsToPayload(response)
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
override async messageBatchSendFile (
|
|
1742
|
+
conversationIds : string[],
|
|
1743
|
+
fileBox : FileBoxInterface,
|
|
1744
|
+
batchTaskId? : string,
|
|
1745
|
+
): Promise<MessageBatchSendResponse> {
|
|
1746
|
+
log.verbose('PuppetService', 'messageBatchSendFile(%s)', conversationIds.join(','))
|
|
1747
|
+
|
|
1748
|
+
const request = new grpcPuppet.MessageBatchSendFileRequest()
|
|
1749
|
+
request.setConversationIdsList(conversationIds)
|
|
1750
|
+
request.setFileBox(await this.serializeFileBox(fileBox))
|
|
1751
|
+
if (batchTaskId) {
|
|
1752
|
+
request.setBatchTaskId(batchTaskId)
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendFileRequest, grpcPuppet.MessageBatchSendFileResponse>(
|
|
1756
|
+
this.grpcManager.client.messageBatchSendFile,
|
|
1757
|
+
request,
|
|
1758
|
+
)
|
|
1759
|
+
|
|
1760
|
+
return grpcBatchResultsToPayload(response)
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
override async messageBatchForward (
|
|
1764
|
+
conversationIds : string[],
|
|
1765
|
+
messageIds : string | string[],
|
|
1766
|
+
batchTaskId? : string,
|
|
1767
|
+
): Promise<MessageBatchSendResponse> {
|
|
1768
|
+
log.verbose('PuppetService', 'messageBatchForward(%s, %s)', conversationIds.join(','), messageIds)
|
|
1769
|
+
|
|
1770
|
+
const request = new grpcPuppet.MessageBatchForwardRequest()
|
|
1771
|
+
request.setConversationIdsList(conversationIds)
|
|
1772
|
+
if (Array.isArray(messageIds)) {
|
|
1773
|
+
request.setMessageIdsList(messageIds)
|
|
1774
|
+
if (messageIds.length === 1) {
|
|
1775
|
+
request.setMessageId(messageIds[0] as string)
|
|
1776
|
+
}
|
|
1777
|
+
} else {
|
|
1778
|
+
request.setMessageId(messageIds)
|
|
1779
|
+
}
|
|
1780
|
+
if (batchTaskId) {
|
|
1781
|
+
request.setBatchTaskId(batchTaskId)
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchForwardRequest, grpcPuppet.MessageBatchForwardResponse>(
|
|
1785
|
+
this.grpcManager.client.messageBatchForward,
|
|
1786
|
+
request,
|
|
1787
|
+
)
|
|
1788
|
+
|
|
1789
|
+
return grpcBatchResultsToPayload(response)
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
override async messageBatchSendContact (
|
|
1793
|
+
conversationIds : string[],
|
|
1794
|
+
contactId : string,
|
|
1795
|
+
batchTaskId? : string,
|
|
1796
|
+
): Promise<MessageBatchSendResponse> {
|
|
1797
|
+
log.verbose('PuppetService', 'messageBatchSendContact(%s, %s)', conversationIds.join(','), contactId)
|
|
1798
|
+
|
|
1799
|
+
const request = new grpcPuppet.MessageBatchSendContactRequest()
|
|
1800
|
+
request.setConversationIdsList(conversationIds)
|
|
1801
|
+
request.setContactId(contactId)
|
|
1802
|
+
if (batchTaskId) {
|
|
1803
|
+
request.setBatchTaskId(batchTaskId)
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendContactRequest, grpcPuppet.MessageBatchSendContactResponse>(
|
|
1807
|
+
this.grpcManager.client.messageBatchSendContact,
|
|
1808
|
+
request,
|
|
1809
|
+
)
|
|
1810
|
+
|
|
1811
|
+
return grpcBatchResultsToPayload(response)
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
override async messageBatchSendUrl (
|
|
1815
|
+
conversationIds : string[],
|
|
1816
|
+
urlLinkPayload : PUPPET.payloads.UrlLink,
|
|
1817
|
+
batchTaskId? : string,
|
|
1818
|
+
): Promise<MessageBatchSendResponse> {
|
|
1819
|
+
log.verbose('PuppetService', 'messageBatchSendUrl(%s)', conversationIds.join(','))
|
|
1820
|
+
|
|
1821
|
+
const request = new grpcPuppet.MessageBatchSendUrlRequest()
|
|
1822
|
+
request.setConversationIdsList(conversationIds)
|
|
1823
|
+
request.setUrlLink(urlLinkPayloadToPb(grpcPuppet, urlLinkPayload))
|
|
1824
|
+
if (batchTaskId) {
|
|
1825
|
+
request.setBatchTaskId(batchTaskId)
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendUrlRequest, grpcPuppet.MessageBatchSendUrlResponse>(
|
|
1829
|
+
this.grpcManager.client.messageBatchSendUrl,
|
|
1830
|
+
request,
|
|
1831
|
+
)
|
|
1832
|
+
|
|
1833
|
+
return grpcBatchResultsToPayload(response)
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
override async messageBatchSendMiniProgram (
|
|
1837
|
+
conversationIds : string[],
|
|
1838
|
+
miniProgramPayload : PUPPET.payloads.MiniProgram,
|
|
1839
|
+
batchTaskId? : string,
|
|
1840
|
+
): Promise<MessageBatchSendResponse> {
|
|
1841
|
+
log.verbose('PuppetService', 'messageBatchSendMiniProgram(%s)', conversationIds.join(','))
|
|
1842
|
+
|
|
1843
|
+
const request = new grpcPuppet.MessageBatchSendMiniProgramRequest()
|
|
1844
|
+
request.setConversationIdsList(conversationIds)
|
|
1845
|
+
request.setMiniProgram(miniProgramPayloadToPb(grpcPuppet, miniProgramPayload))
|
|
1846
|
+
if (batchTaskId) {
|
|
1847
|
+
request.setBatchTaskId(batchTaskId)
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendMiniProgramRequest, grpcPuppet.MessageBatchSendMiniProgramResponse>(
|
|
1851
|
+
this.grpcManager.client.messageBatchSendMiniProgram,
|
|
1852
|
+
request,
|
|
1853
|
+
)
|
|
1854
|
+
|
|
1855
|
+
return grpcBatchResultsToPayload(response)
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
override async messageBatchSendLocation (
|
|
1859
|
+
conversationIds : string[],
|
|
1860
|
+
locationPayload : PUPPET.payloads.Location,
|
|
1861
|
+
batchTaskId? : string,
|
|
1862
|
+
): Promise<MessageBatchSendResponse> {
|
|
1863
|
+
log.verbose('PuppetService', 'messageBatchSendLocation(%s)', conversationIds.join(','))
|
|
1864
|
+
|
|
1865
|
+
const request = new grpcPuppet.MessageBatchSendLocationRequest()
|
|
1866
|
+
request.setConversationIdsList(conversationIds)
|
|
1867
|
+
request.setLocation(locationPayloadToPb(grpcPuppet, locationPayload))
|
|
1868
|
+
if (batchTaskId) {
|
|
1869
|
+
request.setBatchTaskId(batchTaskId)
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendLocationRequest, grpcPuppet.MessageBatchSendLocationResponse>(
|
|
1873
|
+
this.grpcManager.client.messageBatchSendLocation,
|
|
1874
|
+
request,
|
|
1875
|
+
)
|
|
1876
|
+
|
|
1877
|
+
return grpcBatchResultsToPayload(response)
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
override async messageBatchSendChannel (
|
|
1881
|
+
conversationIds : string[],
|
|
1882
|
+
channelPayload : PUPPET.payloads.Channel,
|
|
1883
|
+
batchTaskId? : string,
|
|
1884
|
+
): Promise<MessageBatchSendResponse> {
|
|
1885
|
+
log.verbose('PuppetService', 'messageBatchSendChannel(%s)', conversationIds.join(','))
|
|
1886
|
+
|
|
1887
|
+
const request = new grpcPuppet.MessageBatchSendChannelRequest()
|
|
1888
|
+
request.setConversationIdsList(conversationIds)
|
|
1889
|
+
request.setChannel(channelPayloadToPb(grpcPuppet, channelPayload))
|
|
1890
|
+
if (batchTaskId) {
|
|
1891
|
+
request.setBatchTaskId(batchTaskId)
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendChannelRequest, grpcPuppet.MessageBatchSendChannelResponse>(
|
|
1895
|
+
this.grpcManager.client.messageBatchSendChannel,
|
|
1896
|
+
request,
|
|
1897
|
+
)
|
|
1898
|
+
|
|
1899
|
+
return grpcBatchResultsToPayload(response)
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
override async messageBatchSendChannelCard (
|
|
1903
|
+
conversationIds : string[],
|
|
1904
|
+
channelCardPayload : PUPPET.payloads.ChannelCard,
|
|
1905
|
+
batchTaskId? : string,
|
|
1906
|
+
): Promise<MessageBatchSendResponse> {
|
|
1907
|
+
log.verbose('PuppetService', 'messageBatchSendChannelCard(%s)', conversationIds.join(','))
|
|
1908
|
+
|
|
1909
|
+
const request = new grpcPuppet.MessageBatchSendChannelCardRequest()
|
|
1910
|
+
request.setConversationIdsList(conversationIds)
|
|
1911
|
+
request.setChannelCard(channelCardPayloadToPb(grpcPuppet, channelCardPayload))
|
|
1912
|
+
if (batchTaskId) {
|
|
1913
|
+
request.setBatchTaskId(batchTaskId)
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
const response = await this.grpcUnary<grpcPuppet.MessageBatchSendChannelCardRequest, grpcPuppet.MessageBatchSendChannelCardResponse>(
|
|
1917
|
+
this.grpcManager.client.messageBatchSendChannelCard,
|
|
1918
|
+
request,
|
|
1919
|
+
)
|
|
1920
|
+
|
|
1921
|
+
return grpcBatchResultsToPayload(response)
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1490
1924
|
override async messageSendFile (
|
|
1491
1925
|
conversationId : string,
|
|
1492
1926
|
fileBox : FileBoxInterface,
|
package/src/package-json.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import type { PackageJson } from 'type-fest'
|
|
5
5
|
export const packageJson: PackageJson = {
|
|
6
6
|
"name": "@juzi/wechaty-puppet-service",
|
|
7
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.115",
|
|
8
8
|
"description": "Puppet Service for Wechaty",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"exports": {
|
|
@@ -55,7 +55,7 @@ export const packageJson: PackageJson = {
|
|
|
55
55
|
"@chatie/eslint-config": "^1.0.4",
|
|
56
56
|
"@chatie/semver": "^0.4.7",
|
|
57
57
|
"@chatie/tsconfig": "^4.6.3",
|
|
58
|
-
"@juzi/wechaty-puppet": "^1.0.
|
|
58
|
+
"@juzi/wechaty-puppet": "^1.0.138",
|
|
59
59
|
"@juzi/wechaty-puppet-mock": "^1.0.1",
|
|
60
60
|
"@swc/core": "1.3.39",
|
|
61
61
|
"@types/google-protobuf": "^3.15.5",
|
|
@@ -74,10 +74,10 @@ export const packageJson: PackageJson = {
|
|
|
74
74
|
"why-is-node-running": "^2.2.1"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
|
-
"@juzi/wechaty-puppet": "^1.0.
|
|
77
|
+
"@juzi/wechaty-puppet": "^1.0.138"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@juzi/wechaty-grpc": "^1.0.
|
|
80
|
+
"@juzi/wechaty-grpc": "^1.0.102",
|
|
81
81
|
"clone-class": "^1.1.1",
|
|
82
82
|
"ducks": "^1.0.2",
|
|
83
83
|
"file-box": "^1.5.5",
|