Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ If `opts` is specified, then the default options (shown below) will be overridde
```
{
initiator: false,
enableDataChannel: true,
channelConfig: {},
channelName: '<random string>',
config: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }] },
Expand All @@ -286,6 +287,7 @@ If `opts` is specified, then the default options (shown below) will be overridde
The options do the following:

- `initiator` - set to `true` if this is the initiating peer
- `enableDataChannel` - set to `false` if no data channel should be created for this peer
- `channelConfig` - custom webrtc data channel configuration (used by [`createDataChannel`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel))
- `channelName` - custom webrtc data channel name
- `config` - custom webrtc configuration (used by [`RTCPeerConnection`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) constructor)
Expand Down Expand Up @@ -456,6 +458,7 @@ Possible error codes:
- `ERR_ICE_CONNECTION_FAILURE`
- `ERR_SIGNALING`
- `ERR_DATA_CHANNEL`
- `ERR_DISABLED_DATA_CHANNEL`
- `ERR_CONNECTION_FAILURE`


Expand Down
40 changes: 31 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Peer extends stream.Duplex {
: null

this.initiator = opts.initiator || false
this.enableDataChannel = opts.enableDataChannel ?? true
this.channelConfig = opts.channelConfig || Peer.channelConfig
this.channelNegotiated = this.channelConfig.negotiated
this.config = Object.assign({}, Peer.config, opts.config)
Expand Down Expand Up @@ -137,13 +138,15 @@ class Peer extends stream.Duplex {
// - onfingerprintfailure
// - onnegotiationneeded

if (this.initiator || this.channelNegotiated) {
this._setupData({
channel: this._pc.createDataChannel(this.channelName, this.channelConfig)
})
} else {
this._pc.ondatachannel = event => {
this._setupData(event)
if (this.enableDataChannel) {
if (this.initiator || this.channelNegotiated) {
this._setupData({
channel: this._pc.createDataChannel(this.channelName, this.channelConfig)
})
} else {
this._pc.ondatachannel = event => {
this._setupData(event)
}
}
}

Expand Down Expand Up @@ -172,7 +175,7 @@ class Peer extends stream.Duplex {
// HACK: it's possible channel.readyState is "closing" before peer.destroy() fires
// https://bugs.chromium.org/p/chromium/issues/detail?id=882743
get connected () {
return (this._connected && this._channel.readyState === 'open')
return (this._connected && this._channel && this._channel.readyState === 'open')
Comment thread
marcelwgn marked this conversation as resolved.
Outdated
}

address () {
Expand Down Expand Up @@ -244,6 +247,7 @@ class Peer extends stream.Duplex {
* @param {ArrayBufferView|ArrayBuffer|Buffer|string|Blob} chunk
*/
send (chunk) {
if (!this.enableDataChannel) throw errCode(new Error('Cannot write if data channel is disabled'), 'ERR_DISABLED_DATA_CHANNEL')
if (this.destroying) return
if (this.destroyed) throw errCode(new Error('cannot send after peer is destroyed'), 'ERR_DESTROYED')
this._channel.send(chunk)
Expand Down Expand Up @@ -500,6 +504,12 @@ class Peer extends stream.Duplex {
}

_setupData (event) {
if(!this.enableDataChannel)
{
// Configured to NOT use a data channel, calling setupData is invalid in this case.
return this.destroy(errCode(new Error('Tried to create data channel despite disabled data channel.'), 'ERR_DISABLED_DATA_CHANNEL'))
}

if (!event.channel) {
// In some situations `pc.createDataChannel()` returns `undefined` (in wrtc),
// which is invalid behavior. Handle it gracefully.
Expand Down Expand Up @@ -548,11 +558,23 @@ class Peer extends stream.Duplex {
}, CHANNEL_CLOSING_TIMEOUT)
}

_read () {}
_read () {
if(!this.enableDataChannel)
{
// Calling read without data channel is invalid, throw error.
throw errCode(new Error('Cannot read with data channel not enabled.'), 'ERR_DISABLED_DATA_CHANNEL')
}
}

_write (chunk, encoding, cb) {
if (this.destroyed) return cb(errCode(new Error('cannot write after peer is destroyed'), 'ERR_DATA_CHANNEL'))

if(!this.enableDataChannel)
{
// Calling write without data channel is invalid, throw error.
return cb(errCode(new Error('Cannot write with data channel not enabled.'), 'ERR_DISABLED_DATA_CHANNEL'))
}

if (this._connected) {
try {
this.send(chunk)
Expand Down
31 changes: 31 additions & 0 deletions test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,34 @@ test('ensure iceStateChange fires when connection failed', (t) => {
peer.destroy()
peer._pc.oniceconnectionstatechange()
})

test('ensure enableDataChannel is being respected', async (t) => {
t.plan(4)
const peer = new Peer({ config, initiator: true, wrtc: common.wrtc, enableDataChannel: false })

const onSignalPromise = new Promise((resolve,reject) => {
peer.on('signal', data => {
resolve(data);
});
});

t.throws(function(){peer.send("data")},"Sending data is not allowed with enableDataChannel set to false");
t.throws(function(){peer.write("data")},"Writing data is not allowed with enableDataChannel set to false");
t.throws(function(){peer.read()},"Reading data is not allowed with enableDataChannel set to false");

const data = await onSignalPromise;
const lines = data.sdp.split("\r\n");

// Determining whether we have found any media descriptions in SDP offer
// Since no data channel, or audio/video channel is being created, we shouldn't find any
let mLines = [];
lines.forEach(line => {
if(line.substring = "m=")
{
mLines.concat(line)
}
});
t.assert(mLines.length === 0, "No media descriptions have been created");

t.end();
})