mezon-js 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
package/socket.ts ADDED
@@ -0,0 +1,1303 @@
1
+ /**
2
+ * Copyright 2020 The Mezon Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { decode } from 'js-base64'
18
+
19
+ import {ApiMessageAttachment, ApiMessageMention, ApiMessageReaction, ApiMessageRef, ApiNotification, ApiRpc} from "./api.gen";
20
+ import {Session} from "./session";
21
+ import {Notification} from "./client";
22
+ import {WebSocketAdapter, WebSocketAdapterText} from "./web_socket_adapter"
23
+
24
+ /** Stores function references for resolve/reject with a DOM Promise. */
25
+ interface PromiseExecutor {
26
+ resolve: (value?: any) => void;
27
+ reject: (reason?: any) => void;
28
+ }
29
+ /** An object which represents a connected user in the server. */
30
+ export interface Presence {
31
+ /** The id of the user. */
32
+ user_id: string;
33
+ /** The session id of the user. */
34
+ session_id: string;
35
+ /** The username of the user. */
36
+ username: string;
37
+ /** The node the user is connected to. */
38
+ node: string;
39
+ }
40
+
41
+ /** A response from a channel join operation. */
42
+ export interface Channel {
43
+ /** The server-assigned channel id. */
44
+ id: string;
45
+ // label
46
+ chanel_label: string;
47
+ /** The presences visible on the chat channel. */
48
+ presences: Presence[];
49
+ /** The presence of the current user, i.e. yourself. */
50
+ self: Presence;
51
+ // The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
52
+ user_id_one: string;
53
+ // The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
54
+ user_id_two: string;
55
+ }
56
+
57
+ /** Join a realtime chat channel. */
58
+ interface ChannelJoin {
59
+ channel_join: {
60
+ /** The id of the channel to join. */
61
+ target_id: string;
62
+ /** The name of the channel to join. */
63
+ target: string;
64
+ /** The channel type: 1 = Channel, 2 = Direct Message, 3 = Group. */
65
+ type: number;
66
+ /** Whether channel messages are persisted in the database. */
67
+ persistence: boolean;
68
+ /** Whether the user's channel presence is hidden when joining. */
69
+ hidden: boolean;
70
+ };
71
+ }
72
+
73
+ /** Leave a realtime chat channel. */
74
+ interface ChannelLeave {
75
+ channel_leave: {
76
+ /** The id of the channel to leave. */
77
+ channel_id:string;
78
+ // The mode
79
+ mode: number;
80
+ // The channel label
81
+ channel_label: string;
82
+ };
83
+ }
84
+
85
+ /** Last seen message by user */
86
+ export interface LastSeenMessageEvent {
87
+ /** The channel this message belongs to. */
88
+ channel_id:string;
89
+ // The mode
90
+ mode: number;
91
+ // The channel label
92
+ channel_label: string;
93
+ /** The unique ID of this message. */
94
+ message_id: string;
95
+ }
96
+
97
+ /** User is react to message */
98
+ export interface MessageReactionEvent {
99
+ // id of reaction message
100
+ id: string;
101
+ /** The channel this message belongs to. */
102
+ channel_id:string;
103
+ // The mode
104
+ mode: number;
105
+ // The channel label
106
+ channel_label: string;
107
+ /** The message that user react */
108
+ message_id: string;
109
+ /** Message sender, usually a user ID. */
110
+ sender_id: string;
111
+ //
112
+ sender_name?: string;
113
+ //
114
+ sender_avatar?: string;
115
+ /** Emoji list. */
116
+ emoji: string;
117
+ // count of emoji
118
+ count: number;
119
+ // action
120
+ action: boolean;
121
+ }
122
+
123
+ /** User is react to message */
124
+ export interface MessageMentionEvent {
125
+ /** The channel this message belongs to. */
126
+ channel_id:string;
127
+ // The mode
128
+ mode: number;
129
+ // The channel label
130
+ channel_label: string;
131
+ /** The message that user react */
132
+ message_id: string;
133
+ /** Message sender, usually a user ID. */
134
+ sender_id: string;
135
+ // mention user id
136
+ user_id: string;
137
+ // mention username
138
+ username: string;
139
+ }
140
+
141
+ /** User is react to message */
142
+ export interface MessageAttachmentEvent {
143
+ /** The channel this message belongs to. */
144
+ channel_id:string;
145
+ // The mode
146
+ mode: number;
147
+ // The channel label
148
+ channel_label: string;
149
+ /** The message that user react */
150
+ message_id: string;
151
+ /** Message sender, usually a user ID. */
152
+ sender_id: string;
153
+ // Attachment file name
154
+ filename: string;
155
+ // Attachment file size
156
+ size: number;
157
+ // Attachment url
158
+ url: string;
159
+ // Attachment file type
160
+ filetype: string;
161
+ // Attachment width
162
+ width?: number;
163
+ // Attachment width
164
+ height?: number;
165
+ }
166
+
167
+ /** User is delete to message */
168
+ export interface MessageDeletedEvent {
169
+ /** The channel this message belongs to. */
170
+ channel_id:string;
171
+ // The mode
172
+ mode: number;
173
+ // The channel label
174
+ channel_label: string;
175
+ /** The message that user react */
176
+ message_id: string;
177
+ /** Message sender, usually a user ID. */
178
+ deletor: string;
179
+ }
180
+
181
+
182
+ /** User is delete to message */
183
+ export interface MessageRefEvent {
184
+ /** The channel this message belongs to. */
185
+ channel_id:string;
186
+ // The mode
187
+ mode: number;
188
+ // The channel label
189
+ channel_label: string;
190
+ /** The message that user react */
191
+ message_id: string;
192
+ /** Message reference ID. */
193
+ message_ref_id: string;
194
+ /** reference type */
195
+ ref_type: number;
196
+ }
197
+
198
+ /** User is typing */
199
+ export interface MessageTypingEvent {
200
+ /** The channel this message belongs to. */
201
+ channel_id:string;
202
+ // The mode
203
+ mode: number;
204
+ // The channel label
205
+ channel_label: string;
206
+ /** Message sender, usually a user ID. */
207
+ sender_id: string;
208
+ }
209
+
210
+ /** An incoming message on a realtime chat channel. */
211
+ export interface ChannelMessageEvent {
212
+ avatar?: string;
213
+ //The channel this message belongs to.
214
+ channel_id:string;
215
+ // The mode
216
+ mode: number;
217
+ //The name of the chat room, or an empty string if this message was not sent through a chat room.
218
+ channel_label: string;
219
+ //The clan this message belong to.
220
+ clan_id?: string;
221
+ //The code representing a message type or category.
222
+ code: number;
223
+ //The content payload.
224
+ content: string;
225
+ //The UNIX time (for gRPC clients) or ISO string (for REST clients) when the message was created.
226
+ create_time: string;
227
+ //The unique ID of this message.
228
+ id: string;
229
+ //True if the message was persisted to the channel's history, false otherwise.
230
+ persistent?: boolean;
231
+ //Message sender, usually a user ID.
232
+ sender_id: string;
233
+ //The UNIX time (for gRPC clients) or ISO string (for REST clients) when the message was last updated.
234
+ update_time: string;
235
+ //The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
236
+ user_id_one: string;
237
+ //The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
238
+ user_id_two: string;
239
+ //The username of the message sender, if any.
240
+ username: string;
241
+ //
242
+ reactions?: Array<ApiMessageReaction>;
243
+ //
244
+ mentions?: Array<ApiMessageMention>;
245
+ //
246
+ attachments?: Array<ApiMessageAttachment>;
247
+ //
248
+ references?: Array<ApiMessageRef>;
249
+ //
250
+ referenced_message?: ChannelMessageEvent;
251
+ }
252
+
253
+ /** An acknowledgement received in response to sending a message on a chat channel. */
254
+ export interface ChannelMessageAck {
255
+ /** The server-assigned channel ID. */
256
+ channel_id:string;
257
+ // The mode
258
+ mode: number;
259
+ /** A unique ID for the chat message. */
260
+ message_id: string;
261
+ /** A user-defined code for the chat message. */
262
+ code: number;
263
+ /** The username of the sender of the message. */
264
+ username: string;
265
+ /** The UNIX time when the message was created. */
266
+ create_time: string;
267
+ /** The UNIX time when the message was updated. */
268
+ update_time: string;
269
+ /** True if the chat message has been stored in history. */
270
+ persistence: boolean;
271
+ }
272
+
273
+ /** Send a message to a realtime chat channel. */
274
+ interface ChannelMessageSend {
275
+ channel_message_send: {
276
+ /** Clan Id */
277
+ clan_id: string;
278
+ /** The server-assigned channel ID. */
279
+ channel_id:string;
280
+ // The mode
281
+ mode: number;
282
+ // channel label
283
+ channel_label: string;
284
+ /** The content payload. */
285
+ content: any;
286
+ //
287
+ mentions?: Array<MessageMentionEvent>;
288
+ //
289
+ attachments?: Array<MessageAttachmentEvent>;
290
+ };
291
+ }
292
+
293
+ /** Update a message previously sent to a realtime chat channel. */
294
+ interface ChannelMessageUpdate {
295
+ channel_message_update: {
296
+ /** The server-assigned channel ID. */
297
+ channel_id: string,
298
+ /** The server-assigned channel label. */
299
+ channel_label: string,
300
+ /** A unique ID for the chat message to be updated. */
301
+ message_id: string,
302
+ /** The content payload. */
303
+ content: any,
304
+ /** The mode payload. */
305
+ mode: number;
306
+ };
307
+ }
308
+
309
+ /** Remove a message previously sent to a realtime chat channel. */
310
+ interface ChannelMessageRemove {
311
+ channel_message_remove: {
312
+ /** The server-assigned channel ID. */
313
+ channel_id:string;
314
+ // The mode
315
+ mode: number;
316
+ // The channel label
317
+ channel_label: string;
318
+ /** A unique ID for the chat message to be removed. */
319
+ message_id: string;
320
+ };
321
+ }
322
+
323
+ /** Presence update for a particular realtime chat channel. */
324
+ export interface ChannelPresenceEvent {
325
+ /** The unique identifier of the chat channel. */
326
+ channel_id: string;
327
+ // The channel name
328
+ channel_label: string;
329
+ // The mode
330
+ mode: number;
331
+ /** Presences of the users who joined the channel. */
332
+ joins: Presence[];
333
+ /** Presences of users who left the channel. */
334
+ leaves: Presence[];
335
+ }
336
+
337
+ export interface VoiceLeavedEvent {
338
+ // event id
339
+ id: string;
340
+ // clan id
341
+ clan_id: string;
342
+ // voice channel name
343
+ voice_channel_id: string;
344
+ // last participant
345
+ last_participant: boolean;
346
+ }
347
+
348
+ export interface VoiceJoinedEvent {
349
+ /** The unique identifier of the chat channel. */
350
+ clan_id: string;
351
+ // The channel name
352
+ clan_name: string;
353
+ // id voice
354
+ id: string;
355
+ // voice participant
356
+ participant: string;
357
+ // user id
358
+ user_id: string;
359
+ // voice channel label
360
+ voice_channel_label: string;
361
+ // voice channel id
362
+ voice_channel_id: string;
363
+ // last screenshot
364
+ last_screenshot: string;
365
+ }
366
+
367
+ /** Stream identifier */
368
+ export interface StreamId {
369
+ /** The type of stream (e.g. chat). */
370
+ mode: number;
371
+ /** The primary stream subject, usually a user id. */
372
+ subject: string;
373
+ /** A secondary stream subject, for example for a direct chat. */
374
+ descriptor: string;
375
+ /** Meta-information (e.g. chat room name). */
376
+ label: string;
377
+ }
378
+
379
+ /** Stream data. */
380
+ export interface StreamData {
381
+ /** The stream identifier. */
382
+ stream: StreamId;
383
+ /** A reference to the user presence that sent this data, if any. */
384
+ sender?: Presence;
385
+ /** Arbitrary contents of the data message. */
386
+ data: string;
387
+ /** True if this data was delivered reliably. */
388
+ reliable?: boolean;
389
+ }
390
+
391
+ /** Presence updates. */
392
+ export interface StreamPresenceEvent {
393
+ /** The stream identifier. */
394
+ stream: StreamId;
395
+ /** Presences of users who joined the stream. */
396
+ joins: Presence[];
397
+ /** Presences of users who left the stream. */
398
+ leaves: Presence[];
399
+ }
400
+
401
+ /** Incoming information about a party. */
402
+ export interface Party {
403
+ /** The unique party identifier. */
404
+ party_id : string;
405
+ /** True, if the party is open to join. */
406
+ open : boolean;
407
+ /** The maximum number of party members. */
408
+ max_size : number;
409
+ /** The current user in this party, i.e. yourself. */
410
+ self : Presence;
411
+ /** The current party leader. */
412
+ leader : Presence;
413
+ /** All members currently in the party. */
414
+ presences : Presence[];
415
+ }
416
+
417
+ /** Create a party. */
418
+ export interface PartyCreate {
419
+ party_create: {
420
+ /** True, if the party is open to join. */
421
+ open : boolean;
422
+ /** The maximum number of party members. */
423
+ max_size : number;
424
+ }
425
+ }
426
+
427
+ /** Join a party. */
428
+ interface PartyJoin {
429
+ party_join: {
430
+ /** The unique party identifier. */
431
+ party_id : string;
432
+ }
433
+ }
434
+
435
+ /** Leave a party. */
436
+ interface PartyLeave {
437
+ party_leave: {
438
+ /** The unique party identifier. */
439
+ party_id : string;
440
+ }
441
+ }
442
+
443
+ /** Promote a new party leader. */
444
+ interface PartyPromote {
445
+ party_promote: {
446
+ /** The unique party identifier. */
447
+ party_id : string;
448
+ /** The user presence being promoted to leader. */
449
+ presence : Presence;
450
+ }
451
+ }
452
+
453
+ /** Announcement of a new party leader. */
454
+ export interface PartyLeader {
455
+ /** The unique party identifier. */
456
+ party_id : string;
457
+ /** The presence of the new party leader. */
458
+ presence : Presence;
459
+ }
460
+
461
+ /** Accept a request to join. */
462
+ interface PartyAccept {
463
+ party_accept: {
464
+ /** The unique party identifier. */
465
+ party_id : string;
466
+ /** The presence being accepted to join the party. */
467
+ presence : Presence;
468
+ }
469
+ }
470
+
471
+ /** End a party, kicking all party members and closing it. */
472
+ interface PartyClose {
473
+ party_close: {
474
+ /** The unique party identifier. */
475
+ party_id : string;
476
+ }
477
+ }
478
+
479
+ /** Incoming party data delivered from the server. */
480
+ export interface PartyData {
481
+ /** The unique party identifier. */
482
+ party_id: string;
483
+ /** A reference to the user presence that sent this data, if any. */
484
+ presence: Presence;
485
+ /** The operation code the message was sent with. */
486
+ op_code: number;
487
+ /** Data payload, if any. */
488
+ data: Uint8Array;
489
+ }
490
+
491
+ /** A client to server request to send data to a party. */
492
+ interface PartyDataSend {
493
+ party_data_send: {
494
+ /** The unique party identifier. */
495
+ party_id : string;
496
+ /** The operation code the message was sent with. */
497
+ op_code : number;
498
+ /** Data payload, if any. */
499
+ data : string | Uint8Array;
500
+ }
501
+ }
502
+
503
+ /** Incoming notification for one or more new presences attempting to join the party. */
504
+ export interface PartyJoinRequest {
505
+ /** The ID of the party to get a list of join requests for. */
506
+ party_id : string;
507
+ /** Presences attempting to join, or who have joined. */
508
+ presences : Presence[];
509
+ }
510
+
511
+ /** Request a list of pending join requests for a party. */
512
+ export interface PartyJoinRequestList {
513
+ party_join_request_list: {
514
+ /** The ID of the party to get a list of join requests for. */
515
+ party_id : string;
516
+ }
517
+ }
518
+
519
+ /** Begin matchmaking as a party. */
520
+ interface PartyMatchmakerAdd {
521
+ party_matchmaker_add: {
522
+ /** The ID of the party to create a matchmaker ticket for. */
523
+ party_id : string;
524
+ /** Minimum total user count to match together. */
525
+ min_count : number;
526
+ /** Maximum total user count to match together. */
527
+ max_count : number;
528
+ /** Filter query used to identify suitable users. */
529
+ query : string;
530
+ /** String properties describing the party (e.g. region). */
531
+ string_properties? : Record<string, string>;
532
+ /** Numeric properties describing the party (e.g. rank). */
533
+ numeric_properties? : Record<string, number>;
534
+ }
535
+ }
536
+
537
+ /** Cancel a party matchmaking process using a ticket. */
538
+ interface PartyMatchmakerRemove {
539
+ party_matchmaker_remove: {
540
+ /** The ID of the party to cancel a matchmaker ticket for. */
541
+ party_id : string;
542
+ /** The ticket to remove. */
543
+ ticket : string;
544
+ }
545
+ }
546
+
547
+ /** A response from starting a new party matchmaking process. */
548
+ export interface PartyMatchmakerTicket {
549
+ /** The ID of the party. */
550
+ party_id: string;
551
+ /** The matchmaker ticket created. */
552
+ ticket: string;
553
+ }
554
+
555
+ /** Presence update for a particular party. */
556
+ export interface PartyPresenceEvent {
557
+ /** The ID of the party. */
558
+ party_id : string;
559
+ /** The user presences that have just joined the party. */
560
+ joins : Presence[];
561
+ /** The user presences that have just left the party. */
562
+ leaves : Presence[];
563
+ }
564
+
565
+ /** Kick a party member, or decline a request to join. */
566
+ interface PartyRemove {
567
+ party_remove: {
568
+ /** The ID of the party to remove/reject from. */
569
+ party_id : string;
570
+ /** The presence to remove/reject. */
571
+ presence : Presence;
572
+ }
573
+ }
574
+
575
+ /** Execute an Lua function on the server. */
576
+ interface Rpc {
577
+ rpc: ApiRpc;
578
+ }
579
+
580
+ /** Application-level heartbeat ping. */
581
+ interface Ping {
582
+
583
+ }
584
+
585
+ /** A snapshot of statuses for some set of users. */
586
+ export interface Status {
587
+ /** The user presences to view statuses of. */
588
+ presences: Presence[];
589
+ }
590
+
591
+ /** Start receiving status updates for some set of users. */
592
+ interface StatusFollow {
593
+ /** The IDs of the users to follow. */
594
+ status_follow: {user_ids: string[];}
595
+ }
596
+
597
+ /** A batch of status updates for a given user. */
598
+ export interface StatusPresenceEvent {
599
+ /** This join information is in response to a subscription made to be notified when a user comes online. */
600
+ joins: Presence[];
601
+ /** This join information is in response to a subscription made to be notified when a user goes offline. */
602
+ leaves: Presence[];
603
+ }
604
+
605
+ /** Stop receiving status updates for some set of users. */
606
+ interface StatusUnfollow {
607
+ /** The IDs of user to unfollow. */
608
+ status_unfollow: {user_ids: string[];};
609
+ }
610
+
611
+ /** Set the user's own status. */
612
+ interface StatusUpdate {
613
+ /** Status string to set, if not present the user will appear offline. */
614
+ status_update: {status?: string;};
615
+ }
616
+
617
+ /** A socket connection to Mezon server. */
618
+ export interface Socket {
619
+ /** Connect to the server. */
620
+ connect(session: Session, createStatus: boolean): Promise<Session>;
621
+
622
+ /** Disconnect from the server. */
623
+ disconnect(fireDisconnectEvent: boolean): void;
624
+
625
+ /** Accept a request to join. */
626
+ acceptPartyMember(party_id : string, presence : Presence) : Promise<void>;
627
+
628
+ /** End a party, kicking all party members and closing it. */
629
+ closeParty(party_id : string) : Promise<void>;
630
+
631
+ /** Create a party. */
632
+ createParty(open : boolean, max_size : number) : Promise<Party>;
633
+
634
+ /** Subscribe to one or more users for their status updates. */
635
+ followUsers(user_ids: string[]) : Promise<Status>;
636
+
637
+ /** Join a chat channel on the server. */
638
+ joinChat(channel_id: string, channel_label: string, mode: number, type: number, persistence: boolean, hidden: boolean) : Promise<Channel>;
639
+
640
+ /** Join a party. */
641
+ joinParty(party_id: string) : Promise<void>;
642
+
643
+ /** Leave a chat channel on the server. */
644
+ leaveChat(channel_id: string, channel_label: string, mode: number) : Promise<void>;
645
+
646
+ /** Leave a multiplayer match on the server. */
647
+ leaveMatch(matchId : string) : Promise<void>;
648
+
649
+ /** Leave a party. */
650
+ leaveParty(party_id: string) : Promise<void>;
651
+
652
+ /** Request a list of pending join requests for a party. */
653
+ listPartyJoinRequests(party_id : string) : Promise<PartyJoinRequest>;
654
+
655
+ /** Promote a new party leader. */
656
+ promotePartyMember(party_id : string, party_member : Presence) : Promise<PartyLeader>;
657
+
658
+ /** Remove a chat message from a chat channel on the server. */
659
+ removeChatMessage(channel_id: string, channel_label: string, mode: number, message_id: string) : Promise<ChannelMessageAck>;
660
+
661
+ /** Kick a party member, or decline a request to join. */
662
+ removePartyMember(party_id : string, presence : Presence) : Promise<void>;
663
+
664
+ /** Execute an RPC function to the server. */
665
+ rpc(id?: string, payload?: string, http_key?: string) : Promise<ApiRpc>
666
+
667
+ /** Send data to a party. */
668
+ sendPartyData(party_id : string, opcode : number, data : string | Uint8Array) : Promise<void>;
669
+
670
+ /** Unfollow one or more users from their status updates. */
671
+ unfollowUsers(user_ids : string[]) : Promise<void>;
672
+
673
+ /** Update a chat message on a chat channel in the server. */
674
+ updateChatMessage(channel_id: string, channel_label: string, mode: number, message_id : string, content: any) : Promise<ChannelMessageAck>;
675
+
676
+ /** Update the status for the current user online. */
677
+ updateStatus(status? : string) : Promise<void>;
678
+
679
+ /** Send a chat message to a chat channel on the server. */
680
+ writeChatMessage(clan_id: string, channel_id: string, channel_label: string, mode: number, content?: any, mentions?: Array<ApiMessageMention>, attachments?: Array<ApiMessageAttachment>, references?: Array<ApiMessageRef>) : Promise<ChannelMessageAck>;
681
+
682
+ /** Send message typing */
683
+ writeMessageTyping(channel_id: string, channel_label: string, mode: number) : Promise<MessageTypingEvent>;
684
+
685
+ /** Send message reaction */
686
+ writeMessageReaction(id: string, channel_id: string, channel_label: string, mode: number, message_id: string, emoji: string, count: number, message_sender_id: string, action_delete: boolean) : Promise<MessageReactionEvent>;
687
+
688
+ /** Send message mention */
689
+ writeMessageDeleted(channel_id: string, channel_label: string, mode: number, message_id: string, deletor: string) : Promise<MessageDeletedEvent>;
690
+
691
+ /** Send last seen message */
692
+ writeLastSeenMessage(channel_id: string, channel_label: string, mode: number, message_id: string, timestamp: string) : Promise<LastSeenMessageEvent>;
693
+
694
+ /** send voice joined */
695
+ writeVoiceJoined(id: string, clanId: string, clanName: string, voiceChannelId: string, voiceChannelLabel: string, participant: string, lastScreenshot: string) : Promise<VoiceJoinedEvent>;
696
+
697
+ /** send voice leaved */
698
+ writeVoiceLeaved(id: string, clanId: string, voiceChannelId: string, lastParticipant: boolean) : Promise<VoiceLeavedEvent>;
699
+
700
+ /** Handle disconnect events received from the socket. */
701
+ ondisconnect: (evt: Event) => void;
702
+
703
+ /** Handle error events received from the socket. */
704
+ onerror: (evt: Event) => void;
705
+
706
+ /** Receive notifications from the socket. */
707
+ onnotification: (notification: Notification) => void;
708
+
709
+ /** Receive party events. */
710
+ onparty: (party : Party) => void;
711
+
712
+ /** Receive party close events. */
713
+ onpartyclose: (partyClose : PartyClose) => void;
714
+
715
+ /** Receive party data updates. */
716
+ onpartydata: (partyData: PartyData) => void;
717
+
718
+ /** Receive party join requests, if party leader. */
719
+ onpartyjoinrequest: (partyJoinRequest: PartyJoinRequest) => void;
720
+
721
+ /** Receive announcements of a new party leader. */
722
+ onpartyleader: (partyLeader : PartyLeader) => void;
723
+
724
+ /** Receive a presence update for a party. */
725
+ onpartypresence: (partyPresence : PartyPresenceEvent) => void;
726
+
727
+ /** Receive status presence updates. */
728
+ onstatuspresence: (statusPresence: StatusPresenceEvent) => void;
729
+
730
+ /** Receive stream presence updates. */
731
+ onstreampresence: (streamPresence: StreamPresenceEvent) => void;
732
+
733
+ /** Receive stream data. */
734
+ onstreamdata: (streamData: StreamData) => void;
735
+
736
+ /**
737
+ * An application-level heartbeat timeout that fires after the client does not receive a pong from the server after the heartbeat interval.
738
+ * Most browsers maintain an internal heartbeat, in which case its unlikely you'll need to use this callback. However, Chrome does not implement an internal heartbeat.
739
+ * We fire this separately from `onclose` because heartbeats fail when there's no connectivity, and many browsers don't fire `onclose` until the closing handshake either succeeds or fails.
740
+ * In any case, be aware that `onclose` will still fire if there is a heartbeat timeout in a potentially delayed manner.
741
+ */
742
+ onheartbeattimeout: () => void;
743
+
744
+ /** Receive channel message. */
745
+ onchannelmessage: (channelMessage: ChannelMessageEvent) => void;
746
+
747
+ /** Receive typing event */
748
+ onmessagetyping: (messageTypingEvent: MessageTypingEvent) => void;
749
+
750
+ /** Receive reaction event */
751
+ onmessagereaction: (messageReactionEvent: MessageReactionEvent) => void;
752
+
753
+ /** Receive deleted message */
754
+ onmessagedeleted: (messageDeletedEvent: MessageDeletedEvent) => void;
755
+
756
+ /** Receive channel presence updates. */
757
+ onchannelpresence: (channelPresence: ChannelPresenceEvent) => void;
758
+
759
+ // when someone join to voice room
760
+ onvoicejoined: (voiceParticipant: VoiceJoinedEvent) => void;
761
+
762
+ // when someone join to voice room
763
+ onvoiceleaved: (voiceParticipant: VoiceLeavedEvent) => void;
764
+
765
+ /* Set the heartbeat timeout used by the socket to detect if it has lost connectivity to the server. */
766
+ setHeartbeatTimeoutMs(ms : number) : void;
767
+
768
+ /* Get the heartbeat timeout used by the socket to detect if it has lost connectivity to the server. */
769
+ getHeartbeatTimeoutMs() : number;
770
+ }
771
+
772
+ /** Reports an error received from a socket message. */
773
+ export interface SocketError {
774
+ /** The error code. */
775
+ code: number;
776
+ /** A message in English to help developers debug the response. */
777
+ message: string;
778
+ }
779
+
780
+ /** A socket connection to Mezon server implemented with the DOM's WebSocket API. */
781
+ export class DefaultSocket implements Socket {
782
+ public static readonly DefaultHeartbeatTimeoutMs = 10000;
783
+ public static readonly DefaultSendTimeoutMs = 10000;
784
+ public static readonly DefaultConnectTimeoutMs = 30000;
785
+
786
+ private readonly cIds: { [key: string]: PromiseExecutor };
787
+ private nextCid: number;
788
+ private _heartbeatTimeoutMs: number;
789
+
790
+ constructor(
791
+ readonly host: string,
792
+ readonly port: string,
793
+ readonly useSSL: boolean = false,
794
+ public verbose: boolean = false,
795
+ readonly adapter : WebSocketAdapter = new WebSocketAdapterText(),
796
+ readonly sendTimeoutMs : number = DefaultSocket.DefaultSendTimeoutMs
797
+ ) {
798
+ this.cIds = {};
799
+ this.nextCid = 1;
800
+ this._heartbeatTimeoutMs = DefaultSocket.DefaultHeartbeatTimeoutMs;
801
+ }
802
+
803
+ generatecid(): string {
804
+ const cid = this.nextCid.toString();
805
+ ++this.nextCid;
806
+ return cid;
807
+ }
808
+
809
+ connect(session: Session, createStatus: boolean = false, connectTimeoutMs: number = DefaultSocket.DefaultConnectTimeoutMs): Promise<Session> {
810
+ if (this.adapter.isOpen()) {
811
+ return Promise.resolve(session);
812
+ }
813
+
814
+ const scheme = (this.useSSL) ? "wss://" : "ws://";
815
+ this.adapter.connect(scheme, this.host, this.port, createStatus, session.token);
816
+
817
+ this.adapter.onClose = (evt: Event) => {
818
+ this.ondisconnect(evt);
819
+ }
820
+
821
+ this.adapter.onError = (evt: Event) => {
822
+ this.onerror(evt);
823
+ }
824
+
825
+ this.adapter.onMessage = (message: any) => {
826
+ if (this.verbose && window && window.console) {
827
+ console.log("Response: %o", JSON.stringify(message));
828
+ }
829
+
830
+ /** Inbound message from server. */
831
+ if (!message.cid) {
832
+ if (message.notifications) {
833
+ message.notifications.notifications.forEach((n: ApiNotification) => {
834
+ n.content = n.content ? JSON.parse(n.content) : undefined;
835
+ this.onnotification(n);
836
+ });
837
+ } else if (message.voice_joined_event) {
838
+ this.onvoicejoined(message.voice_joined_event)
839
+ } else if (message.voice_leaved_event) {
840
+ this.onvoiceleaved(message.voice_leaved_event)
841
+ } else if (message.status_presence_event) {
842
+ this.onstatuspresence(<StatusPresenceEvent>message.status_presence_event);
843
+ } else if (message.stream_presence_event) {
844
+ this.onstreampresence(<StreamPresenceEvent>message.stream_presence_event);
845
+ } else if (message.stream_data) {
846
+ this.onstreamdata(<StreamData>message.stream_data);
847
+ } else if (message.channel_message) {
848
+ try {
849
+ var e: ChannelMessageEvent = {
850
+ avatar: message.channel_message.avatar,
851
+ channel_id: message.channel_message.channel_id,
852
+ mode: message.channel_message.mode,
853
+ channel_label: message.channel_message.channel_label,
854
+ clan_id: message.channel_message.clan_id,
855
+ code: message.channel_message.code,
856
+ content: JSON.parse(message.channel_message.content),
857
+ create_time: message.channel_message.create_time,
858
+ id: message.channel_message.message_id,
859
+ sender_id: message.channel_message.sender_id,
860
+ update_time: message.channel_message.update_time,
861
+ user_id_one: message.channel_message.user_id_one,
862
+ user_id_two: message.channel_message.user_id_two,
863
+ username: message.channel_message.username,
864
+ reactions: JSON.parse(message.channel_message.reactions),
865
+ mentions: JSON.parse(message.channel_message.mentions),
866
+ attachments: JSON.parse(message.channel_message.attachments),
867
+ references: JSON.parse(message.channel_message.references)
868
+ };
869
+ this.onchannelmessage(e);
870
+ } catch(e) {
871
+ //console.log("error parse data", e);
872
+ }
873
+ } else if (message.message_typing_event) {
874
+ this.onmessagetyping(<MessageTypingEvent>message.message_typing_event);
875
+ } else if (message.message_reaction_event) {
876
+ this.onmessagereaction(<MessageReactionEvent>message.message_reaction_event);
877
+ } else if (message.message_deleted_event) {
878
+ this.onmessagedeleted(<MessageDeletedEvent>message.message_deleted_event);
879
+ } else if (message.channel_presence_event) {
880
+ this.onchannelpresence(<ChannelPresenceEvent>message.channel_presence_event);
881
+ } else if (message.party_data) {
882
+ message.party_data.op_code = parseInt(message.party_data.op_code);
883
+ this.onpartydata(<PartyData>message.party_data);
884
+ } else if (message.party_close) {
885
+ this.onpartyclose(<PartyClose>message.party_close);
886
+ } else if (message.party_join_request) {
887
+ this.onpartyjoinrequest(message.party_join_request);
888
+ } else if (message.party_leader) {
889
+ this.onpartyleader(<PartyLeader> message.party_leader);
890
+ } else if (message.party_presence_event) {
891
+ this.onpartypresence(<PartyPresenceEvent> message.party_presence_event);
892
+ } else if (message.party) {
893
+ this.onparty(<Party> message.party);
894
+ } else {
895
+ if (this.verbose && window && window.console) {
896
+ console.log("Unrecognized message received: %o", message);
897
+ }
898
+ }
899
+ } else {
900
+ const executor = this.cIds[message.cid];
901
+ if (!executor) {
902
+ if (this.verbose && window && window.console) {
903
+ console.error("No promise executor for message: %o", message);
904
+ }
905
+ return;
906
+ }
907
+ delete this.cIds[message.cid];
908
+
909
+ if (message.error) {
910
+ executor.reject(<SocketError>message.error);
911
+ } else {
912
+ executor.resolve(message);
913
+ }
914
+ }
915
+ }
916
+
917
+ return new Promise((resolve, reject) => {
918
+ this.adapter.onOpen = (evt: Event) => {
919
+ if (this.verbose && window && window.console) {
920
+ console.log(evt);
921
+ }
922
+
923
+ this.pingPong();
924
+ resolve(session);
925
+ }
926
+ this.adapter.onError = (evt: Event) => {
927
+ reject(evt);
928
+ this.adapter.close();
929
+ }
930
+
931
+
932
+ setTimeout(() => {
933
+ // if promise has resolved by now, the reject() is a no-op
934
+ reject("The socket timed out when trying to connect.");
935
+ }, connectTimeoutMs);
936
+ });
937
+ }
938
+
939
+ disconnect(fireDisconnectEvent: boolean = true) {
940
+ if (this.adapter.isOpen()) {
941
+ this.adapter.close();
942
+ }
943
+ if (fireDisconnectEvent) {
944
+ this.ondisconnect(<Event>{});
945
+ }
946
+ }
947
+
948
+ setHeartbeatTimeoutMs(ms : number) {
949
+ this._heartbeatTimeoutMs = ms;
950
+ }
951
+
952
+ getHeartbeatTimeoutMs() : number {
953
+ return this._heartbeatTimeoutMs;
954
+ }
955
+
956
+ ondisconnect(evt: Event) {
957
+ if (this.verbose && window && window.console) {
958
+ console.log(evt);
959
+ }
960
+ }
961
+
962
+ onerror(evt: Event) {
963
+ if (this.verbose && window && window.console) {
964
+ console.log(evt);
965
+ }
966
+ }
967
+
968
+ onmessagetyping(messagetyping: MessageTypingEvent) {
969
+ if (this.verbose && window && window.console) {
970
+ console.log(messagetyping);
971
+ }
972
+ }
973
+
974
+ onmessagereaction(messagereaction: MessageReactionEvent) {
975
+ if (this.verbose && window && window.console) {
976
+ console.log(messagereaction);
977
+ }
978
+ }
979
+
980
+ onmessagedeleted(messagedeleted: MessageDeletedEvent) {
981
+ if (this.verbose && window && window.console) {
982
+ console.log(messagedeleted);
983
+ }
984
+ }
985
+
986
+ onchannelmessage(channelMessage: ChannelMessageEvent) {
987
+ if (this.verbose && window && window.console) {
988
+ console.log(channelMessage);
989
+ }
990
+ }
991
+
992
+ onchannelpresence(channelPresence: ChannelPresenceEvent) {
993
+ if (this.verbose && window && window.console) {
994
+ console.log(channelPresence);
995
+ }
996
+ }
997
+
998
+ onnotification(notification: Notification) {
999
+ if (this.verbose && window && window.console) {
1000
+ console.log(notification);
1001
+ }
1002
+ }
1003
+
1004
+ onparty(party : Party) {
1005
+ if (this.verbose && window && window.console) {
1006
+ console.log(party);
1007
+ }
1008
+ }
1009
+
1010
+ onpartyclose(close: PartyClose) {
1011
+ if (this.verbose && window && window.console) {
1012
+ console.log("Party closed: " + close);
1013
+ }
1014
+ }
1015
+
1016
+ onpartyjoinrequest(partyJoinRequest : PartyJoinRequest) {
1017
+ if (this.verbose && window && window.console) {
1018
+ console.log(partyJoinRequest);
1019
+ }
1020
+ }
1021
+
1022
+ onpartydata(partyData: PartyData) {
1023
+ if (this.verbose && window && window.console) {
1024
+ console.log(partyData);
1025
+ }
1026
+ }
1027
+
1028
+ onpartyleader(partyLeader: PartyLeader) {
1029
+ if (this.verbose && window && window.console) {
1030
+ console.log(partyLeader);
1031
+ }
1032
+ }
1033
+
1034
+ onpartymatchmakerticket(partyMatched: PartyMatchmakerTicket) {
1035
+ if (this.verbose && window && window.console) {
1036
+ console.log(partyMatched);
1037
+ }
1038
+ }
1039
+
1040
+
1041
+ onpartypresence(partyPresence: PartyPresenceEvent) {
1042
+ if (this.verbose && window && window.console) {
1043
+ console.log(partyPresence);
1044
+ }
1045
+ }
1046
+
1047
+ onstatuspresence(statusPresence: StatusPresenceEvent) {
1048
+ if (this.verbose && window && window.console) {
1049
+ console.log(statusPresence);
1050
+ }
1051
+ }
1052
+
1053
+ onvoicejoined(voiceParticipant: VoiceJoinedEvent) {
1054
+ if (this.verbose && window && window.console) {
1055
+ console.log(voiceParticipant);
1056
+ }
1057
+ }
1058
+
1059
+ onvoiceleaved(voiceParticipant: VoiceLeavedEvent) {
1060
+ if (this.verbose && window && window.console) {
1061
+ console.log(voiceParticipant);
1062
+ }
1063
+ }
1064
+
1065
+ onstreampresence(streamPresence: StreamPresenceEvent) {
1066
+ if (this.verbose && window && window.console) {
1067
+ console.log(streamPresence);
1068
+ }
1069
+ }
1070
+
1071
+ onstreamdata(streamData: StreamData) {
1072
+ if (this.verbose && window && window.console) {
1073
+ console.log(streamData);
1074
+ }
1075
+ }
1076
+
1077
+ onheartbeattimeout() {
1078
+ if (this.verbose && window && window.console) {
1079
+ console.log("Heartbeat timeout.");
1080
+ }
1081
+ }
1082
+
1083
+ send(message: ChannelJoin | ChannelLeave | ChannelMessageSend | ChannelMessageUpdate |
1084
+ ChannelMessageRemove | MessageTypingEvent | LastSeenMessageEvent | PartyAccept | PartyClose | PartyCreate | PartyDataSend | PartyJoin |
1085
+ PartyJoinRequestList | PartyLeave | PartyMatchmakerAdd | PartyMatchmakerRemove | PartyPromote |
1086
+ PartyRemove | Rpc | StatusFollow | StatusUnfollow | StatusUpdate | Ping, sendTimeout = DefaultSocket.DefaultSendTimeoutMs): Promise<any> {
1087
+ const untypedMessage = message as any;
1088
+
1089
+ return new Promise<void>((resolve, reject) => {
1090
+ if (!this.adapter.isOpen()) {
1091
+ reject("Socket connection has not been established yet.");
1092
+ }
1093
+ else {
1094
+ if (untypedMessage.party_data_send) {
1095
+ this.adapter.send(untypedMessage);
1096
+ resolve();
1097
+ }
1098
+ else {
1099
+
1100
+ if (untypedMessage.channel_message_send) {
1101
+ untypedMessage.channel_message_send.content = JSON.stringify(untypedMessage.channel_message_send.content);
1102
+ } else if (untypedMessage.channel_message_update) {
1103
+ untypedMessage.channel_message_update.content = JSON.stringify(untypedMessage.channel_message_update.content);
1104
+ }
1105
+
1106
+ const cid = this.generatecid();
1107
+ this.cIds[cid] = {resolve, reject};
1108
+ setTimeout(() => {
1109
+ reject("The socket timed out while waiting for a response.")
1110
+ }, sendTimeout);
1111
+
1112
+ /** Add id for promise executor. */
1113
+ untypedMessage.cid = cid;
1114
+ this.adapter.send(untypedMessage);
1115
+ }
1116
+ }
1117
+
1118
+ if (this.verbose && window && window.console) {
1119
+ const loggedMessage = { ...untypedMessage };
1120
+
1121
+ if (loggedMessage.match_data_send && loggedMessage.match_data_send.data) {
1122
+ loggedMessage.match_data_send.data = decode(loggedMessage.match_data_send.data);
1123
+ } else if (loggedMessage.party_data_send && loggedMessage.party_data_send.data) {
1124
+ loggedMessage.party_data_send.data = decode(loggedMessage.party_data_send.data);
1125
+ }
1126
+
1127
+ console.log("Sent message: %o", JSON.stringify(loggedMessage));
1128
+ }
1129
+ });
1130
+ }
1131
+
1132
+ acceptPartyMember(party_id: string, presence: Presence): Promise<void> {
1133
+ return this.send({party_accept: {party_id: party_id, presence: presence}});
1134
+ }
1135
+
1136
+ async closeParty(party_id: string): Promise<void> {
1137
+ return await this.send({party_close: {party_id: party_id}});
1138
+ }
1139
+
1140
+ async createParty(open: boolean, max_size: number): Promise<Party> {
1141
+ const response = await this.send({party_create: {open: open, max_size: max_size}});
1142
+ return response.party;
1143
+ }
1144
+
1145
+ async followUsers(userIds : string[]): Promise<Status> {
1146
+ const response = await this.send({status_follow: {user_ids: userIds}});
1147
+ return response.status;
1148
+ }
1149
+
1150
+ async joinChat(channel_id: string, channel_label: string, mode: number, type: number, persistence: boolean, hidden: boolean): Promise<Channel> {
1151
+
1152
+ const response = await this.send({
1153
+ channel_join: {
1154
+ channel_id: channel_id,
1155
+ channel_label: channel_label,
1156
+ mode: mode,
1157
+ type: type,
1158
+ persistence: persistence,
1159
+ hidden: hidden
1160
+ }
1161
+ }
1162
+ );
1163
+
1164
+ return response.channel;
1165
+ }
1166
+
1167
+ async joinParty(party_id: string): Promise<void> {
1168
+ return await this.send({party_join: {party_id: party_id}});
1169
+ }
1170
+
1171
+ leaveChat(channel_id: string, channel_label: string, mode: number): Promise<void> {
1172
+ return this.send({channel_leave: {channel_id: channel_id, channel_label: channel_label, mode:mode}});
1173
+ }
1174
+
1175
+ leaveMatch(matchId: string): Promise<void> {
1176
+ return this.send({match_leave: {match_id: matchId}});
1177
+ }
1178
+
1179
+ leaveParty(party_id: string): Promise<void> {
1180
+ return this.send({party_leave: {party_id: party_id}});
1181
+ }
1182
+
1183
+ async listPartyJoinRequests(party_id: string): Promise<PartyJoinRequest> {
1184
+ const response = await this.send({party_join_request_list: {party_id: party_id}});
1185
+ return response.party_join_request;
1186
+ }
1187
+
1188
+ async promotePartyMember(party_id: string, party_member: Presence): Promise<PartyLeader> {
1189
+ const response = await this.send({party_promote: {party_id: party_id, presence: party_member}});
1190
+ return response.party_leader;
1191
+ }
1192
+
1193
+ async removeChatMessage(channel_id: string, channel_label: string, mode: number, message_id: string): Promise<ChannelMessageAck> {
1194
+ const response = await this.send(
1195
+ {
1196
+ channel_message_remove: {
1197
+ channel_id: channel_id,
1198
+ channel_label: channel_label,
1199
+ mode: mode,
1200
+ message_id: message_id
1201
+ }
1202
+ }
1203
+ );
1204
+
1205
+ return response.channel_message_ack;
1206
+ }
1207
+
1208
+ async removePartyMember(party_id: string, member: Presence): Promise<void> {
1209
+ return this.send({party_remove: {
1210
+ party_id: party_id,
1211
+ presence: member
1212
+ }});
1213
+ }
1214
+
1215
+ async rpc(id?: string, payload?: string, http_key?: string) : Promise<ApiRpc> {
1216
+ const response = await this.send(
1217
+ {
1218
+ rpc: {
1219
+ id: id,
1220
+ payload: payload,
1221
+ http_key: http_key,
1222
+ }
1223
+ });
1224
+
1225
+ return response.rpc;
1226
+ }
1227
+
1228
+ sendPartyData(party_id: string, op_code: number, data: string | Uint8Array): Promise<void> {
1229
+ return this.send({party_data_send: {party_id: party_id, op_code: op_code, data: data}})
1230
+ }
1231
+
1232
+ unfollowUsers(user_ids : string[]): Promise<void> {
1233
+ return this.send({status_unfollow: {user_ids: user_ids}});
1234
+ }
1235
+
1236
+ async updateChatMessage(channel_id: string, channel_label: string, mode: number, message_id : string, content: any): Promise<ChannelMessageAck> {
1237
+ const response = await this.send({channel_message_update: {channel_id: channel_id,channel_label:channel_label, message_id: message_id, content: content, mode: mode}});
1238
+ return response.channel_message_ack;
1239
+ }
1240
+
1241
+ updateStatus(status?: string): Promise<void> {
1242
+ return this.send({status_update: {status: status}});
1243
+ }
1244
+
1245
+ async writeChatMessage(clan_id: string, channel_id: string, channel_label: string, mode: number, content: any, mentions?: Array<ApiMessageMention>, attachments?: Array<ApiMessageAttachment>, references?: Array<ApiMessageRef> ): Promise<ChannelMessageAck> {
1246
+ const response = await this.send({channel_message_send: {clan_id: clan_id, channel_id: channel_id, channel_label:channel_label, mode:mode, content: content, mentions: mentions, attachments: attachments, references: references}});
1247
+ return response.channel_message_ack;
1248
+ }
1249
+
1250
+ async writeMessageReaction(id: string, channel_id: string, channel_label: string, mode: number, message_id: string, emoji: string, count: number, message_sender_id: string, action_delete: boolean) : Promise<MessageReactionEvent> {
1251
+ const response = await this.send({message_reaction_event: {id: id, channel_id: channel_id, channel_label: channel_label, mode: mode, message_id: message_id, emoji: emoji, count: count, message_sender_id: message_sender_id, action: action_delete}});
1252
+ return response.message_reaction_event
1253
+ }
1254
+
1255
+ async writeMessageDeleted(channel_id: string, channel_label: string, mode: number, message_id: string) : Promise<MessageDeletedEvent> {
1256
+ const response = await this.send({message_deleted_event: {channel_id: channel_id, channel_label: channel_label, mode: mode, message_id: message_id}});
1257
+ return response.message_deleted_event
1258
+ }
1259
+
1260
+ async writeMessageTyping(channel_id: string, channel_label: string, mode: number) : Promise<MessageTypingEvent> {
1261
+ const response = await this.send({message_typing_event: {channel_id: channel_id, channel_label: channel_label, mode:mode}});
1262
+ return response.message_typing_event
1263
+ }
1264
+
1265
+ async writeLastSeenMessage(channel_id: string, channel_label: string, mode: number, message_id: string, timestamp: string) : Promise<LastSeenMessageEvent> {
1266
+ const response = await this.send({last_seen_message_event: {channel_id: channel_id, channel_label: channel_label, mode: mode, message_id: message_id, timestamp: timestamp}});
1267
+ return response.last_seen_message_event
1268
+ }
1269
+
1270
+ async writeVoiceJoined(id: string, clanId: string, clanName: string, voiceChannelId: string, voiceChannelLabel: string, participant: string, lastScreenshot: string) : Promise<VoiceJoinedEvent> {
1271
+ const response = await this.send({voice_joined_event: {clan_id: clanId, clan_name: clanName, id: id, participant: participant, voice_channel_id: voiceChannelId, voice_channel_label: voiceChannelLabel, last_screenshot: lastScreenshot}});
1272
+ return response.voice_joined_event
1273
+ }
1274
+
1275
+ async writeVoiceLeaved(id: string, clanId: string, voiceChannelId: string, lastParticipant: boolean) : Promise<VoiceLeavedEvent> {
1276
+ const response = await this.send({voice_leaved_event: {id: id, clan_id: clanId, voice_channel_id: voiceChannelId, last_participant: lastParticipant}});
1277
+ return response.voice_leaved_event
1278
+ }
1279
+
1280
+ private async pingPong() : Promise<void> {
1281
+ if (!this.adapter.isOpen()) {
1282
+ return;
1283
+ }
1284
+
1285
+ try {
1286
+ await this.send({ping: {}}, this._heartbeatTimeoutMs);
1287
+ } catch {
1288
+ if (this.adapter.isOpen()) {
1289
+ if (window && window.console) {
1290
+ console.error("Server unreachable from heartbeat.");
1291
+ }
1292
+ this.onheartbeattimeout();
1293
+ this.adapter.close();
1294
+ }
1295
+
1296
+ return;
1297
+ }
1298
+
1299
+ // reuse the timeout as the interval for now.
1300
+ // we can separate them out into separate values if needed later.
1301
+ setTimeout(() => this.pingPong(), this._heartbeatTimeoutMs);
1302
+ }
1303
+ };