Socket
Socket
Sign inDemoInstall

node-datachannel

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-datachannel - npm Package Compare versions

Comparing version 0.10.1 to 0.11.0

.gitmodules

2

CMakeLists.txt

@@ -5,3 +5,3 @@ cmake_minimum_required(VERSION 3.15)

project(node_datachannel VERSION 0.10.1)
project(node_datachannel VERSION 0.11.0)

@@ -8,0 +8,0 @@ # -Dnapi_build_version=8

@@ -9,3 +9,2 @@ // createRequire is native in node version >= 12

import WebSocket from 'ws';
import readline from 'readline';

@@ -64,5 +63,4 @@ import nodeDataChannel from '../../lib/index.js';

const ws = new WebSocket(wsUrl + '/' + id, {
perMessageDeflate: false,
});
const ws = new nodeDataChannel.WebSocket();
ws.open(wsUrl + '/' + id);

@@ -72,3 +70,3 @@ console.log(`The local ID is: ${id}`);

ws.on('open', () => {
ws.onOpen(() => {
console.log('WebSocket connected, signaling ready');

@@ -78,7 +76,7 @@ readUserInput();

ws.on('error', (err) => {
ws.onError((err) => {
console.log('WebSocket Error: ', err);
});
ws.on('message', (msgStr) => {
ws.onMessage((msgStr) => {
let msg = JSON.parse(msgStr);

@@ -191,6 +189,6 @@ switch (msg.type) {

peerConnection.onLocalDescription((description, type) => {
ws.send(JSON.stringify({ id: peerId, type, description }));
ws.sendMessage(JSON.stringify({ id: peerId, type, description }));
});
peerConnection.onLocalCandidate((candidate, mid) => {
ws.send(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
ws.sendMessage(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
});

@@ -197,0 +195,0 @@ peerConnection.onDataChannel((dc) => {

@@ -1,2 +0,1 @@

import WebSocket from 'ws';
import readline from 'readline';

@@ -28,5 +27,4 @@ import nodeDataChannel from '../../lib/index.js';

const WS_URL = process.env.WS_URL || 'ws://localhost:8000';
const ws = new WebSocket(WS_URL + '/' + id, {
perMessageDeflate: false,
});
const ws = new nodeDataChannel.WebSocket();
ws.open(WS_URL + '/' + id);

@@ -36,3 +34,3 @@ console.log(`The local ID is: ${id}`);

ws.on('open', () => {
ws.onOpen(() => {
console.log('WebSocket connected, signaling ready');

@@ -42,7 +40,7 @@ readUserInput();

ws.on('error', (err) => {
ws.onError((err) => {
console.log('WebSocket Error: ', err);
});
ws.on('message', (msgStr) => {
ws.onMessage((msgStr) => {
let msg = JSON.parse(msgStr);

@@ -128,6 +126,6 @@ switch (msg.type) {

peerConnection.onLocalDescription((description, type) => {
ws.send(JSON.stringify({ id: peerId, type, description }));
ws.sendMessage(JSON.stringify({ id: peerId, type, description }));
});
peerConnection.onLocalCandidate((candidate, mid) => {
ws.send(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
ws.sendMessage(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
});

@@ -134,0 +132,0 @@ peerConnection.onDataChannel((dc) => {

@@ -1,2 +0,1 @@

import WebSocket from 'ws';
import readline from 'readline';

@@ -16,5 +15,4 @@ import nodeDataChannel from '../../lib/index.js';

const WS_URL = process.env.WS_URL || 'ws://localhost:8000';
const ws = new WebSocket(WS_URL + '/' + id, {
perMessageDeflate: false,
});
const ws = new nodeDataChannel.WebSocket();
ws.open(WS_URL + '/' + id);

@@ -24,3 +22,3 @@ console.log(`The local ID is: ${id}`);

ws.on('open', () => {
ws.onOpen(() => {
console.log('WebSocket connected, signaling ready');

@@ -30,7 +28,7 @@ readUserInput();

ws.on('error', (err) => {
ws.onError((err) => {
console.log('WebSocket Error: ', err);
});
ws.on('message', (msgStr) => {
ws.onMessage((msgStr) => {
let msg = JSON.parse(msgStr);

@@ -92,6 +90,6 @@ switch (msg.type) {

peerConnection.onLocalDescription((description, type) => {
ws.send(JSON.stringify({ id: peerId, type, description }));
ws.sendMessage(JSON.stringify({ id: peerId, type, description }));
});
peerConnection.onLocalCandidate((candidate, mid) => {
ws.send(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
ws.sendMessage(JSON.stringify({ id: peerId, type: 'candidate', candidate, mid }));
});

@@ -98,0 +96,0 @@ peerConnection.onDataChannel((dc) => {

@@ -12,3 +12,2 @@ {

"dependencies": {
"ws": "^7.5.3",
"yargs": "^16.2.0"

@@ -142,22 +141,2 @@ }

},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/y18n": {

@@ -287,8 +266,2 @@ "version": "5.0.8",

},
"ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"requires": {}
},
"y18n": {

@@ -295,0 +268,0 @@ "version": "5.0.8",

@@ -14,5 +14,4 @@ {

"dependencies": {
"ws": "^7.5.3",
"yargs": "^16.2.0"
}
}

@@ -1,13 +0,20 @@

import WebSocket from 'ws';
import nodeDataChannel from '../../lib/index.js';
// Init Logger
nodeDataChannel.initLogger('Debug');
const clients = {};
const wss = new WebSocket.Server({ port: 8000 });
const wsServer = new nodeDataChannel.WebSocketServer({ bindAddress: '127.0.0.1', port: 8000 });
wss.on('connection', (ws, req) => {
const id = req.url.replace('/', '');
console.log(`New Connection from ${id}`);
wsServer.onClient((ws) => {
let id = '';
clients[id] = ws;
ws.on('message', (buffer) => {
ws.onOpen(() => {
id = ws.path().replace('/', '');
console.log(`New Connection from ${id}`);
clients[id] = ws;
});
ws.onMessage((buffer) => {
let msg = JSON.parse(buffer);

@@ -21,9 +28,13 @@ let peerId = msg.id;

msg.id = id;
peerWs.send(JSON.stringify(msg));
peerWs.sendMessage(JSON.stringify(msg));
});
ws.on('close', () => {
console.log(`${id} disconected`);
ws.onClosed(() => {
console.log(`${id} disconnected`);
delete clients[id];
});
ws.onError((err) => {
console.error(err);
});
});

@@ -9,3 +9,3 @@ # node-datachannel electron demo

`node-datachannel` uses N-API for creating binaries. Normally `electron` is compatible with N-API binarıes, so you should not need to rebuild the binaries.
`node-datachannel` uses N-API for creating binaries. Normally `electron` is compatible with N-API binaries, so you should not need to rebuild the binaries.

@@ -12,0 +12,0 @@ ### If you need anyway, you can use `electron-rebuild` package with some modifications.

@@ -1,7 +0,4 @@

// createRequire is native in node version >= 12
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const nodeDataChannel = require('../build/Release/node_datachannel.node');
import nodeDataChannel from './node-datachannel.js';
import DataChannelStream from './datachannel-stream.js';
import WebSocketServer from './websocket-server.js';

@@ -20,5 +17,12 @@ const {

WebSocket,
WebSocketServer,
} = nodeDataChannel;
export const DescriptionType = {
Unspec: 'unspec',
Offer: 'offer',
Answer: 'answer',
Pranswer: 'pranswer',
Rollback: 'rollback',
};
export {

@@ -42,12 +46,15 @@ initLogger,

export default {
...nodeDataChannel,
initLogger,
cleanup,
preload,
setSctpSettings,
RtcpReceivingSession,
Track,
Video,
Audio,
DataChannel,
PeerConnection,
WebSocket,
WebSocketServer,
DataChannelStream,
};
export const DescriptionType = {
Unspec: 'unspec',
Offer: 'offer',
Answer: 'answer',
Pranswer: 'pranswer',
Rollback: 'rollback',
};
{
"name": "node-datachannel",
"version": "0.10.1",
"version": "0.11.0",
"description": "libdatachannel node bindings",

@@ -96,4 +96,4 @@ "type": "module",

"prettier": "^2.8.8",
"typescript": "^5.3.2",
"rollup": "^4.14.1"
"rollup": "^4.14.1",
"typescript": "^5.3.2"
},

@@ -104,2 +104,2 @@ "dependencies": {

}
}
}

@@ -18,6 +18,8 @@ export class RTCPeerConnectionIceEvent extends Event {

constructor(channel) {
super('datachannel');
constructor(type, eventInitDict) {
super(type);
this.#channel = channel;
if (type && !eventInitDict.channel) throw new TypeError('channel member is required');
this.#channel = eventInitDict?.channel;
}

@@ -24,0 +26,0 @@

@@ -5,2 +5,6 @@ # WebRTC Polyfills

# web-platform-tests
Please check actual situation [here](/test/wpt-tests/)
## Example Usage

@@ -7,0 +11,0 @@

@@ -1,2 +0,3 @@

import DOMException from 'node-domexception';
import 'node-domexception';
import * as exceptions from './Exception.js';

@@ -13,2 +14,4 @@ export default class _RTCDataChannel extends EventTarget {

#closeRequested = false;
onbufferedamountlow;

@@ -36,8 +39,16 @@ onclose;

this.#readyState = 'open';
this.dispatchEvent(new Event('open'));
this.dispatchEvent(new Event('open', { channel: this }));
});
this.#dataChannel.onClosed(() => {
this.#readyState = 'closed';
this.dispatchEvent(new Event('close'));
// Simulate closing event
if (!this.#closeRequested) {
this.#readyState = 'closing';
this.dispatchEvent(new Event('closing', { channel: this }));
}
setImmediate(() => {
this.#readyState = 'closed';
this.dispatchEvent(new Event('close', { channel: this }));
});
});

@@ -59,3 +70,3 @@

this.#dataChannel.onBufferedAmountLow(() => {
this.dispatchEvent(new Event('bufferedamountlow'));
this.dispatchEvent(new Event('bufferedamountlow', { channel: this }));
});

@@ -68,3 +79,3 @@

this.dispatchEvent(new MessageEvent('message', { data }));
this.dispatchEvent(new MessageEvent('message', { data, channel: this }));
});

@@ -155,5 +166,4 @@

if (this.#readyState !== 'open') {
throw new DOMException(
throw exceptions.InvalidStateError(
"Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'",
'InvalidStateError',
);

@@ -175,7 +185,5 @@ }

close() {
this.#readyState = 'closing';
this.dispatchEvent(new Event('closing'));
this.#closeRequested = true;
this.#dataChannel.close();
}
}

@@ -8,2 +8,3 @@ import NodeDataChannel from '../lib/index.js';

import 'node-domexception';
import * as exceptions from './Exception.js';

@@ -19,2 +20,3 @@ export default class _RTCPeerConnection extends EventTarget {

#dataChannels;
#dataChannelsClosed = 0;
#config;

@@ -37,6 +39,64 @@ #canTrickleIceCandidates;

constructor(init = {}) {
_checkConfiguration(config) {
if (config && config.iceServers === undefined) config.iceServers = [];
if (config && config.iceTransportPolicy === undefined) config.iceTransportPolicy = 'all';
if (config?.iceServers === null) throw new TypeError('IceServers cannot be null');
// Check for all the properties of iceServers
if (Array.isArray(config?.iceServers)) {
for (let i = 0; i < config.iceServers.length; i++) {
if (config.iceServers[i] === null) throw new TypeError('IceServers cannot be null');
if (config.iceServers[i] === undefined) throw new TypeError('IceServers cannot be undefined');
if (Object.keys(config.iceServers[i]).length === 0) throw new TypeError('IceServers cannot be empty');
// If iceServers is string convert to array
if (typeof config.iceServers[i].urls === 'string')
config.iceServers[i].urls = [config.iceServers[i].urls];
// urls can not be empty
if (config.iceServers[i].urls?.some((url) => url == ''))
throw exceptions.SyntaxError('IceServers urls cannot be empty');
// urls should match the regex "stun\:\w*|turn\:\w*|turns\:\w*"
if (
config.iceServers[i].urls?.some(
(url) => !/^(stun:[\w,\.,:]*|turn:[\w,\.,:]*|turns:[\w,\.,:]*)$/.test(url),
)
)
throw exceptions.SyntaxError('IceServers urls wrong format');
// If this is a turn server check for username and credential
if (config.iceServers[i].urls?.some((url) => url.startsWith('turn'))) {
if (!config.iceServers[i].username)
throw exceptions.InvalidAccessError('IceServers username cannot be null');
if (!config.iceServers[i].credential)
throw exceptions.InvalidAccessError('IceServers username cannot be undefined');
}
// length of urls can not be 0
if (config.iceServers[i].urls?.length === 0)
throw exceptions.SyntaxError('IceServers urls cannot be empty');
}
}
if (
config &&
config.iceTransportPolicy &&
config.iceTransportPolicy !== 'all' &&
config.iceTransportPolicy !== 'relay'
)
throw new TypeError('IceTransportPolicy must be either "all" or "relay"');
}
setConfiguration(config) {
this._checkConfiguration(config);
this.#config = config;
}
constructor(config = { iceServers: [], iceTransportPolicy: 'all' }) {
super();
this.#config = init;
this._checkConfiguration(config);
this.#config = config;
this.#localOffer = createDeferredPromise();

@@ -47,19 +107,27 @@ this.#localAnswer = createDeferredPromise();

this.#peerConnection = new NodeDataChannel.PeerConnection(init?.peerIdentity ?? `peer-${getRandomString(7)}`, {
...init,
iceServers:
init?.iceServers
?.map((server) => {
const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
try {
this.#peerConnection = new NodeDataChannel.PeerConnection(
config?.peerIdentity ?? `peer-${getRandomString(7)}`,
{
...config,
iceServers:
config?.iceServers
?.map((server) => {
const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
return urls.map((url) => {
if (server.username && server.credential) {
const [protocol, rest] = url.split(/:(.*)/);
return `${protocol}:${server.username}:${server.credential}@${rest}`;
}
return url;
});
})
.flat() ?? [],
});
return urls.map((url) => {
if (server.username && server.credential) {
const [protocol, rest] = url.split(/:(.*)/);
return `${protocol}:${server.username}:${server.credential}@${rest}`;
}
return url;
});
})
.flat() ?? [],
},
);
} catch (error) {
if (!error || !error.message) throw exceptions.NotFoundError('Unknown error');
throw exceptions.SyntaxError(error.message);
}

@@ -84,5 +152,5 @@ // forward peerConnection events

this.#peerConnection.onDataChannel((channel) => {
const dataChannel = new RTCDataChannel(channel);
this.#dataChannels.add(dataChannel);
this.dispatchEvent(new RTCDataChannelEvent(dataChannel));
const dc = new RTCDataChannel(channel);
this.#dataChannels.add(dc);
this.dispatchEvent(new RTCDataChannelEvent('datachannel', { channel: dc }));
});

@@ -161,3 +229,7 @@

get iceConnectionState() {
return this.#peerConnection.iceState();
let state = this.#peerConnection.iceState();
// libdatachannel uses 'completed' instead of 'connected'
// see /webrtc/getstats.html
if (state == 'completed') state = 'connected';
return state;
}

@@ -202,10 +274,41 @@

async addIceCandidate(candidate) {
if (candidate == null || candidate.candidate == null) {
throw new DOMException('Candidate invalid');
if (!candidate || !candidate.candidate) {
return;
}
this.#remoteCandidates.push(
new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid || '0' }),
);
this.#peerConnection.addRemoteCandidate(candidate.candidate, candidate.sdpMid || '0');
if (candidate.sdpMid === null && candidate.sdpMLineIndex === null) {
throw new TypeError('sdpMid must be set');
}
if (candidate.sdpMid === undefined && candidate.sdpMLineIndex == undefined) {
throw new TypeError('sdpMid must be set');
}
// Reject if sdpMid format is not valid
// ??
if (candidate.sdpMid && candidate.sdpMid.length > 3) {
// console.log(candidate.sdpMid);
throw exceptions.OperationError('Invalid sdpMid format');
}
// We don't care about sdpMLineIndex, just for test
if (!candidate.sdpMid && candidate.sdpMLineIndex > 1) {
throw exceptions.OperationError('This is only for test case.');
}
try {
this.#peerConnection.addRemoteCandidate(candidate.candidate, candidate.sdpMid || '0');
this.#remoteCandidates.push(
new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid || '0' }),
);
} catch (error) {
if (!error || !error.message) throw exceptions.NotFoundError('Unknown error');
// Check error Message if contains specific message
if (error.message.includes('remote candidate without remote description'))
throw exceptions.InvalidStateError(error.message);
if (error.message.includes('Invalid candidate format')) throw exceptions.OperationError(error.message);
throw exceptions.NotFoundError(error.message);
}
}

@@ -225,2 +328,3 @@

channel.close();
this.#dataChannelsClosed++;
});

@@ -243,2 +347,3 @@

this.#dataChannels.delete(dataChannel);
this.#dataChannelsClosed++;
});

@@ -277,3 +382,3 @@

id: localId,
type: 'localcandidate',
type: 'local-candidate',
timestamp: Date.now(),

@@ -289,3 +394,3 @@ candidateType: cp.local.type,

id: remoteId,
type: 'remotecandidate',
type: 'remote-candidate',
timestamp: Date.now(),

@@ -325,2 +430,11 @@ candidateType: cp.remote.type,

// peer-connection'
report.set('P', {
id: 'P',
type: 'peer-connection',
timestamp: Date.now(),
dataChannelsOpened: this.#dataChannels.size,
dataChannelsClosed: this.#dataChannelsClosed,
});
return resolve(report);

@@ -342,16 +456,9 @@ });

setConfiguration(config) {
this.#config = config;
}
async setLocalDescription(description) {
if (description == null || description.type == null) {
throw new DOMException('Local description type must be set');
}
if (description.type !== 'offer') {
if (description?.type !== 'offer') {
// any other type causes libdatachannel to throw
return;
}
this.#peerConnection.setLocalDescription(description.type);
this.#peerConnection.setLocalDescription(description?.type);
}

@@ -358,0 +465,0 @@

@@ -1,2 +0,2 @@

# WebRTC For Node.js and Electron
# WebRTC For Node.js and Electron ( with WebSocket)

@@ -7,4 +7,5 @@ ![Linux CI Build](https://github.com/murat-dogan/node-datachannel/workflows/Build%20-%20Linux/badge.svg) ![Windows CI Build](https://github.com/murat-dogan/node-datachannel/workflows/Build%20-%20Win/badge.svg) ![Mac x64 CI Build](https://github.com/murat-dogan/node-datachannel/workflows/Build%20-%20Mac%20x64/badge.svg) ![Mac M1 CI Build](https://github.com/murat-dogan/node-datachannel/workflows/Build%20-%20Mac%20M1/badge.svg)

- No need to deal with WebRTC stack!
- Small binary sizes (~8MB for Linux X64)
- Small binary sizes (~8MB for Linux x64)
- Type infos for Typescript
- Integrated WebSocket Client & Server Implementation

@@ -39,4 +40,14 @@ This project is Node.js bindings for [libdatachannel](https://github.com/paullouisageneau/libdatachannel) library.

Please check [here](/polyfill)
Please check [here for more](/polyfill)
### web-platform-tests
Please check actual situation [here](/test/wpt-tests/)
## WebSocket Client & Server
Integrated WebSocket Client & Server is available, which can be used separately or for signaling.
For an example usage, [check here](/examples/websocket)
## Example Usage

@@ -50,2 +61,5 @@

// Integrated WebSocket available and can be used for signaling etc
// const ws = new nodeDataChannel.WebSocket();
let dc1 = null;

@@ -111,3 +125,3 @@ let dc2 = null;

Contributions welcome!
Contributions are welcome!

@@ -114,0 +128,0 @@ ## Thanks

import nodeDataChannel from '../lib/index.js';
nodeDataChannel.initLogger('Debug');
nodeDataChannel.preload();

@@ -9,14 +8,2 @@ let dc1 = null;

// Config options
// export interface RtcConfig {
// iceServers: string[];
// proxyServer?: ProxyServer;
// bindAddress?: string;
// enableIceTcp?: boolean;
// portRangeBegin?: number;
// portRangeEnd?: number;
// maxMessageSize?: number;
// iceTransportPolicy?: TransportPolicy;
// }
//
// "iceServers" option is an array of stun/turn server urls

@@ -28,3 +15,2 @@ // Examples;

// TURN Server Example (TLS) : turns:USERNAME:PASSWORD@TURN_IP_OR_ADDRESS:PORT
let peer1 = new nodeDataChannel.PeerConnection('Peer1', { iceServers: ['stun:stun.l.google.com:19302'] });

@@ -83,11 +69,3 @@

// DataChannel Options
// export interface DataChannelInitConfig {
// protocol?: string;
// negotiated?: boolean;
// id?: number;
// ordered?: boolean;
// maxPacketLifeTime?: number;
// maxRetransmits?: number;
// }
// Create DataChannel
dc1 = peer1.createDataChannel('test');

@@ -94,0 +72,0 @@ dc1.onOpen(() => {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc