node-datachannel 0.7.0 → 0.8.0
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/CMakeLists.txt +2 -2
- package/examples/electron-demo/package.json +1 -1
- package/lib/index.d.cts +313 -0
- package/lib/index.d.ts +4 -0
- package/package.json +18 -7
- package/polyfill/{polyfill.cjs → index.cjs} +1 -1
- package/polyfill/index.d.cts +37 -0
- package/src/web-socket-wrapper.cpp +99 -8
- package/src/web-socket-wrapper.h +4 -0
- package/test/websockets.js +4 -2
package/CMakeLists.txt
CHANGED
|
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
|
|
|
2
2
|
cmake_policy(SET CMP0091 NEW)
|
|
3
3
|
cmake_policy(SET CMP0042 NEW)
|
|
4
4
|
|
|
5
|
-
project(node_datachannel VERSION 0.
|
|
5
|
+
project(node_datachannel VERSION 0.8.0)
|
|
6
6
|
|
|
7
7
|
# -Dnapi_build_version=8
|
|
8
8
|
add_definitions(-DNAPI_VERSION=8)
|
|
@@ -29,7 +29,7 @@ include(FetchContent)
|
|
|
29
29
|
FetchContent_Declare(
|
|
30
30
|
libdatachannel
|
|
31
31
|
GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
|
|
32
|
-
GIT_TAG "v0.20.
|
|
32
|
+
GIT_TAG "v0.20.3"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
|
package/lib/index.d.cts
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import * as stream from 'stream';
|
|
2
|
+
|
|
3
|
+
export as namespace NodeDataChannel;
|
|
4
|
+
|
|
5
|
+
// Enum in d.ts is tricky
|
|
6
|
+
export type LogLevel = 'Verbose' | 'Debug' | 'Info' | 'Warning' | 'Error' | 'Fatal';
|
|
7
|
+
|
|
8
|
+
// SCTP Settings
|
|
9
|
+
export interface SctpSettings {
|
|
10
|
+
recvBufferSize?: number;
|
|
11
|
+
sendBufferSize?: number;
|
|
12
|
+
maxChunksOnQueue?: number;
|
|
13
|
+
initialCongestionWindow?: number;
|
|
14
|
+
congestionControlModule?: number;
|
|
15
|
+
delayedSackTime?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Functions
|
|
19
|
+
export function preload(): void;
|
|
20
|
+
export function initLogger(level: LogLevel, callback?: (level: LogLevel, message: string) => void): void;
|
|
21
|
+
export function cleanup(): void;
|
|
22
|
+
export function setSctpSettings(settings: SctpSettings): void;
|
|
23
|
+
|
|
24
|
+
// Proxy Server
|
|
25
|
+
export type ProxyServerType = 'Socks5' | 'Http';
|
|
26
|
+
export interface ProxyServer {
|
|
27
|
+
type: ProxyServerType;
|
|
28
|
+
ip: string;
|
|
29
|
+
port: number;
|
|
30
|
+
username?: string;
|
|
31
|
+
password?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const enum RelayType {
|
|
35
|
+
TurnUdp = 'TurnUdp',
|
|
36
|
+
TurnTcp = 'TurnTcp',
|
|
37
|
+
TurnTls = 'TurnTls',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IceServer {
|
|
41
|
+
hostname: string;
|
|
42
|
+
port: number;
|
|
43
|
+
username?: string;
|
|
44
|
+
password?: string;
|
|
45
|
+
relayType?: RelayType;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type TransportPolicy = 'all' | 'relay';
|
|
49
|
+
|
|
50
|
+
export interface RtcConfig {
|
|
51
|
+
iceServers: (string | IceServer)[];
|
|
52
|
+
proxyServer?: ProxyServer;
|
|
53
|
+
bindAddress?: string;
|
|
54
|
+
enableIceTcp?: boolean;
|
|
55
|
+
enableIceUdpMux?: boolean;
|
|
56
|
+
disableAutoNegotiation?: boolean;
|
|
57
|
+
forceMediaTransport?: boolean;
|
|
58
|
+
portRangeBegin?: number;
|
|
59
|
+
portRangeEnd?: number;
|
|
60
|
+
maxMessageSize?: number;
|
|
61
|
+
mtu?: number;
|
|
62
|
+
iceTransportPolicy?: TransportPolicy;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Lowercase to match the description type string from libdatachannel
|
|
66
|
+
export const enum DescriptionType {
|
|
67
|
+
Unspec = 'unspec',
|
|
68
|
+
Offer = 'offer',
|
|
69
|
+
Answer = 'answer',
|
|
70
|
+
Pranswer = 'pranswer',
|
|
71
|
+
Rollback = 'rollback',
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const enum ReliabilityType {
|
|
75
|
+
Reliable = 0,
|
|
76
|
+
Rexmit = 1,
|
|
77
|
+
Timed = 2,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface DataChannelInitConfig {
|
|
81
|
+
protocol?: string;
|
|
82
|
+
negotiated?: boolean;
|
|
83
|
+
id?: number;
|
|
84
|
+
ordered?: boolean;
|
|
85
|
+
maxPacketLifeTime?: number;
|
|
86
|
+
maxRetransmits?: number;
|
|
87
|
+
|
|
88
|
+
// Deprecated, use ordered, maxPacketLifeTime, and maxRetransmits
|
|
89
|
+
reliability?: {
|
|
90
|
+
type?: ReliabilityType;
|
|
91
|
+
unordered?: boolean;
|
|
92
|
+
rexmit?: number;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface SelectedCandidateInfo {
|
|
97
|
+
address: string;
|
|
98
|
+
port: number;
|
|
99
|
+
type: string;
|
|
100
|
+
transportType: string;
|
|
101
|
+
candidate: string;
|
|
102
|
+
mid: string;
|
|
103
|
+
priority: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Must be same as rtc enum class Direction
|
|
107
|
+
export const enum Direction {
|
|
108
|
+
SendOnly = 'SendOnly',
|
|
109
|
+
RecvOnly = 'RecvOnly',
|
|
110
|
+
SendRecv = 'SendRecv',
|
|
111
|
+
Inactive = 'Inactive',
|
|
112
|
+
Unknown = 'Unknown',
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class RtcpReceivingSession {
|
|
116
|
+
requestBitrate(bitRate: number): void;
|
|
117
|
+
requestKeyframe(): boolean;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export class Audio {
|
|
121
|
+
constructor(mid: string, dir: Direction);
|
|
122
|
+
addAudioCodec(payloadType: number, codec: string, profile?: string): void;
|
|
123
|
+
addOpusCodec(payloadType: number, profile?: string): string;
|
|
124
|
+
|
|
125
|
+
direction(): Direction;
|
|
126
|
+
generateSdp(eol: string, addr: string, port: number): string;
|
|
127
|
+
mid(): string;
|
|
128
|
+
setDirection(dir: Direction): void;
|
|
129
|
+
description(): string;
|
|
130
|
+
removeFormat(fmt: string): void;
|
|
131
|
+
addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
132
|
+
removeSSRC(ssrc: number): void;
|
|
133
|
+
replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
134
|
+
hasSSRC(ssrc: number): boolean;
|
|
135
|
+
getSSRCs(): number[];
|
|
136
|
+
getCNameForSsrc(ssrc: number): string;
|
|
137
|
+
setBitrate(bitRate: number): void;
|
|
138
|
+
getBitrate(): number;
|
|
139
|
+
hasPayloadType(payloadType: number): boolean;
|
|
140
|
+
addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
|
|
141
|
+
addRTPMap(): void;
|
|
142
|
+
parseSdpLine(line: string): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class Video {
|
|
146
|
+
constructor(mid: string, dir: Direction);
|
|
147
|
+
addVideoCodec(payloadType: number, codec: string, profile?: string): void;
|
|
148
|
+
addH264Codec(payloadType: number, profile?: string): void;
|
|
149
|
+
addVP8Codec(payloadType: number): void;
|
|
150
|
+
addVP9Codec(payloadType: number): void;
|
|
151
|
+
|
|
152
|
+
direction(): Direction;
|
|
153
|
+
generateSdp(eol: string, addr: string, port: number): string;
|
|
154
|
+
mid(): string;
|
|
155
|
+
setDirection(dir: Direction): void;
|
|
156
|
+
description(): string;
|
|
157
|
+
removeFormat(fmt: string): void;
|
|
158
|
+
addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
159
|
+
removeSSRC(ssrc: number): void;
|
|
160
|
+
replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
161
|
+
hasSSRC(ssrc: number): boolean;
|
|
162
|
+
getSSRCs(): number[];
|
|
163
|
+
getCNameForSsrc(ssrc: number): string;
|
|
164
|
+
setBitrate(bitRate: number): void;
|
|
165
|
+
getBitrate(): number;
|
|
166
|
+
hasPayloadType(payloadType: number): boolean;
|
|
167
|
+
addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
|
|
168
|
+
addRTPMap(): void;
|
|
169
|
+
parseSdpLine(line: string): void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export class Track {
|
|
173
|
+
direction(): Direction;
|
|
174
|
+
mid(): string;
|
|
175
|
+
type(): string;
|
|
176
|
+
close(): void;
|
|
177
|
+
sendMessage(msg: string): boolean;
|
|
178
|
+
sendMessageBinary(buffer: Buffer): boolean;
|
|
179
|
+
isOpen(): boolean;
|
|
180
|
+
isClosed(): boolean;
|
|
181
|
+
bufferedAmount(): number;
|
|
182
|
+
maxMessageSize(): number;
|
|
183
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
184
|
+
requestKeyframe(): boolean;
|
|
185
|
+
setMediaHandler(handler: RtcpReceivingSession): void;
|
|
186
|
+
onOpen(cb: () => void): void;
|
|
187
|
+
onClosed(cb: () => void): void;
|
|
188
|
+
onError(cb: (err: string) => void): void;
|
|
189
|
+
onMessage(cb: (msg: Buffer) => void): void;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface Channel {
|
|
193
|
+
close(): void;
|
|
194
|
+
sendMessage(msg: string): boolean;
|
|
195
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
196
|
+
isOpen(): boolean;
|
|
197
|
+
bufferedAmount(): number;
|
|
198
|
+
maxMessageSize(): number;
|
|
199
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
200
|
+
onOpen(cb: () => void): void;
|
|
201
|
+
onClosed(cb: () => void): void;
|
|
202
|
+
onError(cb: (err: string) => void): void;
|
|
203
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
204
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
205
|
+
}
|
|
206
|
+
export class DataChannel implements Channel {
|
|
207
|
+
getLabel(): string;
|
|
208
|
+
getId(): number;
|
|
209
|
+
getProtocol(): string;
|
|
210
|
+
|
|
211
|
+
// Channel implementation
|
|
212
|
+
close(): void;
|
|
213
|
+
sendMessage(msg: string): boolean;
|
|
214
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
215
|
+
isOpen(): boolean;
|
|
216
|
+
bufferedAmount(): number;
|
|
217
|
+
maxMessageSize(): number;
|
|
218
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
219
|
+
onOpen(cb: () => void): void;
|
|
220
|
+
onClosed(cb: () => void): void;
|
|
221
|
+
onError(cb: (err: string) => void): void;
|
|
222
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
223
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface WebSocketConfiguration {
|
|
227
|
+
disableTlsVerification?: boolean; // default = false, if true, don't verify the TLS certificate
|
|
228
|
+
proxyServer?: ProxyServer; // only non-authenticated http supported for now
|
|
229
|
+
protocols?: string[];
|
|
230
|
+
connectionTimeout?: number; // miliseconds, zero to disable
|
|
231
|
+
pingInterval?: number; // millisecondrs, zero to disable
|
|
232
|
+
maxOutstandingPings?: number;
|
|
233
|
+
caCertificatePemFile?: string;
|
|
234
|
+
certificatePemFile?: string;
|
|
235
|
+
keyPemFile?: string;
|
|
236
|
+
keyPemPass?: string;
|
|
237
|
+
maxMessageSize: number;
|
|
238
|
+
}
|
|
239
|
+
export class WebSocket implements Channel {
|
|
240
|
+
constructor(config?: WebSocketConfiguration);
|
|
241
|
+
open(url: string): void;
|
|
242
|
+
forceClose(): void;
|
|
243
|
+
remoteAddress(): string | undefined;
|
|
244
|
+
path(): string | undefined;
|
|
245
|
+
|
|
246
|
+
// Channel implementation
|
|
247
|
+
close(): void;
|
|
248
|
+
sendMessage(msg: string): boolean;
|
|
249
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
250
|
+
isOpen(): boolean;
|
|
251
|
+
bufferedAmount(): number;
|
|
252
|
+
maxMessageSize(): number;
|
|
253
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
254
|
+
onOpen(cb: () => void): void;
|
|
255
|
+
onClosed(cb: () => void): void;
|
|
256
|
+
onError(cb: (err: string) => void): void;
|
|
257
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
258
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface WebSocketServerConfiguration {
|
|
262
|
+
port?: number; // default 8080
|
|
263
|
+
enableTls?: boolean; // default = false;
|
|
264
|
+
certificatePemFile?: string;
|
|
265
|
+
keyPemFile?: string;
|
|
266
|
+
keyPemPass?: string;
|
|
267
|
+
bindAddress?: string;
|
|
268
|
+
connectionTimeout?: number; // milliseconds
|
|
269
|
+
maxMessageSize?: number;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export class WebSocketServer {
|
|
273
|
+
constructor(config?: WebSocketServerConfiguration);
|
|
274
|
+
port(): number;
|
|
275
|
+
stop(): void;
|
|
276
|
+
onClient(cb: (ws: WebSocket) => void): void;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export class PeerConnection {
|
|
280
|
+
constructor(peerName: string, config: RtcConfig);
|
|
281
|
+
close(): void;
|
|
282
|
+
setLocalDescription(type?: DescriptionType): void;
|
|
283
|
+
setRemoteDescription(sdp: string, type: DescriptionType): void;
|
|
284
|
+
localDescription(): { type: string; sdp: string } | null;
|
|
285
|
+
remoteDescription(): { type: string; sdp: string } | null;
|
|
286
|
+
addRemoteCandidate(candidate: string, mid: string): void;
|
|
287
|
+
createDataChannel(label: string, config?: DataChannelInitConfig): DataChannel;
|
|
288
|
+
addTrack(media: Video | Audio): Track;
|
|
289
|
+
hasMedia(): boolean;
|
|
290
|
+
state(): RTCPeerConnectionState;
|
|
291
|
+
iceState(): RTCIceConnectionState;
|
|
292
|
+
signalingState(): RTCSignalingState;
|
|
293
|
+
gatheringState(): RTCIceGatheringState;
|
|
294
|
+
onLocalDescription(cb: (sdp: string, type: DescriptionType) => void): void;
|
|
295
|
+
onLocalCandidate(cb: (candidate: string, mid: string) => void): void;
|
|
296
|
+
onStateChange(cb: (state: string) => void): void;
|
|
297
|
+
onIceStateChange(cb: (state: string) => void): void;
|
|
298
|
+
onSignalingStateChange(cb: (state: string) => void): void;
|
|
299
|
+
onGatheringStateChange(cb: (state: string) => void): void;
|
|
300
|
+
onDataChannel(cb: (dc: DataChannel) => void): void;
|
|
301
|
+
onTrack(cb: (track: Track) => void): void;
|
|
302
|
+
bytesSent(): number;
|
|
303
|
+
bytesReceived(): number;
|
|
304
|
+
rtt(): number;
|
|
305
|
+
getSelectedCandidatePair(): { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null;
|
|
306
|
+
maxDataChannelId(): number;
|
|
307
|
+
maxMessageSize(): number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export class DataChannelStream extends stream.Duplex {
|
|
311
|
+
constructor(rawChannel: DataChannel, options?: Omit<stream.DuplexOptions, 'objectMode'>);
|
|
312
|
+
get label(): string;
|
|
313
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -238,6 +238,10 @@ export interface WebSocketConfiguration {
|
|
|
238
238
|
}
|
|
239
239
|
export class WebSocket implements Channel {
|
|
240
240
|
constructor(config?: WebSocketConfiguration);
|
|
241
|
+
open(url: string): void;
|
|
242
|
+
forceClose(): void;
|
|
243
|
+
remoteAddress(): string | undefined;
|
|
244
|
+
path(): string | undefined;
|
|
241
245
|
|
|
242
246
|
// Channel implementation
|
|
243
247
|
close(): void;
|
package/package.json
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-datachannel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "libdatachannel node bindings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"import":
|
|
9
|
-
|
|
8
|
+
"import": {
|
|
9
|
+
"default": "./lib/index.js",
|
|
10
|
+
"types": "./lib/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"require": {
|
|
13
|
+
"default": "./lib/index.cjs",
|
|
14
|
+
"types": "./lib/index.d.cts"
|
|
15
|
+
}
|
|
10
16
|
},
|
|
11
17
|
"./polyfill": {
|
|
12
|
-
"import":
|
|
13
|
-
|
|
18
|
+
"import": {
|
|
19
|
+
"default": "./polyfill/index.js",
|
|
20
|
+
"types": "./polyfill/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"default": "./polyfill/index.cjs",
|
|
24
|
+
"types": "./polyfill/index.d.cts"
|
|
25
|
+
}
|
|
14
26
|
}
|
|
15
27
|
},
|
|
16
|
-
"typings": "lib/index.d.ts",
|
|
17
28
|
"engines": {
|
|
18
29
|
"node": ">=16.0.0"
|
|
19
30
|
},
|
|
@@ -34,7 +45,7 @@
|
|
|
34
45
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
35
46
|
"wpt-test": "node test/wpt.js",
|
|
36
47
|
"test-types": "tsc",
|
|
37
|
-
"prepublishOnly": "rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/
|
|
48
|
+
"prepublishOnly": "cp lib/index.d.ts lib/index.d.cts && cp polyfill/index.d.ts polyfill/index.d.cts && rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/index.cjs --format cjs"
|
|
38
49
|
},
|
|
39
50
|
"binary": {
|
|
40
51
|
"napi_versions": [
|
|
@@ -547,7 +547,7 @@ class DataChannelStream extends stream.Duplex {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
// createRequire is native in node version >= 12
|
|
550
|
-
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('
|
|
550
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
551
551
|
|
|
552
552
|
const nodeDataChannel = require$1('../build/Release/node_datachannel.node');
|
|
553
553
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import RTCCertificate from './RTCCertificate.js';
|
|
2
|
+
import RTCDataChannel from './RTCDataChannel.js';
|
|
3
|
+
import RTCDtlsTransport from './RTCDtlsTransport.js';
|
|
4
|
+
import RTCIceCandidate from './RTCIceCandidate.js';
|
|
5
|
+
import RTCIceTransport from './RTCIceTransport.js';
|
|
6
|
+
import RTCPeerConnection from './RTCPeerConnection.js';
|
|
7
|
+
import RTCSctpTransport from './RTCSctpTransport.js';
|
|
8
|
+
import RTCSessionDescription from './RTCSessionDescription.js';
|
|
9
|
+
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events.js';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
RTCCertificate,
|
|
13
|
+
RTCDataChannel,
|
|
14
|
+
RTCDtlsTransport,
|
|
15
|
+
RTCIceCandidate,
|
|
16
|
+
RTCIceTransport,
|
|
17
|
+
RTCPeerConnection,
|
|
18
|
+
RTCSctpTransport,
|
|
19
|
+
RTCSessionDescription,
|
|
20
|
+
RTCDataChannelEvent,
|
|
21
|
+
RTCPeerConnectionIceEvent,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
declare const _default: {
|
|
25
|
+
RTCCertificate: typeof RTCCertificate;
|
|
26
|
+
RTCDataChannel: typeof RTCDataChannel;
|
|
27
|
+
RTCDtlsTransport: typeof RTCDtlsTransport;
|
|
28
|
+
RTCIceCandidate: typeof RTCIceCandidate;
|
|
29
|
+
RTCIceTransport: typeof RTCIceTransport;
|
|
30
|
+
RTCPeerConnection: typeof RTCPeerConnection;
|
|
31
|
+
RTCSctpTransport: typeof RTCSctpTransport;
|
|
32
|
+
RTCSessionDescription: typeof RTCSessionDescription;
|
|
33
|
+
RTCDataChannelEvent: typeof RTCDataChannelEvent;
|
|
34
|
+
RTCPeerConnectionIceEvent: typeof RTCPeerConnectionIceEvent;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default _default;
|
|
@@ -31,6 +31,7 @@ Napi::Object WebSocketWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
31
31
|
{
|
|
32
32
|
InstanceMethod("open", &WebSocketWrapper::open),
|
|
33
33
|
InstanceMethod("close", &WebSocketWrapper::close),
|
|
34
|
+
InstanceMethod("forceClose", &WebSocketWrapper::forceClose),
|
|
34
35
|
InstanceMethod("sendMessage", &WebSocketWrapper::sendMessage),
|
|
35
36
|
InstanceMethod("sendMessageBinary", &WebSocketWrapper::sendMessageBinary),
|
|
36
37
|
InstanceMethod("isOpen", &WebSocketWrapper::isOpen),
|
|
@@ -42,6 +43,8 @@ Napi::Object WebSocketWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
42
43
|
InstanceMethod("onError", &WebSocketWrapper::onError),
|
|
43
44
|
InstanceMethod("onBufferedAmountLow", &WebSocketWrapper::onBufferedAmountLow),
|
|
44
45
|
InstanceMethod("onMessage", &WebSocketWrapper::onMessage),
|
|
46
|
+
InstanceMethod("remoteAddress", &WebSocketWrapper::remoteAddress),
|
|
47
|
+
InstanceMethod("path", &WebSocketWrapper::path),
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
constructor = Napi::Persistent(func);
|
|
@@ -257,7 +260,31 @@ void WebSocketWrapper::doClose()
|
|
|
257
260
|
}
|
|
258
261
|
catch (std::exception &ex)
|
|
259
262
|
{
|
|
260
|
-
std::cerr << std::string("
|
|
263
|
+
std::cerr << std::string("libdatachannel error while closing WebSocket: ") + ex.what() << std::endl;
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
mOnOpenCallback.reset();
|
|
269
|
+
mOnErrorCallback.reset();
|
|
270
|
+
mOnBufferedAmountLowCallback.reset();
|
|
271
|
+
mOnMessageCallback.reset();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
void WebSocketWrapper::doForceClose()
|
|
275
|
+
{
|
|
276
|
+
PLOG_DEBUG << "doForceClose() called";
|
|
277
|
+
if (mWebSocketPtr)
|
|
278
|
+
{
|
|
279
|
+
PLOG_DEBUG << "Force closing...";
|
|
280
|
+
try
|
|
281
|
+
{
|
|
282
|
+
mWebSocketPtr->forceClose();
|
|
283
|
+
mWebSocketPtr.reset();
|
|
284
|
+
}
|
|
285
|
+
catch (std::exception &ex)
|
|
286
|
+
{
|
|
287
|
+
std::cerr << std::string("libdatachannel error while force closing WebSocket: ") + ex.what() << std::endl;
|
|
261
288
|
return;
|
|
262
289
|
}
|
|
263
290
|
}
|
|
@@ -297,7 +324,7 @@ void WebSocketWrapper::open(const Napi::CallbackInfo &info)
|
|
|
297
324
|
}
|
|
298
325
|
catch (std::exception &ex)
|
|
299
326
|
{
|
|
300
|
-
Napi::Error::New(env, std::string("
|
|
327
|
+
Napi::Error::New(env, std::string("libdatachannel error while opening WebSocket: ") + ex.what()).ThrowAsJavaScriptException();
|
|
301
328
|
return;
|
|
302
329
|
}
|
|
303
330
|
}
|
|
@@ -308,6 +335,12 @@ void WebSocketWrapper::close(const Napi::CallbackInfo &info)
|
|
|
308
335
|
doClose();
|
|
309
336
|
}
|
|
310
337
|
|
|
338
|
+
void WebSocketWrapper::forceClose(const Napi::CallbackInfo &info)
|
|
339
|
+
{
|
|
340
|
+
PLOG_DEBUG << "forceClose() called";
|
|
341
|
+
doForceClose();
|
|
342
|
+
}
|
|
343
|
+
|
|
311
344
|
Napi::Value WebSocketWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
312
345
|
{
|
|
313
346
|
PLOG_DEBUG << "sendMessage() called";
|
|
@@ -333,7 +366,7 @@ Napi::Value WebSocketWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
|
333
366
|
}
|
|
334
367
|
catch (std::exception &ex)
|
|
335
368
|
{
|
|
336
|
-
Napi::Error::New(env, std::string("
|
|
369
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending data channel message: ") + ex.what()).ThrowAsJavaScriptException();
|
|
337
370
|
return Napi::Boolean::New(info.Env(), false);
|
|
338
371
|
}
|
|
339
372
|
}
|
|
@@ -363,7 +396,7 @@ Napi::Value WebSocketWrapper::sendMessageBinary(const Napi::CallbackInfo &info)
|
|
|
363
396
|
}
|
|
364
397
|
catch (std::exception &ex)
|
|
365
398
|
{
|
|
366
|
-
Napi::Error::New(env, std::string("
|
|
399
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending data channel message: ") + ex.what()).ThrowAsJavaScriptException();
|
|
367
400
|
return Napi::Boolean::New(info.Env(), false);
|
|
368
401
|
}
|
|
369
402
|
}
|
|
@@ -384,7 +417,7 @@ Napi::Value WebSocketWrapper::isOpen(const Napi::CallbackInfo &info)
|
|
|
384
417
|
}
|
|
385
418
|
catch (std::exception &ex)
|
|
386
419
|
{
|
|
387
|
-
Napi::Error::New(env, std::string("
|
|
420
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
388
421
|
return Napi::Boolean::New(info.Env(), false);
|
|
389
422
|
}
|
|
390
423
|
}
|
|
@@ -405,7 +438,7 @@ Napi::Value WebSocketWrapper::bufferedAmount(const Napi::CallbackInfo &info)
|
|
|
405
438
|
}
|
|
406
439
|
catch (std::exception &ex)
|
|
407
440
|
{
|
|
408
|
-
Napi::Error::New(env, std::string("
|
|
441
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
409
442
|
return Napi::Number::New(info.Env(), 0);
|
|
410
443
|
}
|
|
411
444
|
}
|
|
@@ -426,11 +459,69 @@ Napi::Value WebSocketWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
|
426
459
|
}
|
|
427
460
|
catch (std::exception &ex)
|
|
428
461
|
{
|
|
429
|
-
Napi::Error::New(env, std::string("
|
|
462
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
430
463
|
return Napi::Number::New(info.Env(), 0);
|
|
431
464
|
}
|
|
432
465
|
}
|
|
433
466
|
|
|
467
|
+
Napi::Value WebSocketWrapper::remoteAddress(const Napi::CallbackInfo &info)
|
|
468
|
+
{
|
|
469
|
+
PLOG_DEBUG << "remoteAddress() called";
|
|
470
|
+
Napi::Env env = info.Env();
|
|
471
|
+
|
|
472
|
+
if (!mWebSocketPtr)
|
|
473
|
+
{
|
|
474
|
+
return env.Undefined();
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
try
|
|
478
|
+
{
|
|
479
|
+
auto address = mWebSocketPtr->remoteAddress();
|
|
480
|
+
if (address.has_value())
|
|
481
|
+
{
|
|
482
|
+
return Napi::String::New(info.Env(), address.value());
|
|
483
|
+
}
|
|
484
|
+
else
|
|
485
|
+
{
|
|
486
|
+
return env.Undefined();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
catch (std::exception &ex)
|
|
490
|
+
{
|
|
491
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
492
|
+
return env.Undefined();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
Napi::Value WebSocketWrapper::path(const Napi::CallbackInfo &info)
|
|
497
|
+
{
|
|
498
|
+
PLOG_DEBUG << "path() called";
|
|
499
|
+
Napi::Env env = info.Env();
|
|
500
|
+
|
|
501
|
+
if (!mWebSocketPtr)
|
|
502
|
+
{
|
|
503
|
+
return env.Undefined();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
try
|
|
507
|
+
{
|
|
508
|
+
auto path = mWebSocketPtr->path();
|
|
509
|
+
if (path.has_value())
|
|
510
|
+
{
|
|
511
|
+
return Napi::String::New(info.Env(), path.value());
|
|
512
|
+
}
|
|
513
|
+
else
|
|
514
|
+
{
|
|
515
|
+
return env.Undefined();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
catch (std::exception &ex)
|
|
519
|
+
{
|
|
520
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
521
|
+
return env.Undefined();
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
434
525
|
void WebSocketWrapper::setBufferedAmountLowThreshold(const Napi::CallbackInfo &info)
|
|
435
526
|
{
|
|
436
527
|
PLOG_DEBUG << "setBufferedAmountLowThreshold() called";
|
|
@@ -455,7 +546,7 @@ void WebSocketWrapper::setBufferedAmountLowThreshold(const Napi::CallbackInfo &i
|
|
|
455
546
|
}
|
|
456
547
|
catch (std::exception &ex)
|
|
457
548
|
{
|
|
458
|
-
Napi::Error::New(env, std::string("
|
|
549
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
459
550
|
return;
|
|
460
551
|
}
|
|
461
552
|
}
|
package/src/web-socket-wrapper.h
CHANGED
|
@@ -23,12 +23,15 @@ public:
|
|
|
23
23
|
// Functions
|
|
24
24
|
void open(const Napi::CallbackInfo &info);
|
|
25
25
|
void close(const Napi::CallbackInfo &info);
|
|
26
|
+
void forceClose(const Napi::CallbackInfo &info);
|
|
26
27
|
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
27
28
|
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
28
29
|
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
29
30
|
Napi::Value bufferedAmount(const Napi::CallbackInfo &info);
|
|
30
31
|
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
31
32
|
void setBufferedAmountLowThreshold(const Napi::CallbackInfo &info);
|
|
33
|
+
Napi::Value remoteAddress(const Napi::CallbackInfo &info);
|
|
34
|
+
Napi::Value path(const Napi::CallbackInfo &info);
|
|
32
35
|
|
|
33
36
|
// Callbacks
|
|
34
37
|
void onOpen(const Napi::CallbackInfo &info);
|
|
@@ -47,6 +50,7 @@ private:
|
|
|
47
50
|
static std::unordered_set<WebSocketWrapper *> instances;
|
|
48
51
|
|
|
49
52
|
void doClose();
|
|
53
|
+
void doForceClose();
|
|
50
54
|
void doCleanup();
|
|
51
55
|
|
|
52
56
|
std::shared_ptr<rtc::WebSocket> mWebSocketPtr = nullptr;
|
package/test/websockets.js
CHANGED
|
@@ -6,7 +6,9 @@ nodeDataChannel.preload();
|
|
|
6
6
|
const webSocketServer = new nodeDataChannel.WebSocketServer({ bindAddress: '127.0.0.1', port: 1987 });
|
|
7
7
|
|
|
8
8
|
webSocketServer.onClient((serverSocket) => {
|
|
9
|
-
console.log(
|
|
9
|
+
console.log(
|
|
10
|
+
'webSocketServer.onClient() remoteAddress: ' + serverSocket.remoteAddress() + ', path: ' + serverSocket.path(),
|
|
11
|
+
);
|
|
10
12
|
|
|
11
13
|
serverSocket.onOpen(() => {
|
|
12
14
|
console.log('serverSocket.onOpen()');
|
|
@@ -32,7 +34,7 @@ clientSocket.onOpen(() => {
|
|
|
32
34
|
|
|
33
35
|
clientSocket.onMessage((message) => {
|
|
34
36
|
console.log('clientSocket.onMessage():', message);
|
|
35
|
-
clientSocket.
|
|
37
|
+
clientSocket.forceClose();
|
|
36
38
|
webSocketServer.stop();
|
|
37
39
|
});
|
|
38
40
|
|