@softtynet/zca-js 2.3.4 → 2.3.5

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.
Files changed (123) hide show
  1. package/README.md +47 -11
  2. package/dist/apis/call/addUserGroupCall.d.ts +11 -0
  3. package/dist/apis/call/addUserGroupCall.js +48 -0
  4. package/dist/apis/call/answerAckVoiceCall.d.ts +5 -0
  5. package/dist/apis/call/answerAckVoiceCall.js +38 -0
  6. package/dist/apis/call/answerGroupCall.d.ts +10 -0
  7. package/dist/apis/call/answerGroupCall.js +45 -0
  8. package/dist/apis/call/answerVoiceCall.d.ts +11 -0
  9. package/dist/apis/call/answerVoiceCall.js +50 -0
  10. package/dist/apis/call/broadcastGroupCallState.d.ts +10 -0
  11. package/dist/apis/call/broadcastGroupCallState.js +45 -0
  12. package/dist/apis/call/cancelGroupCall.d.ts +10 -0
  13. package/dist/apis/call/cancelGroupCall.js +45 -0
  14. package/dist/apis/call/cancelVoiceCall.d.ts +1 -1
  15. package/dist/apis/call/cancelVoiceCall.js +5 -1
  16. package/dist/apis/call/createController.d.ts +7 -0
  17. package/dist/apis/call/createController.js +9 -0
  18. package/dist/apis/call/createRtcSession.d.ts +8 -0
  19. package/dist/apis/call/createRtcSession.js +10 -0
  20. package/dist/apis/call/endGroupCall.d.ts +10 -0
  21. package/dist/apis/call/endGroupCall.js +45 -0
  22. package/dist/apis/call/finishGroupCall.d.ts +12 -0
  23. package/dist/apis/call/finishGroupCall.js +47 -0
  24. package/dist/apis/call/getGroupCallState.d.ts +3 -0
  25. package/dist/apis/call/getGroupCallState.js +38 -0
  26. package/dist/apis/call/holdVoiceCall.d.ts +5 -0
  27. package/dist/apis/call/holdVoiceCall.js +34 -0
  28. package/dist/apis/call/joinGroupCall.d.ts +11 -0
  29. package/dist/apis/call/joinGroupCall.js +46 -0
  30. package/dist/apis/call/logEndVoiceCall.d.ts +8 -0
  31. package/dist/apis/call/logEndVoiceCall.js +46 -0
  32. package/dist/apis/call/notifyGroupCall.d.ts +9 -0
  33. package/dist/apis/call/notifyGroupCall.js +44 -0
  34. package/dist/apis/call/pingGroupCall.d.ts +10 -0
  35. package/dist/apis/call/pingGroupCall.js +45 -0
  36. package/dist/apis/call/requestAudioToVideoCall.d.ts +5 -0
  37. package/dist/apis/call/requestAudioToVideoCall.js +37 -0
  38. package/dist/apis/call/requestGroupCall.d.ts +9 -0
  39. package/dist/apis/call/requestGroupCall.js +46 -0
  40. package/dist/apis/call/requestShareScreenCall.d.ts +5 -0
  41. package/dist/apis/call/requestShareScreenCall.js +37 -0
  42. package/dist/apis/call/requestVoiceCall.d.ts +10 -0
  43. package/dist/apis/call/requestVoiceCall.js +47 -0
  44. package/dist/apis/call/ringRingGroupCall.d.ts +10 -0
  45. package/dist/apis/call/ringRingGroupCall.js +45 -0
  46. package/dist/apis/call/ringRingVoiceCall.d.ts +5 -0
  47. package/dist/apis/call/ringRingVoiceCall.js +38 -0
  48. package/dist/apis/call/sendRequestGroupCall.d.ts +11 -0
  49. package/dist/apis/call/sendRequestGroupCall.js +48 -0
  50. package/dist/apis/call/sendRequestVoiceCall.d.ts +11 -0
  51. package/dist/apis/call/sendRequestVoiceCall.js +51 -0
  52. package/dist/apis/call/sendVoiceCall.d.ts +8 -1
  53. package/dist/apis/call/sendVoiceCall.js +10 -8
  54. package/dist/apis/call/shareScreenGroupCall.d.ts +10 -0
  55. package/dist/apis/call/shareScreenGroupCall.js +45 -0
  56. package/dist/apis/call/unholdVoiceCall.d.ts +5 -0
  57. package/dist/apis/call/unholdVoiceCall.js +34 -0
  58. package/dist/apis/call/updateCallMediaState.d.ts +7 -0
  59. package/dist/apis/call/updateCallMediaState.js +61 -0
  60. package/dist/apis.d.ts +81 -0
  61. package/dist/apis.js +135 -0
  62. package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
  63. package/dist/call-engine/ZRTPPacketCodec.js +506 -0
  64. package/dist/call-engine/ZaloCallController.d.ts +134 -0
  65. package/dist/call-engine/ZaloCallController.js +638 -0
  66. package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
  67. package/dist/call-engine/ZaloCallTransport.js +233 -0
  68. package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
  69. package/dist/call-engine/ZaloRtcSession.js +2931 -0
  70. package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
  71. package/dist/call-engine/ZaloSrtpSession.js +278 -0
  72. package/dist/call-engine/index.d.ts +18 -0
  73. package/dist/call-engine/index.js +24 -0
  74. package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
  75. package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
  76. package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
  77. package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
  78. package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
  79. package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
  80. package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
  81. package/dist/cjs/apis/call/createController.cjs +14 -0
  82. package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
  83. package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
  84. package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
  85. package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
  86. package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
  87. package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
  88. package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
  89. package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
  90. package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
  91. package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
  92. package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
  93. package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
  94. package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
  95. package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
  96. package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
  97. package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
  98. package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
  99. package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
  100. package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
  101. package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
  102. package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
  103. package/dist/cjs/apis.cjs +135 -0
  104. package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
  105. package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
  106. package/dist/cjs/call-engine/ZaloCallTransport.cjs +239 -0
  107. package/dist/cjs/call-engine/ZaloRtcSession.cjs +2937 -0
  108. package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
  109. package/dist/cjs/constants/protocol.cjs +1 -1
  110. package/dist/cjs/index.cjs +61 -11
  111. package/dist/cjs/models/CallEvent.cjs +95 -1
  112. package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
  113. package/dist/cjs/realtime/listener.cjs +19 -0
  114. package/dist/constants/protocol.d.ts +1 -1
  115. package/dist/constants/protocol.js +1 -1
  116. package/dist/index.d.ts +32 -4
  117. package/dist/index.js +2 -0
  118. package/dist/models/CallEvent.d.ts +15 -0
  119. package/dist/models/CallEvent.js +95 -1
  120. package/dist/realtime/handlers/control.handler.js +17 -3
  121. package/dist/realtime/listener.d.ts +5 -0
  122. package/dist/realtime/listener.js +19 -0
  123. package/package.json +2 -1
@@ -0,0 +1,239 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('node:crypto');
4
+ var EventEmitter = require('node:events');
5
+ var fs = require('node:fs');
6
+ var net = require('node:net');
7
+ var node_buffer = require('node:buffer');
8
+
9
+ /**
10
+ * Khoá AES-128-CBC tĩnh chuẩn trong module `4KIH` của Zalo PC và binary `ZaloCall` (`yjAF9oqMWl6XfXYJn9mA7w==`).
11
+ */
12
+ const DEFAULT_ZALOCALL_IPC_KEY_BASE64 = "yjAF9oqMWl6XfXYJn9mA7w==";
13
+ const MAX_IPC_CHUNK_LENGTH = 4000;
14
+ /**
15
+ * Tầng giao thức IPC双kênh (`receiveSocketPath` & `sendSocketPath`) mã hoá AES-128-CBC (Hex + `$` framing + 4000-char chunking)
16
+ * khớp 100% với module `3Zc2` / `4KIH` của Zalo PC và `zrtc_call::ZIpcClientMac` (`0x10012eb50`).
17
+ */
18
+ class ZaloCallTransport extends EventEmitter {
19
+ socketId;
20
+ sendSocketPath;
21
+ receiveSocketPath;
22
+ keyBase64;
23
+ keyBuffer;
24
+ ivBuffer;
25
+ ackTimeoutMs;
26
+ sendServer = null;
27
+ receiveServer = null;
28
+ sendClient = null;
29
+ receiveClient = null;
30
+ receiveBuffer = "";
31
+ outgoingQueue = [];
32
+ waitingForAck = false;
33
+ ackTimer = null;
34
+ emittedConnected = false;
35
+ constructor(options = {}) {
36
+ super();
37
+ this.socketId = options.socketId ?? `${process.pid}_${Math.floor(Math.random() * 10000)}`;
38
+ this.keyBase64 = options.keyBase64 ?? DEFAULT_ZALOCALL_IPC_KEY_BASE64;
39
+ this.ackTimeoutMs = options.ackTimeoutMs ?? 250;
40
+ const decodedKey = node_buffer.Buffer.from(this.keyBase64, "base64");
41
+ this.keyBuffer = node_buffer.Buffer.alloc(16, 0);
42
+ decodedKey.copy(this.keyBuffer, 0, 0, Math.min(16, decodedKey.length));
43
+ this.ivBuffer = node_buffer.Buffer.alloc(16, 0);
44
+ if (process.platform === "win32") {
45
+ this.receiveSocketPath = `\\\\.\\pipe\\receive_socket_${this.socketId}`;
46
+ this.sendSocketPath = `\\\\.\\pipe\\send_socket_${this.socketId}`;
47
+ }
48
+ else {
49
+ this.receiveSocketPath = `/tmp/zcall_r_${this.socketId}`;
50
+ this.sendSocketPath = `/tmp/zcall_s_${this.socketId}`;
51
+ }
52
+ }
53
+ /**
54
+ * Mã hoá đối tượng JSON thành mảng các mảnh Hex (tối đa 4000 ký tự/mảnh, mảnh cuối kết thúc bằng `$`).
55
+ */
56
+ encryptFrames(payload) {
57
+ const json = typeof payload === "string" ? payload : JSON.stringify(payload);
58
+ const cipher = crypto.createCipheriv("aes-128-cbc", this.keyBuffer, this.ivBuffer);
59
+ const encryptedHex = cipher.update(json, "utf-8", "hex") + cipher.final("hex");
60
+ const chunks = [];
61
+ let offset = 0;
62
+ while (offset < encryptedHex.length) {
63
+ chunks.push(encryptedHex.slice(offset, offset + MAX_IPC_CHUNK_LENGTH));
64
+ offset += MAX_IPC_CHUNK_LENGTH;
65
+ }
66
+ if (chunks.length === 0) {
67
+ chunks.push("$");
68
+ }
69
+ else {
70
+ chunks[chunks.length - 1] += "$";
71
+ }
72
+ return chunks;
73
+ }
74
+ /**
75
+ * Giải mã một khung chuỗi Hex (không bao gồm ký tự `$`) thành đối tượng JSON.
76
+ */
77
+ decryptFrame(encryptedHex) {
78
+ const clean = encryptedHex.endsWith("$") ? encryptedHex.slice(0, -1) : encryptedHex;
79
+ const decipher = crypto.createDecipheriv("aes-128-cbc", this.keyBuffer, this.ivBuffer);
80
+ const plain = decipher.update(clean, "hex", "utf-8") + decipher.final("utf-8");
81
+ return JSON.parse(plain);
82
+ }
83
+ /**
84
+ * Khởi tạo 2 máy chủ IPC (`receiveSocketPath` và `sendSocketPath`) sẵn sàng đón tiến trình `ZaloCall`.
85
+ */
86
+ async start() {
87
+ this.unlinkUnixSockets();
88
+ this.emittedConnected = false;
89
+ this.sendServer = net.createServer((socket) => {
90
+ this.sendClient = socket;
91
+ socket.on("data", (chunk) => {
92
+ const text = chunk.toString("utf-8");
93
+ if (text.includes("ack")) {
94
+ this.emit("raw_ack");
95
+ this.onAckReceived();
96
+ }
97
+ });
98
+ socket.on("error", (err) => this.emit("error", err));
99
+ this.checkBothConnected();
100
+ this.flushOutgoingQueue();
101
+ });
102
+ this.receiveServer = net.createServer((socket) => {
103
+ this.receiveClient = socket;
104
+ socket.on("data", (chunk) => {
105
+ this.handleReceiveChunk(chunk.toString("utf-8"));
106
+ });
107
+ socket.on("error", (err) => this.emit("error", err));
108
+ this.checkBothConnected();
109
+ });
110
+ await Promise.all([
111
+ new Promise((resolve, reject) => {
112
+ this.receiveServer.once("error", reject);
113
+ this.receiveServer.listen(this.receiveSocketPath, () => resolve());
114
+ }),
115
+ new Promise((resolve, reject) => {
116
+ this.sendServer.once("error", reject);
117
+ this.sendServer.listen(this.sendSocketPath, () => resolve());
118
+ }),
119
+ ]);
120
+ this.emit("ready");
121
+ }
122
+ /**
123
+ * Gửi một thông điệp IPC đã mã hoá AES-128-CBC xuống tiến trình `ZaloCall` (qua hàng đợi `"ack"`).
124
+ */
125
+ send(message) {
126
+ const frames = this.encryptFrames(message);
127
+ this.outgoingQueue.push(...frames);
128
+ this.flushOutgoingQueue();
129
+ }
130
+ isConnected() {
131
+ return Boolean(this.sendClient &&
132
+ !this.sendClient.destroyed &&
133
+ this.receiveClient &&
134
+ !this.receiveClient.destroyed);
135
+ }
136
+ /**
137
+ * Đóng toàn bộ kết nối và dọn dẹp file socket trên đĩa.
138
+ */
139
+ async close() {
140
+ if (this.ackTimer) {
141
+ clearTimeout(this.ackTimer);
142
+ this.ackTimer = null;
143
+ }
144
+ this.outgoingQueue = [];
145
+ this.waitingForAck = false;
146
+ this.emittedConnected = false;
147
+ if (this.sendClient) {
148
+ this.sendClient.destroy();
149
+ this.sendClient = null;
150
+ }
151
+ if (this.receiveClient) {
152
+ this.receiveClient.destroy();
153
+ this.receiveClient = null;
154
+ }
155
+ await Promise.all([
156
+ new Promise((resolve) => {
157
+ if (this.sendServer)
158
+ this.sendServer.close(() => resolve());
159
+ else
160
+ resolve();
161
+ }),
162
+ new Promise((resolve) => {
163
+ if (this.receiveServer)
164
+ this.receiveServer.close(() => resolve());
165
+ else
166
+ resolve();
167
+ }),
168
+ ]);
169
+ this.sendServer = null;
170
+ this.receiveServer = null;
171
+ this.unlinkUnixSockets();
172
+ this.emit("close");
173
+ }
174
+ checkBothConnected() {
175
+ if (this.isConnected() && !this.emittedConnected) {
176
+ this.emittedConnected = true;
177
+ this.emit("client_connected");
178
+ }
179
+ }
180
+ onAckReceived() {
181
+ if (this.ackTimer) {
182
+ clearTimeout(this.ackTimer);
183
+ this.ackTimer = null;
184
+ }
185
+ this.waitingForAck = false;
186
+ this.flushOutgoingQueue();
187
+ }
188
+ flushOutgoingQueue() {
189
+ if (this.waitingForAck || !this.sendClient || this.sendClient.destroyed) {
190
+ return;
191
+ }
192
+ const nextFrame = this.outgoingQueue.shift();
193
+ if (!nextFrame)
194
+ return;
195
+ this.waitingForAck = true;
196
+ this.sendClient.write(nextFrame, "utf-8");
197
+ this.ackTimer = setTimeout(() => {
198
+ this.waitingForAck = false;
199
+ this.flushOutgoingQueue();
200
+ }, this.ackTimeoutMs);
201
+ if (typeof this.ackTimer.unref === "function") {
202
+ this.ackTimer.unref();
203
+ }
204
+ }
205
+ handleReceiveChunk(chunk) {
206
+ this.receiveBuffer += chunk;
207
+ let dollarIdx = this.receiveBuffer.indexOf("$");
208
+ while (dollarIdx !== -1) {
209
+ const frame = this.receiveBuffer.slice(0, dollarIdx);
210
+ this.receiveBuffer = this.receiveBuffer.slice(dollarIdx + 1);
211
+ if (frame.length > 0) {
212
+ try {
213
+ const parsed = this.decryptFrame(frame);
214
+ this.emit("message", parsed);
215
+ }
216
+ catch (err) {
217
+ this.emit("error", err);
218
+ }
219
+ }
220
+ dollarIdx = this.receiveBuffer.indexOf("$");
221
+ }
222
+ }
223
+ unlinkUnixSockets() {
224
+ if (process.platform === "win32")
225
+ return;
226
+ for (const p of [this.sendSocketPath, this.receiveSocketPath]) {
227
+ try {
228
+ if (fs.existsSync(p))
229
+ fs.unlinkSync(p);
230
+ }
231
+ catch {
232
+ // Ignore unlink errors
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ exports.DEFAULT_ZALOCALL_IPC_KEY_BASE64 = DEFAULT_ZALOCALL_IPC_KEY_BASE64;
239
+ exports.ZaloCallTransport = ZaloCallTransport;