@camera.ui/rpc 1.0.1
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/README.md +3 -0
- package/dist/channel.d.ts +106 -0
- package/dist/channel.js +347 -0
- package/dist/channel.js.map +1 -0
- package/dist/chunking.d.ts +77 -0
- package/dist/chunking.js +151 -0
- package/dist/chunking.js.map +1 -0
- package/dist/client.d.ts +245 -0
- package/dist/client.js +1863 -0
- package/dist/client.js.map +1 -0
- package/dist/codec.d.ts +12 -0
- package/dist/codec.js +31 -0
- package/dist/codec.js.map +1 -0
- package/dist/decorators.d.ts +7 -0
- package/dist/decorators.js +192 -0
- package/dist/decorators.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.js +54 -0
- package/dist/errors.js.map +1 -0
- package/dist/handler.d.ts +35 -0
- package/dist/handler.js +399 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/service.d.ts +60 -0
- package/dist/service.js +286 -0
- package/dist/service.js.map +1 -0
- package/dist/types.d.ts +300 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +83 -0
- package/dist/utils.js +273 -0
- package/dist/utils.js.map +1 -0
- package/dist/wrapper.d.ts +1 -0
- package/dist/wrapper.js +2 -0
- package/dist/wrapper.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { RPCClient } from './client.js';
|
|
2
|
+
export interface ChannelMessage {
|
|
3
|
+
type: 'message' | 'close' | 'error';
|
|
4
|
+
data?: any;
|
|
5
|
+
error?: string;
|
|
6
|
+
sender?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Bidirectional communication channel between RPC clients
|
|
10
|
+
*/
|
|
11
|
+
export declare class Channel {
|
|
12
|
+
protected client: RPCClient;
|
|
13
|
+
protected channelId: string;
|
|
14
|
+
protected closed: boolean;
|
|
15
|
+
protected unsubscribe?: () => void;
|
|
16
|
+
protected initialized: boolean;
|
|
17
|
+
private handlers;
|
|
18
|
+
private closeHandlers;
|
|
19
|
+
private errorHandlers;
|
|
20
|
+
private subscriptions;
|
|
21
|
+
/**
|
|
22
|
+
* Check if channel is closed
|
|
23
|
+
*/
|
|
24
|
+
get isClosed(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Get the channel ID
|
|
27
|
+
*/
|
|
28
|
+
get id(): string;
|
|
29
|
+
constructor(client: RPCClient, channelId: string);
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the channel (called by RPCClient)
|
|
32
|
+
*/
|
|
33
|
+
init(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Send data through the channel
|
|
36
|
+
*/
|
|
37
|
+
send<TMessage = any>(data: TMessage): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Send a request and wait for reply
|
|
40
|
+
*/
|
|
41
|
+
request<TRequest = any, TResponse = any>(data: TRequest, timeout?: number): Promise<TResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Setup a request handler for this channel
|
|
44
|
+
*/
|
|
45
|
+
onRequest<TRequest = any, TResponse = any>(handler: (data: TRequest) => Promise<TResponse> | TResponse): Promise<() => void>;
|
|
46
|
+
/**
|
|
47
|
+
* Listen for messages
|
|
48
|
+
*/
|
|
49
|
+
on<TEvent = any>(event: 'message', handler: (data: TEvent) => void): void;
|
|
50
|
+
on(event: 'close', handler: () => void): void;
|
|
51
|
+
on(event: 'error', handler: (error: Error) => void): void;
|
|
52
|
+
/**
|
|
53
|
+
* Remove event listener
|
|
54
|
+
*/
|
|
55
|
+
off<TEvent = any>(event: 'message', handler: (data: TEvent) => void): void;
|
|
56
|
+
off(event: 'close', handler: () => void): void;
|
|
57
|
+
off(event: 'error', handler: (error: Error) => void): void;
|
|
58
|
+
/**
|
|
59
|
+
* Close the channel gracefully
|
|
60
|
+
*/
|
|
61
|
+
close(): Promise<void>;
|
|
62
|
+
private handlerChain;
|
|
63
|
+
private runHandler;
|
|
64
|
+
protected emit(event: string, data?: any): void;
|
|
65
|
+
protected handleClose(): void;
|
|
66
|
+
protected handleError(error: Error): void;
|
|
67
|
+
protected cleanup(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Private channel for 1:1 communication between two specific clients
|
|
71
|
+
*/
|
|
72
|
+
export declare class PrivateChannel extends Channel {
|
|
73
|
+
private targetClientId;
|
|
74
|
+
private readonly clientId;
|
|
75
|
+
private remoteClientId?;
|
|
76
|
+
/**
|
|
77
|
+
* Get the remote client ID (if connected)
|
|
78
|
+
*/
|
|
79
|
+
get remoteId(): string | undefined;
|
|
80
|
+
constructor(client: RPCClient, channelId: string, targetClientId: string);
|
|
81
|
+
/**
|
|
82
|
+
* Initialize private channel with handshake
|
|
83
|
+
*/
|
|
84
|
+
init(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Send data through the private channel
|
|
87
|
+
*/
|
|
88
|
+
send<TMessage = any>(data: TMessage): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Send a request and wait for reply using native NATS request/reply
|
|
91
|
+
*/
|
|
92
|
+
request<TRequest = any, TResponse = any>(data: TRequest, timeout?: number): Promise<TResponse>;
|
|
93
|
+
/**
|
|
94
|
+
* Setup a request handler for this private channel
|
|
95
|
+
*/
|
|
96
|
+
onRequest<TRequest = any, TResponse = any>(handler: (data: TRequest) => Promise<TResponse> | TResponse): Promise<() => void>;
|
|
97
|
+
/**
|
|
98
|
+
* Close the private channel gracefully
|
|
99
|
+
*/
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Check if channel is connected to a specific client
|
|
103
|
+
*/
|
|
104
|
+
isConnectedTo(clientId: string): boolean;
|
|
105
|
+
private sendRaw;
|
|
106
|
+
}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { isPromise } from './utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Bidirectional communication channel between RPC clients
|
|
4
|
+
*/
|
|
5
|
+
export class Channel {
|
|
6
|
+
client;
|
|
7
|
+
channelId;
|
|
8
|
+
closed = false;
|
|
9
|
+
unsubscribe;
|
|
10
|
+
initialized = false;
|
|
11
|
+
// Return type is `void` (consumer-void) so handlers that incidentally
|
|
12
|
+
// return a value type-check. Runtime uses isPromise() on the actual
|
|
13
|
+
// returned value to detect async handlers and chain them.
|
|
14
|
+
handlers = new Map();
|
|
15
|
+
closeHandlers = new Set();
|
|
16
|
+
errorHandlers = new Set();
|
|
17
|
+
subscriptions = [];
|
|
18
|
+
/**
|
|
19
|
+
* Check if channel is closed
|
|
20
|
+
*/
|
|
21
|
+
get isClosed() {
|
|
22
|
+
return this.closed;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the channel ID
|
|
26
|
+
*/
|
|
27
|
+
get id() {
|
|
28
|
+
return this.channelId;
|
|
29
|
+
}
|
|
30
|
+
constructor(client, channelId) {
|
|
31
|
+
this.client = client;
|
|
32
|
+
this.channelId = channelId;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the channel (called by RPCClient)
|
|
36
|
+
*/
|
|
37
|
+
async init() {
|
|
38
|
+
if (this.initialized) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.initialized = true;
|
|
42
|
+
const subject = `channel.${this.channelId}`;
|
|
43
|
+
this.unsubscribe = await this.client.subscribe(subject, async (msg) => {
|
|
44
|
+
switch (msg.type) {
|
|
45
|
+
case 'message':
|
|
46
|
+
this.emit('message', msg.data);
|
|
47
|
+
break;
|
|
48
|
+
case 'close':
|
|
49
|
+
this.handleClose();
|
|
50
|
+
break;
|
|
51
|
+
case 'error':
|
|
52
|
+
this.handleError(new Error(msg.error ?? 'Channel error'));
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Send data through the channel
|
|
59
|
+
*/
|
|
60
|
+
async send(data) {
|
|
61
|
+
if (this.closed) {
|
|
62
|
+
throw new Error('Channel is closed');
|
|
63
|
+
}
|
|
64
|
+
const msg = {
|
|
65
|
+
type: 'message',
|
|
66
|
+
data,
|
|
67
|
+
};
|
|
68
|
+
await this.client.publish(`channel.${this.channelId}`, msg);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Send a request and wait for reply
|
|
72
|
+
*/
|
|
73
|
+
async request(data, timeout = 5000) {
|
|
74
|
+
if (this.closed) {
|
|
75
|
+
throw new Error('Channel is closed');
|
|
76
|
+
}
|
|
77
|
+
const subject = `channel.${this.channelId}.request`;
|
|
78
|
+
return this.client.request(subject, data, { timeout });
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Setup a request handler for this channel
|
|
82
|
+
*/
|
|
83
|
+
async onRequest(handler) {
|
|
84
|
+
const subject = `channel.${this.channelId}.request`;
|
|
85
|
+
const unsubscribe = this.client.onRequest(subject, handler);
|
|
86
|
+
this.subscriptions.push(unsubscribe);
|
|
87
|
+
return unsubscribe;
|
|
88
|
+
}
|
|
89
|
+
on(event, handler) {
|
|
90
|
+
if (event === 'close') {
|
|
91
|
+
this.closeHandlers.add(handler);
|
|
92
|
+
}
|
|
93
|
+
else if (event === 'error') {
|
|
94
|
+
this.errorHandlers.add(handler);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
if (!this.handlers.has(event)) {
|
|
98
|
+
this.handlers.set(event, new Set());
|
|
99
|
+
}
|
|
100
|
+
this.handlers.get(event).add(handler);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
off(event, handler) {
|
|
104
|
+
if (event === 'close') {
|
|
105
|
+
this.closeHandlers.delete(handler);
|
|
106
|
+
}
|
|
107
|
+
else if (event === 'error') {
|
|
108
|
+
this.errorHandlers.delete(handler);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.handlers.get(event)?.delete(handler);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Close the channel gracefully
|
|
116
|
+
*/
|
|
117
|
+
async close() {
|
|
118
|
+
if (this.closed)
|
|
119
|
+
return;
|
|
120
|
+
this.closed = true;
|
|
121
|
+
// Try to notify other side
|
|
122
|
+
try {
|
|
123
|
+
const msg = { type: 'close' };
|
|
124
|
+
await this.client.publish(`channel.${this.channelId}`, msg);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Ignore publish errors during close
|
|
128
|
+
}
|
|
129
|
+
// Cleanup
|
|
130
|
+
await this.cleanup();
|
|
131
|
+
}
|
|
132
|
+
// Per-channel promise chain. Async handlers for message / close / error
|
|
133
|
+
// are serialized via this chain so dispatch stays ordered — matches
|
|
134
|
+
// Python's channel.py:_emit/_handle_close/_handle_error behavior.
|
|
135
|
+
// Sync handlers stay fire-and-forget (not chained, no overhead).
|
|
136
|
+
handlerChain = Promise.resolve();
|
|
137
|
+
runHandler(handler, arg, label) {
|
|
138
|
+
let result;
|
|
139
|
+
try {
|
|
140
|
+
result = handler(arg);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error(`Error in ${label}:`, error);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (isPromise(result)) {
|
|
147
|
+
const pending = result;
|
|
148
|
+
this.handlerChain = this.handlerChain.then(() => pending).catch((error) => console.error(`Error in ${label}:`, error));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
emit(event, data) {
|
|
152
|
+
const handlers = this.handlers.get(event);
|
|
153
|
+
if (!handlers)
|
|
154
|
+
return;
|
|
155
|
+
for (const handler of handlers) {
|
|
156
|
+
this.runHandler(handler, data, 'channel handler');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
handleClose() {
|
|
160
|
+
if (this.closed)
|
|
161
|
+
return;
|
|
162
|
+
this.closed = true;
|
|
163
|
+
for (const handler of this.closeHandlers) {
|
|
164
|
+
this.runHandler(() => handler(), undefined, 'close handler');
|
|
165
|
+
}
|
|
166
|
+
this.cleanup().catch(console.error);
|
|
167
|
+
}
|
|
168
|
+
handleError(error) {
|
|
169
|
+
for (const handler of this.errorHandlers) {
|
|
170
|
+
this.runHandler(handler, error, 'error handler');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async cleanup() {
|
|
174
|
+
// Clear all handlers
|
|
175
|
+
this.handlers.clear();
|
|
176
|
+
this.closeHandlers.clear();
|
|
177
|
+
this.errorHandlers.clear();
|
|
178
|
+
// Clear subscriptions
|
|
179
|
+
await Promise.allSettled(this.subscriptions.map((unsub) => unsub));
|
|
180
|
+
// Unsubscribe from NATS
|
|
181
|
+
if (this.unsubscribe) {
|
|
182
|
+
try {
|
|
183
|
+
this.unsubscribe();
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// Ignore unsubscribe errors
|
|
187
|
+
}
|
|
188
|
+
this.unsubscribe = undefined;
|
|
189
|
+
}
|
|
190
|
+
// Disconnect isolated client if present
|
|
191
|
+
const isolatedClient = this._isolatedClient;
|
|
192
|
+
if (isolatedClient) {
|
|
193
|
+
try {
|
|
194
|
+
await isolatedClient.disconnect();
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Ignore disconnect errors
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Private channel for 1:1 communication between two specific clients
|
|
204
|
+
*/
|
|
205
|
+
export class PrivateChannel extends Channel {
|
|
206
|
+
targetClientId;
|
|
207
|
+
clientId;
|
|
208
|
+
remoteClientId;
|
|
209
|
+
/**
|
|
210
|
+
* Get the remote client ID (if connected)
|
|
211
|
+
*/
|
|
212
|
+
get remoteId() {
|
|
213
|
+
return this.remoteClientId;
|
|
214
|
+
}
|
|
215
|
+
constructor(client, channelId, targetClientId) {
|
|
216
|
+
super(client, channelId);
|
|
217
|
+
this.targetClientId = targetClientId;
|
|
218
|
+
// Use the original client name, not the isolated connection name
|
|
219
|
+
// When using isolated connections, the name includes suffixes like '-channel-secret-chat'
|
|
220
|
+
// We need to extract the original name to maintain consistent identity
|
|
221
|
+
const fullName = client.options.name ?? `client-${Date.now()}`;
|
|
222
|
+
// Extract base name by removing any suffixes added for isolated connections
|
|
223
|
+
this.clientId = fullName.replace(/-(channel|private)-.*$/, '');
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Initialize private channel with handshake
|
|
227
|
+
*/
|
|
228
|
+
async init() {
|
|
229
|
+
if (this.initialized) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.initialized = true;
|
|
233
|
+
// Use a unique subject that includes channelId and both client IDs for true privacy
|
|
234
|
+
const sortedIds = [this.clientId, this.targetClientId].sort();
|
|
235
|
+
const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}`;
|
|
236
|
+
this.unsubscribe = await this.client.subscribe(subject, async (msg) => {
|
|
237
|
+
// Filter messages: only process if it's for us
|
|
238
|
+
if (msg.sender === this.clientId) {
|
|
239
|
+
// Skip our own messages
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (msg.sender !== this.targetClientId) {
|
|
243
|
+
// Only accept messages from the target client
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!this.remoteClientId && msg.sender) {
|
|
247
|
+
// First message establishes the connection
|
|
248
|
+
this.remoteClientId = msg.sender;
|
|
249
|
+
}
|
|
250
|
+
if (this.remoteClientId && msg.sender !== this.remoteClientId) {
|
|
251
|
+
// After connection established, only accept from connected client
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
switch (msg.type) {
|
|
255
|
+
case 'message':
|
|
256
|
+
// Filter out handshake messages
|
|
257
|
+
if (msg.data && typeof msg.data === 'object' && '__handshake' in msg.data) {
|
|
258
|
+
// Handshake received, connection established
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
this.emit('message', msg.data);
|
|
262
|
+
break;
|
|
263
|
+
case 'close':
|
|
264
|
+
this.handleClose();
|
|
265
|
+
break;
|
|
266
|
+
case 'error':
|
|
267
|
+
this.handleError(new Error(msg.error ?? 'Channel error'));
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
// Send initial handshake
|
|
272
|
+
try {
|
|
273
|
+
await this.sendRaw({
|
|
274
|
+
type: 'message',
|
|
275
|
+
data: { __handshake: true },
|
|
276
|
+
sender: this.clientId,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Ignore handshake errors - connection might still work
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Send data through the private channel
|
|
285
|
+
*/
|
|
286
|
+
async send(data) {
|
|
287
|
+
if (this.closed) {
|
|
288
|
+
throw new Error('Channel is closed');
|
|
289
|
+
}
|
|
290
|
+
await this.sendRaw({
|
|
291
|
+
type: 'message',
|
|
292
|
+
data,
|
|
293
|
+
sender: this.clientId,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Send a request and wait for reply using native NATS request/reply
|
|
298
|
+
*/
|
|
299
|
+
async request(data, timeout = 5000) {
|
|
300
|
+
if (this.closed) {
|
|
301
|
+
throw new Error('Channel is closed');
|
|
302
|
+
}
|
|
303
|
+
const sortedIds = [this.clientId, this.targetClientId].sort();
|
|
304
|
+
const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}.request`;
|
|
305
|
+
return this.client.request(subject, data, { timeout });
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Setup a request handler for this private channel
|
|
309
|
+
*/
|
|
310
|
+
async onRequest(handler) {
|
|
311
|
+
const sortedIds = [this.clientId, this.targetClientId].sort();
|
|
312
|
+
const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}.request`;
|
|
313
|
+
return this.client.onRequest(subject, handler);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Close the private channel gracefully
|
|
317
|
+
*/
|
|
318
|
+
async close() {
|
|
319
|
+
if (this.closed)
|
|
320
|
+
return;
|
|
321
|
+
this.closed = true;
|
|
322
|
+
// Try to notify remote client, but don't fail if it errors
|
|
323
|
+
try {
|
|
324
|
+
await this.sendRaw({
|
|
325
|
+
type: 'close',
|
|
326
|
+
sender: this.clientId,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Ignore send errors during close
|
|
331
|
+
}
|
|
332
|
+
await this.cleanup();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Check if channel is connected to a specific client
|
|
336
|
+
*/
|
|
337
|
+
isConnectedTo(clientId) {
|
|
338
|
+
return this.remoteClientId === clientId;
|
|
339
|
+
}
|
|
340
|
+
async sendRaw(msg) {
|
|
341
|
+
// Use the same subject format as in init()
|
|
342
|
+
const sortedIds = [this.clientId, this.targetClientId].sort();
|
|
343
|
+
const subject = `channel.private.${this.channelId}.${sortedIds.join('.')}`;
|
|
344
|
+
await this.client.publish(subject, msg);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message types for chunked transfers
|
|
3
|
+
*/
|
|
4
|
+
export interface ChunkMessage {
|
|
5
|
+
id: string;
|
|
6
|
+
chunkIndex: number;
|
|
7
|
+
data: Uint8Array;
|
|
8
|
+
isLast: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Split data into chunks
|
|
12
|
+
*/
|
|
13
|
+
export declare function createChunks(encoded: Uint8Array, chunkId: string, maxChunkSize: number): Generator<ChunkMessage>;
|
|
14
|
+
/**
|
|
15
|
+
* Reassemble chunks back into original data using a pre-allocated buffer.
|
|
16
|
+
* Chunks are written directly to the buffer - no intermediate Map storage.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ChunkAssembler {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
private buffer;
|
|
21
|
+
private receivedChunks;
|
|
22
|
+
private totalChunks;
|
|
23
|
+
private chunkSize;
|
|
24
|
+
constructor(id: string, totalSize: number, totalChunks: number, chunkSize?: number);
|
|
25
|
+
/**
|
|
26
|
+
* Add a chunk to the assembler.
|
|
27
|
+
* Writes directly to the pre-allocated buffer.
|
|
28
|
+
* @returns true if all chunks are received
|
|
29
|
+
*/
|
|
30
|
+
addChunk(chunk: ChunkMessage): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if all chunks have been received
|
|
33
|
+
*/
|
|
34
|
+
isComplete(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get the reassembled data.
|
|
37
|
+
* Buffer is already complete, just decode - no copy needed.
|
|
38
|
+
*/
|
|
39
|
+
getData<T = any>(): T;
|
|
40
|
+
/**
|
|
41
|
+
* Get progress information
|
|
42
|
+
*/
|
|
43
|
+
getProgress(): {
|
|
44
|
+
received: number;
|
|
45
|
+
total: number;
|
|
46
|
+
percentage: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Manager for handling multiple chunk transfers
|
|
51
|
+
*/
|
|
52
|
+
export declare class ChunkingManager {
|
|
53
|
+
private assemblers;
|
|
54
|
+
private completedCallbacks;
|
|
55
|
+
private errorCallbacks;
|
|
56
|
+
/**
|
|
57
|
+
* Start receiving chunks for a transfer.
|
|
58
|
+
* Pre-allocates buffer for direct chunk writing.
|
|
59
|
+
*/
|
|
60
|
+
startReceiving(id: string, totalChunks: number, onComplete: (data: any) => void, onError: (error: Error) => void, totalSize: number, chunkSize?: number): void;
|
|
61
|
+
/**
|
|
62
|
+
* Process an incoming chunk
|
|
63
|
+
*/
|
|
64
|
+
processChunk(chunk: ChunkMessage): void;
|
|
65
|
+
/**
|
|
66
|
+
* Cancel a transfer
|
|
67
|
+
*/
|
|
68
|
+
cancel(id: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get progress for a transfer
|
|
71
|
+
*/
|
|
72
|
+
getProgress(id: string): {
|
|
73
|
+
received: number;
|
|
74
|
+
total: number;
|
|
75
|
+
percentage: number;
|
|
76
|
+
} | null;
|
|
77
|
+
}
|