@phystack/hub-client 4.5.19-dev → 4.5.20-dev
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/index.d.ts +22 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +252 -378
- package/dist/index.js.map +1 -1
- package/dist/peripheral-twin.d.ts +34 -0
- package/dist/peripheral-twin.d.ts.map +1 -0
- package/dist/peripheral-twin.js +234 -0
- package/dist/peripheral-twin.js.map +1 -0
- package/dist/services/phyhub-connection.service.d.ts +1 -0
- package/dist/services/phyhub-connection.service.d.ts.map +1 -1
- package/dist/services/phyhub-connection.service.js +17 -0
- package/dist/services/phyhub-connection.service.js.map +1 -1
- package/dist/services/phyhub-direct-connection.service.d.ts +21 -0
- package/dist/services/phyhub-direct-connection.service.d.ts.map +1 -0
- package/dist/services/phyhub-direct-connection.service.js +101 -0
- package/dist/services/phyhub-direct-connection.service.js.map +1 -0
- package/dist/services/webrtc/data-channel-handler.d.ts +45 -0
- package/dist/services/webrtc/data-channel-handler.d.ts.map +1 -0
- package/dist/services/webrtc/data-channel-handler.js +260 -0
- package/dist/services/webrtc/data-channel-handler.js.map +1 -0
- package/dist/services/webrtc/index.d.ts +8 -0
- package/dist/services/webrtc/index.d.ts.map +1 -0
- package/dist/services/webrtc/index.js +18 -0
- package/dist/services/webrtc/index.js.map +1 -0
- package/dist/services/webrtc/media-stream-handler.d.ts +57 -0
- package/dist/services/webrtc/media-stream-handler.d.ts.map +1 -0
- package/dist/services/webrtc/media-stream-handler.js +383 -0
- package/dist/services/webrtc/media-stream-handler.js.map +1 -0
- package/dist/services/webrtc/peer-connection-manager.d.ts +40 -0
- package/dist/services/webrtc/peer-connection-manager.d.ts.map +1 -0
- package/dist/services/webrtc/peer-connection-manager.js +336 -0
- package/dist/services/webrtc/peer-connection-manager.js.map +1 -0
- package/dist/services/webrtc/types.d.ts +134 -0
- package/dist/services/webrtc/types.d.ts.map +1 -0
- package/dist/services/webrtc/types.js +12 -0
- package/dist/services/webrtc/types.js.map +1 -0
- package/dist/services/webrtc/webrtc-globals.d.ts +4 -0
- package/dist/services/webrtc/webrtc-globals.d.ts.map +1 -0
- package/dist/services/webrtc/webrtc-globals.js +72 -0
- package/dist/services/webrtc/webrtc-globals.js.map +1 -0
- package/dist/services/webrtc/webrtc-manager.d.ts +35 -0
- package/dist/services/webrtc/webrtc-manager.d.ts.map +1 -0
- package/dist/services/webrtc/webrtc-manager.js +274 -0
- package/dist/services/webrtc/webrtc-manager.js.map +1 -0
- package/dist/test/communication-comprehensive-test.d.ts +8 -0
- package/dist/test/communication-comprehensive-test.d.ts.map +1 -0
- package/dist/test/communication-comprehensive-test.js +356 -0
- package/dist/test/communication-comprehensive-test.js.map +1 -0
- package/dist/test/webrtc-channel-names-test.d.ts +2 -0
- package/dist/test/webrtc-channel-names-test.d.ts.map +1 -0
- package/dist/test/webrtc-channel-names-test.js +177 -0
- package/dist/test/webrtc-channel-names-test.js.map +1 -0
- package/dist/test/webrtc-comprehensive-test.d.ts +2 -0
- package/dist/test/webrtc-comprehensive-test.d.ts.map +1 -0
- package/dist/test/webrtc-comprehensive-test.js +328 -0
- package/dist/test/webrtc-comprehensive-test.js.map +1 -0
- package/dist/test/webrtc-reconnect-test.d.ts +4 -0
- package/dist/test/webrtc-reconnect-test.d.ts.map +1 -0
- package/dist/test/webrtc-reconnect-test.js +244 -0
- package/dist/test/webrtc-reconnect-test.js.map +1 -0
- package/dist/test/webrtc-test-harness.d.ts +4 -0
- package/dist/test/webrtc-test-harness.d.ts.map +1 -0
- package/dist/test/webrtc-test-harness.js +169 -0
- package/dist/test/webrtc-test-harness.js.map +1 -0
- package/dist/twin-messaging.d.ts +20 -0
- package/dist/twin-messaging.d.ts.map +1 -0
- package/dist/twin-messaging.js +94 -0
- package/dist/twin-messaging.js.map +1 -0
- package/dist/twin-registry.d.ts +9 -0
- package/dist/twin-registry.d.ts.map +1 -0
- package/dist/twin-registry.js +26 -0
- package/dist/twin-registry.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/twin.types.d.ts +62 -14
- package/dist/types/twin.types.d.ts.map +1 -1
- package/dist/types/twin.types.js +8 -1
- package/dist/types/twin.types.js.map +1 -1
- package/docs/webrtc-howto.md +398 -0
- package/docs/webrtc-test.md +330 -0
- package/package.json +3 -3
- package/scripts/webrtc-test.sh +401 -0
- package/src/index.ts +378 -568
- package/src/peripheral-twin.ts +337 -0
- package/src/services/phyhub-connection.service.ts +24 -0
- package/src/services/phyhub-direct-connection.service.ts +159 -0
- package/src/services/webrtc/data-channel-handler.ts +362 -0
- package/src/services/webrtc/index.ts +36 -0
- package/src/services/webrtc/media-stream-handler.ts +536 -0
- package/src/services/webrtc/peer-connection-manager.ts +467 -0
- package/src/services/webrtc/types.ts +273 -0
- package/src/services/webrtc/webrtc-globals.ts +108 -0
- package/src/services/webrtc/webrtc-manager.ts +490 -0
- package/src/test/communication-comprehensive-test.ts +533 -0
- package/src/test/webrtc-channel-names-test.ts +266 -0
- package/src/test/webrtc-comprehensive-test.ts +494 -0
- package/src/test/webrtc-reconnect-test.ts +345 -0
- package/src/test/webrtc-test-harness.ts +254 -0
- package/src/twin-messaging.ts +184 -0
- package/src/twin-registry.ts +39 -0
- package/src/types/index.ts +3 -0
- package/src/types/twin.types.ts +80 -14
- package/dist/services/webrtc/datachannel.d.ts +0 -10
- package/dist/services/webrtc/datachannel.d.ts.map +0 -1
- package/dist/services/webrtc/datachannel.js +0 -290
- package/dist/services/webrtc/datachannel.js.map +0 -1
- package/dist/services/webrtc/mediastream.d.ts +0 -10
- package/dist/services/webrtc/mediastream.d.ts.map +0 -1
- package/dist/services/webrtc/mediastream.js +0 -396
- package/dist/services/webrtc/mediastream.js.map +0 -1
- package/dist/services/webrtc/peer-connection-ice.d.ts +0 -32
- package/dist/services/webrtc/peer-connection-ice.d.ts.map +0 -1
- package/dist/services/webrtc/peer-connection-ice.js +0 -483
- package/dist/services/webrtc/peer-connection-ice.js.map +0 -1
- package/src/services/webrtc/datachannel.ts +0 -421
- package/src/services/webrtc/mediastream.ts +0 -602
- package/src/services/webrtc/peer-connection-ice.ts +0 -689
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
// Initialize WebRTC globals if we're in Node environment
|
|
2
|
-
(async function initializeWebRTCGlobals() {
|
|
3
|
-
// Only run in Node environment
|
|
4
|
-
if (typeof window !== 'undefined') return;
|
|
5
|
-
|
|
6
|
-
try {
|
|
7
|
-
// Dynamically import wrtc
|
|
8
|
-
const wrtc = require('@roamhq/wrtc');
|
|
9
|
-
|
|
10
|
-
// Set all WebRTC globals
|
|
11
|
-
if (typeof global.MediaStream === 'undefined' && wrtc.MediaStream) {
|
|
12
|
-
global.MediaStream = wrtc.MediaStream;
|
|
13
|
-
console.log('Global MediaStream initialized');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (typeof global.RTCDataChannel === 'undefined' && wrtc.RTCDataChannel) {
|
|
17
|
-
global.RTCDataChannel = wrtc.RTCDataChannel;
|
|
18
|
-
console.log('Global RTCDataChannel initialized');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (typeof global.RTCPeerConnection === 'undefined' && wrtc.RTCPeerConnection) {
|
|
22
|
-
global.RTCPeerConnection = wrtc.RTCPeerConnection;
|
|
23
|
-
console.log('Global RTCPeerConnection initialized');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (typeof global.RTCSessionDescription === 'undefined' && wrtc.RTCSessionDescription) {
|
|
27
|
-
global.RTCSessionDescription = wrtc.RTCSessionDescription;
|
|
28
|
-
console.log('Global RTCSessionDescription initialized');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (typeof global.RTCIceCandidate === 'undefined' && wrtc.RTCIceCandidate) {
|
|
32
|
-
global.RTCIceCandidate = wrtc.RTCIceCandidate;
|
|
33
|
-
console.log('Global RTCIceCandidate initialized');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log('WebRTC globals successfully initialized');
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.error('Failed to initialize WebRTC globals:', error);
|
|
39
|
-
}
|
|
40
|
-
})().catch(err => console.error('Error in WebRTC globals initialization:', err));
|
|
41
|
-
|
|
42
|
-
import { PhygridDataChannel, WebRTCConnectionOptions } from '../../types/webrtc.types';
|
|
43
|
-
import {
|
|
44
|
-
PeerConnectionState,
|
|
45
|
-
PeerConnectionCallbacks,
|
|
46
|
-
attemptConnection as attemptConnectionICE,
|
|
47
|
-
triggerReconnect as triggerReconnectICE,
|
|
48
|
-
} from './peer-connection-ice';
|
|
49
|
-
|
|
50
|
-
// Initialize WebRTC globals if we're in Node environment
|
|
51
|
-
(async function initializeWebRTCGlobals() {
|
|
52
|
-
// Only run in Node environment
|
|
53
|
-
if (typeof window !== 'undefined') return;
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
// Dynamically import wrtc
|
|
57
|
-
const wrtc = require('@roamhq/wrtc');
|
|
58
|
-
|
|
59
|
-
// Set all WebRTC globals
|
|
60
|
-
if (typeof global.MediaStream === 'undefined' && wrtc.MediaStream) {
|
|
61
|
-
global.MediaStream = wrtc.MediaStream;
|
|
62
|
-
console.log('Global MediaStream initialized');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (typeof global.RTCPeerConnection === 'undefined' && wrtc.RTCPeerConnection) {
|
|
66
|
-
global.RTCPeerConnection = wrtc.RTCPeerConnection;
|
|
67
|
-
console.log('Global RTCPeerConnection initialized');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (typeof global.RTCSessionDescription === 'undefined' && wrtc.RTCSessionDescription) {
|
|
71
|
-
global.RTCSessionDescription = wrtc.RTCSessionDescription;
|
|
72
|
-
console.log('Global RTCSessionDescription initialized');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (typeof global.RTCIceCandidate === 'undefined' && wrtc.RTCIceCandidate) {
|
|
76
|
-
global.RTCIceCandidate = wrtc.RTCIceCandidate;
|
|
77
|
-
console.log('Global RTCIceCandidate initialized');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log('WebRTC globals successfully initialized');
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error('Failed to initialize WebRTC globals:', error);
|
|
83
|
-
}
|
|
84
|
-
})().catch(err => console.error('Error in WebRTC globals initialization:', err));
|
|
85
|
-
|
|
86
|
-
export interface WebRTCDataChannelResult {
|
|
87
|
-
dataChannel: PhygridDataChannel;
|
|
88
|
-
close: () => void;
|
|
89
|
-
_rawPeerConnection?: RTCPeerConnection;
|
|
90
|
-
_rawDataChannel?: RTCDataChannel;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export type WebRTCDataChannelConnectionResult = WebRTCDataChannelResult;
|
|
94
|
-
|
|
95
|
-
const CONNECTION_TIMEOUT = 15000; // 15 seconds
|
|
96
|
-
const RECONNECT_DELAY = 1000; // 1 second initial reconnect delay
|
|
97
|
-
const INITIAL_RETRY_DELAY = 1000; // 1 second
|
|
98
|
-
const MAX_RETRY_DELAY = 30000; // 30 seconds maximum
|
|
99
|
-
|
|
100
|
-
export async function createWebRTCDataChannelConnection(
|
|
101
|
-
options: WebRTCConnectionOptions
|
|
102
|
-
): Promise<WebRTCDataChannelConnectionResult> {
|
|
103
|
-
let pc: RTCPeerConnection | null = null;
|
|
104
|
-
let isShuttingDown = false;
|
|
105
|
-
let isReconnecting = false;
|
|
106
|
-
let currentConnectionId = 0;
|
|
107
|
-
let pendingCandidates: RTCIceCandidateInit[] = [];
|
|
108
|
-
let activeDataChannel: RTCDataChannel | null = null;
|
|
109
|
-
|
|
110
|
-
const {
|
|
111
|
-
targetTwinId,
|
|
112
|
-
sendTwinMessage,
|
|
113
|
-
subscribeTwin,
|
|
114
|
-
onTwinMessage,
|
|
115
|
-
offTwinMessage,
|
|
116
|
-
useStun = true,
|
|
117
|
-
isInitiator = true,
|
|
118
|
-
channelPrefix = 'channel',
|
|
119
|
-
mediaOptions = { isMediaConnection: false },
|
|
120
|
-
} = options;
|
|
121
|
-
|
|
122
|
-
// Create the persistent data channel once - this is the key to maintaining state across reconnections
|
|
123
|
-
const { persistentChannel, setupDataChannel, setCleanupFn } = createPersistentDataChannel();
|
|
124
|
-
|
|
125
|
-
// Set up cleanup function
|
|
126
|
-
setCleanupFn(() => {
|
|
127
|
-
if (mediaOptions.isMediaConnection && mediaOptions.localStream) {
|
|
128
|
-
mediaOptions.localStream.getTracks().forEach(track => track.stop());
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const callbacks: PeerConnectionCallbacks = {
|
|
133
|
-
async onCreateConnection(
|
|
134
|
-
pcInstance: RTCPeerConnection,
|
|
135
|
-
connectionId: number,
|
|
136
|
-
localInitiator: boolean
|
|
137
|
-
) {
|
|
138
|
-
console.log(
|
|
139
|
-
`Creating data channel for connection ID: ${connectionId} ${JSON.stringify(localInitiator)}`
|
|
140
|
-
);
|
|
141
|
-
const channelId = `${channelPrefix}-${targetTwinId}`;
|
|
142
|
-
|
|
143
|
-
return new Promise<RTCDataChannel | null>(resolve => {
|
|
144
|
-
if (isInitiator) {
|
|
145
|
-
const dataChannel = pcInstance.createDataChannel(channelId);
|
|
146
|
-
dataChannel.binaryType = 'arraybuffer';
|
|
147
|
-
setupDataChannel(dataChannel, isReconnecting, isShuttingDown, triggerReconnect);
|
|
148
|
-
|
|
149
|
-
// This is important - we need to resolve with the data channel
|
|
150
|
-
// even before it's open, so the ICE process can continue
|
|
151
|
-
resolve(dataChannel);
|
|
152
|
-
} else {
|
|
153
|
-
pcInstance.ondatachannel = event => {
|
|
154
|
-
console.log('Data channel received in hub-client');
|
|
155
|
-
const dataChannel = event.channel;
|
|
156
|
-
dataChannel.binaryType = 'arraybuffer';
|
|
157
|
-
setupDataChannel(dataChannel, isReconnecting, isShuttingDown, triggerReconnect);
|
|
158
|
-
};
|
|
159
|
-
resolve(null);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
onCloseCleanup() {
|
|
165
|
-
if (mediaOptions.isMediaConnection && mediaOptions.localStream) {
|
|
166
|
-
mediaOptions.localStream.getTracks().forEach(track => track.stop());
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
async onSubscribe() {
|
|
171
|
-
await subscribeTwin(targetTwinId);
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
async sendSignalingMessage(type, data) {
|
|
175
|
-
await sendTwinMessage(targetTwinId, {
|
|
176
|
-
type: `${channelPrefix}-${targetTwinId}:${type}`,
|
|
177
|
-
data,
|
|
178
|
-
});
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
setupMessageHandling(messageHandler) {
|
|
182
|
-
onTwinMessage(targetTwinId, messageHandler);
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
removeMessageHandling(messageHandler) {
|
|
186
|
-
console.log(`Removing message listener for twin ${targetTwinId}`);
|
|
187
|
-
offTwinMessage(targetTwinId, messageHandler);
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
reportConnectionState(info: string) {
|
|
191
|
-
console.log(info);
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
reportError(info: string, error?: any) {
|
|
195
|
-
console.error(info, error || '');
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
async retryConnection(retries: number, toggledUseStun?: boolean, nextDelay?: number) {
|
|
199
|
-
// Important: we need to reset isReconnecting before starting a new connection attempt
|
|
200
|
-
isReconnecting = false;
|
|
201
|
-
|
|
202
|
-
return attemptConnectionICE(
|
|
203
|
-
state,
|
|
204
|
-
{ ...options, useStun: toggledUseStun ?? useStun },
|
|
205
|
-
retries,
|
|
206
|
-
toggledUseStun ?? useStun,
|
|
207
|
-
nextDelay ?? INITIAL_RETRY_DELAY,
|
|
208
|
-
INITIAL_RETRY_DELAY,
|
|
209
|
-
CONNECTION_TIMEOUT,
|
|
210
|
-
MAX_RETRY_DELAY,
|
|
211
|
-
callbacks
|
|
212
|
-
);
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
safeReject(error) {
|
|
216
|
-
throw error;
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const state: PeerConnectionState = {
|
|
221
|
-
pc,
|
|
222
|
-
isShuttingDown,
|
|
223
|
-
isReconnecting,
|
|
224
|
-
currentConnectionId,
|
|
225
|
-
pendingCandidates,
|
|
226
|
-
activeDataChannel,
|
|
227
|
-
useStun,
|
|
228
|
-
channelPrefix,
|
|
229
|
-
targetTwinId,
|
|
230
|
-
isInitiator,
|
|
231
|
-
connectionType: 'datachannel',
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
function triggerReconnect(attempt: number) {
|
|
235
|
-
if (isReconnecting || isShuttingDown) {
|
|
236
|
-
console.log(
|
|
237
|
-
`triggerReconnect() called but already reconnecting or shutting down (attempt ${attempt})`
|
|
238
|
-
);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
isReconnecting = true;
|
|
243
|
-
|
|
244
|
-
triggerReconnectICE(state, attempt, RECONNECT_DELAY, callbacks);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const result = await attemptConnectionICE(
|
|
248
|
-
state,
|
|
249
|
-
{ ...options },
|
|
250
|
-
0,
|
|
251
|
-
useStun,
|
|
252
|
-
INITIAL_RETRY_DELAY,
|
|
253
|
-
INITIAL_RETRY_DELAY,
|
|
254
|
-
CONNECTION_TIMEOUT,
|
|
255
|
-
MAX_RETRY_DELAY,
|
|
256
|
-
callbacks
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
// Return the persistent data channel
|
|
260
|
-
return {
|
|
261
|
-
dataChannel: persistentChannel,
|
|
262
|
-
_rawPeerConnection: result._rawPeerConnection,
|
|
263
|
-
_rawDataChannel: result._rawDataChannel,
|
|
264
|
-
close: () => {
|
|
265
|
-
isShuttingDown = true;
|
|
266
|
-
if (result.close) {
|
|
267
|
-
result.close();
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const createPersistentDataChannel = (): {
|
|
274
|
-
persistentChannel: PhygridDataChannel;
|
|
275
|
-
setupDataChannel: (
|
|
276
|
-
dc: RTCDataChannel,
|
|
277
|
-
isReconnecting: boolean,
|
|
278
|
-
isShuttingDown: boolean,
|
|
279
|
-
triggerReconnect: (attempt: number) => void
|
|
280
|
-
) => void;
|
|
281
|
-
setCleanupFn: (fn: () => void) => void;
|
|
282
|
-
} => {
|
|
283
|
-
const messageListeners: ((data: any) => void)[] = [];
|
|
284
|
-
const closeListeners: (() => void)[] = [];
|
|
285
|
-
|
|
286
|
-
let currentDataChannel: RTCDataChannel | null = null;
|
|
287
|
-
let activeDataChannel: RTCDataChannel | null = null;
|
|
288
|
-
let reconnectAttempts = 0;
|
|
289
|
-
let cleanupFn: (() => void) | null = null;
|
|
290
|
-
|
|
291
|
-
const setCleanupFn = (fn: () => void) => {
|
|
292
|
-
cleanupFn = fn;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
const persistentChannel: PhygridDataChannel = {
|
|
296
|
-
send: (data: any) => {
|
|
297
|
-
if (activeDataChannel && activeDataChannel.readyState === 'open') {
|
|
298
|
-
try {
|
|
299
|
-
// Convert data to string if it's an object
|
|
300
|
-
if (typeof data === 'object' && data !== null) {
|
|
301
|
-
activeDataChannel.send(JSON.stringify(data));
|
|
302
|
-
} else {
|
|
303
|
-
activeDataChannel.send(data);
|
|
304
|
-
}
|
|
305
|
-
} catch (error) {
|
|
306
|
-
console.error('Error sending data:', error);
|
|
307
|
-
}
|
|
308
|
-
} else {
|
|
309
|
-
console.warn(
|
|
310
|
-
'Channel not ready, dropping message. State:',
|
|
311
|
-
activeDataChannel ? activeDataChannel.readyState : 'no channel'
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
onMessage: (callback: (data: any) => void) => {
|
|
316
|
-
console.log('Adding message listener to persistent channel');
|
|
317
|
-
messageListeners.push(callback);
|
|
318
|
-
},
|
|
319
|
-
offMessage: (callback: (data: any) => void) => {
|
|
320
|
-
const index = messageListeners.indexOf(callback);
|
|
321
|
-
if (index !== -1) {
|
|
322
|
-
messageListeners.splice(index, 1);
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
onClose: (callback: () => void) => {
|
|
326
|
-
closeListeners.push(callback);
|
|
327
|
-
},
|
|
328
|
-
offClose: (callback: () => void) => {
|
|
329
|
-
const index = closeListeners.indexOf(callback);
|
|
330
|
-
if (index !== -1) {
|
|
331
|
-
closeListeners.splice(index, 1);
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
close: () => {
|
|
335
|
-
if (currentDataChannel && currentDataChannel.readyState !== 'closed') {
|
|
336
|
-
currentDataChannel.close();
|
|
337
|
-
}
|
|
338
|
-
if (cleanupFn) cleanupFn();
|
|
339
|
-
},
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
const setupDataChannel = (
|
|
343
|
-
dc: RTCDataChannel,
|
|
344
|
-
isReconnecting: boolean,
|
|
345
|
-
isShuttingDown: boolean,
|
|
346
|
-
triggerReconnect: (attempt: number) => void
|
|
347
|
-
) => {
|
|
348
|
-
console.log('Setting up data channel with listeners');
|
|
349
|
-
currentDataChannel = dc;
|
|
350
|
-
activeDataChannel = dc;
|
|
351
|
-
|
|
352
|
-
dc.onopen = () => {
|
|
353
|
-
console.log('Data channel opened in setupDataChannel, readyState:', dc.readyState);
|
|
354
|
-
currentDataChannel = dc;
|
|
355
|
-
activeDataChannel = dc;
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
dc.onmessage = event => {
|
|
359
|
-
console.log('Received message in data channel:', typeof event.data);
|
|
360
|
-
let parsedData = event.data;
|
|
361
|
-
|
|
362
|
-
// Try to parse JSON if it's a string
|
|
363
|
-
if (typeof event.data === 'string') {
|
|
364
|
-
try {
|
|
365
|
-
parsedData = JSON.parse(event.data);
|
|
366
|
-
} catch (e) {
|
|
367
|
-
// Not JSON, use as is
|
|
368
|
-
parsedData = event.data;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Forward to all listeners
|
|
373
|
-
if (messageListeners.length === 0) {
|
|
374
|
-
console.warn('No message listeners registered for data channel');
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
messageListeners.forEach(listener => {
|
|
378
|
-
try {
|
|
379
|
-
listener(parsedData);
|
|
380
|
-
} catch (error) {
|
|
381
|
-
console.error('Error handling message:', error);
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
dc.onclose = () => {
|
|
387
|
-
console.log('Data channel closed');
|
|
388
|
-
|
|
389
|
-
// Notify all close listeners
|
|
390
|
-
closeListeners.forEach(listener => {
|
|
391
|
-
try {
|
|
392
|
-
listener();
|
|
393
|
-
} catch (error) {
|
|
394
|
-
console.error('Error in close listener:', error);
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
// Only trigger reconnect if not explicitly shutting down
|
|
399
|
-
if (!isShuttingDown && !isReconnecting) {
|
|
400
|
-
console.log('Data channel closed unexpectedly, triggering reconnect');
|
|
401
|
-
triggerReconnect(reconnectAttempts++);
|
|
402
|
-
}
|
|
403
|
-
activeDataChannel = null;
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
dc.onerror = error => {
|
|
407
|
-
console.error('Data channel error:', error);
|
|
408
|
-
// Errors might also require reconnection
|
|
409
|
-
if (!isShuttingDown && !isReconnecting) {
|
|
410
|
-
console.log('Data channel error, triggering reconnect');
|
|
411
|
-
triggerReconnect(reconnectAttempts++);
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
return {
|
|
417
|
-
persistentChannel,
|
|
418
|
-
setupDataChannel,
|
|
419
|
-
setCleanupFn,
|
|
420
|
-
};
|
|
421
|
-
};
|