diff --git a/README.md b/README.md index 394cea94..a8f57f05 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ # [![NPM](https://nodei.co/npm/netflux.png)](https://nodei.co/npm/netflux/) [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) -[![Join the chat at https://gitter.im/coast-team/netflux](https://badges.gitter.im/coast-team/netflux.svg?style=flat-square)](https://gitter.im/coast-team/netflux?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)  +[![Join the chat at https://gitter.im/coast-team/netflux](https://img.shields.io/badge/GITTER-join%20chat-green.svg?style=flat-square)](https://gitter.im/coast-team/netflux?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)  [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)  [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)](http://commitizen.github.io/cz-cli/)  +[![bitHound Dependencies](https://www.bithound.io/github/coast-team/netflux/badges/dependencies.svg)](https://www.bithound.io/github/coast-team/netflux/master/dependencies/npm)  +[![Dependency Status](https://david-dm.org/coast-team/netflux.svg?style=flat-square)](https://david-dm.org/coast-team/netflux)  +[![devDependency Status](https://david-dm.org/coast-team/netflux/dev-status.svg?style=flat-square)](https://david-dm.org/coast-team/netflux#info=devDependencies)  + [![Build Status](https://travis-ci.org/coast-team/netflux.svg?branch=master)](https://travis-ci.org/coast-team/netflux)  [![bitHound Overall Score](https://www.bithound.io/github/coast-team/netflux/badges/score.svg)](https://www.bithound.io/github/coast-team/netflux)  -[![bitHound Code](https://www.bithound.io/github/coast-team/netflux/badges/code.svg)](https://www.bithound.io/github/coast-team/netflux)  [![Code Climate](https://codeclimate.com/github/coast-team/netflux/badges/gpa.svg)](https://codeclimate.com/github/coast-team/netflux)  [![Test Coverage](https://codeclimate.com/github/coast-team/netflux/badges/coverage.svg)](https://codeclimate.com/github/coast-team/netflux/coverage)  -[![Inline docs](http://inch-ci.org/github/coast-team/netflux.svg?branch=master)](http://inch-ci.org/github/coast-team/netflux)  -[![devDependency Status](https://david-dm.org/coast-team/netflux/dev-status.svg)](https://david-dm.org/coast-team/netflux#info=devDependencies) +[![Inline docs](http://inch-ci.org/github/coast-team/netflux.svg?branch=master&style=flat-square)](http://inch-ci.org/github/coast-team/netflux) Abstract peer to peer client transport API. Implementations based on WebRTC and WebSocket to be done. diff --git a/config.js b/config.js index 336bb23d..4d0ab32d 100644 --- a/config.js +++ b/config.js @@ -39,7 +39,7 @@ System.config({ "fs": "github:jspm/nodelibs-fs@0.1.2", "path": "github:jspm/nodelibs-path@0.1.0", "process": "github:jspm/nodelibs-process@0.1.2", - "systemjs-json": "github:systemjs/plugin-json@0.1.1" + "systemjs-json": "github:systemjs/plugin-json@0.1.2" }, "npm:inherits@2.0.1": { "util": "github:jspm/nodelibs-util@0.1.0" diff --git a/dist/netflux.es2015.js b/dist/netflux.es2015.js index 9eed4ff9..4b0aea4a 100644 --- a/dist/netflux.es2015.js +++ b/dist/netflux.es2015.js @@ -1061,7 +1061,7 @@ * * @abstract * @param {WebChannel} wc - Web Channel from which the message is arrived. - * @param {ChannelInterface} wc - Channel by which the message is arrived. + * @param {Channel} wc - Channel by which the message is arrived. * @param {string} msg - Message in stringified JSON format. */ onMessage (wc, channel, msg) { @@ -1098,7 +1098,7 @@ * The channel between the joining peer and intermediary peer. It is null * for every peer, but the joining and intermediary peers. * - * @type {ChannelInterface} + * @type {Channel} */ this.intermediaryChannel = null @@ -1107,7 +1107,7 @@ * added to the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToAdd = [] @@ -1116,7 +1116,7 @@ * closed with the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToRemove = [] } @@ -1124,7 +1124,7 @@ /** * Add channel to `channelsToAdd` array. * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ toAddList (channel) { this.channelsToAdd[this.channelsToAdd.length] = channel @@ -1133,20 +1133,13 @@ /** * Add channel to `channelsToRemove` array * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ toRemoveList (channel) { this.channelsToAdd[this.channelsToAdd.length] = channel } } - /** - * Proxy module for configure channel event handlers and any message sent via - * a channel should be build here in order to be understand by the recepient - * peer. - * @module channelProxy - */ - /** * Constant used to build a message designated to API user. * @type {int} @@ -1203,147 +1196,134 @@ const INIT_CHANNEL_PONG = 9 /** - * This is a special service class for {@link ChannelInterface}. It mostly - * contains event handlers (e.g. *onmessage*, *onclose* etc.) to configure - * a newly created channel. Thus be careful to use `this` in handlers, as - * it will refer to the instance of `ChannelInterface` and not to the - * instance of `ChannelProxyService`. + * Channel interface. + * [RTCDataChannel]{@link https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel} + * and + * [WebSocket]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket} + * implement it implicitly. Any other channel must implement this interface. + * + * @interface */ - class ChannelProxyService extends Interface$1 { - - /** - * On message event handler. - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent} - * - * @param {MessageEvent} msgEvt - Message event - */ - onMsg (msgEvt) { - let msg = JSON.parse(msgEvt.data) - let ch = msgEvt.currentTarget - let wc = ch.webChannel - let jp - switch (msg.code) { - case USER_DATA: - wc.onMessage(msg.id, msg.data) - break - case LEAVE: - wc.onLeaving(msg.id) - for (let c of wc.channels) { - if (c.peerId === msg.id) { - wc.channels.delete(c) + class Channel { + constructor (channel, webChannel, peerId) { + this.channel = channel + this.channel.binaryType = 'arraybuffer' + this.webChannel = webChannel + this.peerId = peerId + } + + config () { + this.channel.onmessage = (msgEvt) => { + let decoder = new TextDecoder() + let i8array = new Uint8Array(msgEvt.data) + let code = i8array[0] + let msg = {} + // let msg = JSON.parse(msgEvt.data) + if (code === USER_DATA) { + let str = decoder.decode(i8array.subarray(1, i8array.length)) + this.webChannel.onMessage(this.peerId, str) + return + } else { + let str = decoder.decode(i8array.subarray(1, i8array.length)) + msg = JSON.parse(str) + } + let jp + switch (code) { + // case USER_DATA: + // this.webChannel.onMessage(msg.id, msg.data) + // break + case LEAVE: + this.webChannel.onLeaving(msg.id) + for (let c of this.webChannel.channels) { + if (c.peerId === msg.id) { + this.webChannel.channels.delete(c) + } } - } - break - case SERVICE_DATA: - if (wc.myId === msg.recepient) { - wc.proxy.onSrvMsg(wc, msg) - } else { - wc.sendSrvMsg(msg.serviceName, msg.recepient, msg.data) - } - break - case JOIN_INIT: - console.log('JOIN_INIT my new id: ' + msg.id) - wc.topology = msg.manager - wc.myId = msg.id - ch.peerId = msg.intermediaryId - jp = new JoiningPeer(msg.id, msg.intermediaryId) - jp.intermediaryChannel = ch - wc.addJoiningPeer(jp) - break - case JOIN_NEW_MEMBER: - wc.addJoiningPeer(new JoiningPeer(msg.id, msg.intermediaryId)) - break - case REMOVE_NEW_MEMBER: - wc.removeJoiningPeer(msg.id) - break - case JOIN_FINILIZE: - wc.joinSuccess(wc.myId) - let nextMsg = wc.proxy.msg(JOIN_SUCCESS, {id: wc.myId}) - wc.manager.broadcast(wc, nextMsg) - wc.onJoin() - break - case JOIN_SUCCESS: - wc.joinSuccess(msg.id) - wc.onJoining(msg.id) - break - case THIS_CHANNEL_TO_JOINING_PEER: - if (wc.hasJoiningPeer(msg.id)) { - jp = wc.getJoiningPeer(msg.id) - } else { - jp = new JoiningPeer(msg.id) - wc.addJoiningPeer(jp) - } - if (msg.toBeAdded) { - jp.toAddList(ch) - } else { - jp.toRemoveList(ch) - } - break - case INIT_CHANNEL_PONG: - ch.onPong() - delete ch.onPong - break + break + case SERVICE_DATA: + if (this.webChannel.myId === msg.recepient) { + get(msg.serviceName, this.webChannel.settings).onMessage(this.webChannel, this, msg.data) + } else { + this.webChannel.sendSrvMsg(msg.serviceName, msg.recepient, msg.data) + } + break + case JOIN_INIT: + this.webChannel.topology = msg.manager + this.webChannel.myId = msg.id + this.peerId = msg.intermediaryId + jp = new JoiningPeer(msg.id, msg.intermediaryId) + jp.intermediaryChannel = this + this.webChannel.addJoiningPeer(jp) + break + case JOIN_NEW_MEMBER: + this.webChannel.addJoiningPeer(new JoiningPeer(msg.id, msg.intermediaryId)) + break + case REMOVE_NEW_MEMBER: + this.webChannel.removeJoiningPeer(msg.id) + break + case JOIN_FINILIZE: + this.webChannel.joinSuccess(this.webChannel.myId) + this.webChannel.manager.broadcast(this.webChannel, JOIN_SUCCESS, {id: this.webChannel.myId}) + this.webChannel.onJoin() + break + case JOIN_SUCCESS: + this.webChannel.joinSuccess(msg.id) + this.webChannel.onJoining(msg.id) + break + case THIS_CHANNEL_TO_JOINING_PEER: + if (this.webChannel.hasJoiningPeer(msg.id)) { + jp = this.webChannel.getJoiningPeer(msg.id) + } else { + jp = new JoiningPeer(msg.id) + this.webChannel.addJoiningPeer(jp) + } + if (msg.toBeAdded) { + jp.toAddList(this) + } else { + jp.toRemoveList(this) + } + break + case INIT_CHANNEL_PONG: + this.onPong() + delete this.onPong + break + } + } + this.channel.onerror = (evt) => { + console.log('DATA_CHANNEL ERROR: ', evt) + } + this.channel.onclose = (evt) => { + console.log('DATA_CHANNEL CLOSE: ', evt) } } /** - * On channel close event handler. - * - For `RTCDataChannel` the type of `evt` is `Event` - * - For `WebSocket`, the type of `evt` is `CloseEvent`. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * @see [CloseEvent doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent} - * - * @param {Event} evt - Close event. - */ - onClose (evt) { - console.log('DATA_CHANNEL CLOSE: ', evt) - } - - /** - * On error event handler. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * - * @param {Event} evt - Error event. - */ - onError (evt) { - console.log('DATA_CHANNEL ERROR: ', evt) - } - - onDisconnect () { - this.webChannel.channels.delete(this) - this.webChannel.onLeaving(this.peerId) - } - - configChannel (channel) { - channel.onmessage = this.onMsg - channel.onerror = this.onError - channel.onclose = this.onClose - channel.ondisconnect = this.onDisconnect - } - - /** - * When the message is designated for a service. This is not an event handler - * for a channel. The main difference with the `SERVICE_DATA` message arriving - * for `onMessage` is that here the message could be sent by the peer to - * himself. + * send - description. * - * @param {WebChannel} wc - Web Channel. - * @param {Object} msg - Message. + * @abstract + * @param {string} msg - Message in stringified JSON format. */ - onSrvMsg (wc, msg, channel = null) { - get(msg.serviceName, wc.settings).onMessage(wc, channel, msg.data) + send (code, data = {}) { + let i8array + let msgStr = code === USER_DATA ? data : JSON.stringify(data) + let encoder = new TextEncoder() + let msgEncoded = encoder.encode(msgStr) + i8array = new Uint8Array(1 + msgEncoded.length) + i8array[0] = code + let index = 1 + for (let i in msgEncoded) { + i8array[index++] = msgEncoded[i] + } + this.channel.send(i8array) } /** - * Message builder. + * Close channel. * - * @param {int} code - One of the constant values in {@link constans}. - * @param {Object} [data={}] - Data to be send. - * @return {string} - Data in stringified JSON format. + * @abstract */ - msg (code, data = {}) { - let msg = Object.assign({code}, data) - return JSON.stringify(msg) + close () { + this.channel.close() } } @@ -1392,17 +1372,15 @@ msg.peers.forEach((id) => { cBuilder.connectMeTo(wc, id) .then((channel) => { - console.log('New channel established') - return wc.initChannel(channel, true) + return wc.initChannel(channel, true, id) }) .then((channel) => { - console.log('New channel has been initialized') wc.getJoiningPeer(msg.jpId).toAddList(channel) - channel.send(wc.proxy.msg(THIS_CHANNEL_TO_JOINING_PEER, + channel.send( + THIS_CHANNEL_TO_JOINING_PEER, {id: msg.jpId, toBeAdded: true} - )) + ) counter++ - console.log('Counter becomes: ' + counter) if (counter === msg.peers.length) { wc.sendSrvMsg(this.name, msg.sender, {code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed} @@ -1410,10 +1388,8 @@ } }) .catch((reason) => { - console.log('New channel catch error: ' + reason) counter++ - console.log('Counter becomes: ' + counter) - result.failed.push({id, reason}) + failed.push({id, reason}) if (counter === msg.peers.length) { wc.sendSrvMsg(this.name, msg.sender, {code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed} @@ -1505,7 +1481,7 @@ * Adds a new peer into Web Channel. * * @abstract - * @param {ChannelInterface} ch - Channel to be added (it should has + * @param {Channel} ch - Channel to be added (it should has * the `webChannel` property). * @return {Promise} - Resolved once the channel has been succesfully added, * rejected otherwise. @@ -1569,19 +1545,19 @@ return this.connectWith(wCh, ch.peerId, ch.peerId, peers) } - broadcast (webChannel, data) { + broadcast (webChannel, code, data) { for (let c of webChannel.channels) { if (c.readyState !== 'closed') { - c.send(data) + c.send(code, data) } } } - sendTo (id, webChannel, data) { + sendTo (id, webChannel, code, data) { for (let c of webChannel.channels) { if (c.peerId === id) { if (c.readyState !== 'closed') { - c.send(data) + c.send(code, data) } return } @@ -1596,7 +1572,7 @@ * Channel Builder module is responsible to create a connection between two * peers. * @module channelBuilder - * @see ChannelInterface + * @see Channel */ /** @@ -1604,7 +1580,7 @@ * function. * * @callback module:channelBuilder~onChannelCallback - * @param {ChannelInterface} channel - A new channel. + * @param {Channel} channel - A new channel. */ /** @@ -1613,7 +1589,7 @@ * ready to be used in the web channel. * * @callback module:channelBuilder~initChannel - * @param {ChannelInterface} ch - Channel. + * @param {Channel} ch - Channel. * @param {string} id - Unique channel identifier. */ @@ -1967,10 +1943,9 @@ createPeerConnectionAndOffer (onCandidate, sendOffer, onChannel) { let pc = this.createPeerConnection(onCandidate) let dc = pc.createDataChannel(null) - dc.ondisconnect = () => {} pc.oniceconnectionstatechange = () => { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect() + dc.onclose() } } dc.onopen = (evt) => onChannel(dc) @@ -1996,10 +1971,10 @@ let pc = this.createPeerConnection(onCandidate) pc.ondatachannel = (dcEvt) => { let dc = dcEvt.channel - dc.ondisconnect = () => {} pc.oniceconnectionstatechange = () => { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect() + console.log('Data channel has been disconnected') + dc.onclose() } } dc.onopen = (evt) => onChannel(dc) @@ -2080,12 +2055,6 @@ * @module serviceProvider */ - /** - * Constant used to get an instance of {@link ChannelProxyService}. - * @type {string} - */ - const CHANNEL_PROXY = 'ChannelProxyService' - /** * Constant used to get an instance of {@link WebRTCService}. * @type {string} @@ -2121,10 +2090,6 @@ service = new FullyConnectedService() services.set(name, service) return service - case CHANNEL_PROXY: - service = new ChannelProxyService() - services.set(name, service) - return service default: return null } @@ -2198,8 +2163,6 @@ /** @private */ this.connectWithRequests = new Map() - /** @private */ - this.proxy = get(CHANNEL_PROXY) /** @private */ this.topology = this.settings.topology } @@ -2228,9 +2191,7 @@ /** Leave `WebChannel`. No longer can receive and send messages to the group. */ leave () { - this.manager.broadcast(this, this.proxy.msg(LEAVE, - {id: this.myId} - )) + this.manager.broadcast(this, LEAVE, {id: this.myId}) } /** @@ -2239,10 +2200,7 @@ * @param {string} data Message */ send (data) { - this.manager.broadcast(this, this.proxy.msg( - USER_DATA, - {id: this.myId, data} - )) + this.manager.broadcast(this, USER_DATA, data) } /** @@ -2252,10 +2210,7 @@ * @param {type} data Message */ sendTo (id, data) { - this.manager.sendTo(id, this, this.proxy.msg( - USER_DATA, - {id: this.myId, data} - )) + this.manager.sendTo(id, this, USER_DATA, {id: this.myId, data}) } /** @@ -2271,28 +2226,27 @@ let cBuilder = get(settings.connector, settings) let key = this.id + this.myId return cBuilder.open(key, (channel) => { - this.initChannel(channel, false).then((channel) => { - let jp = new JoiningPeer(channel.peerId, this.myId) - jp.intermediaryChannel = channel - this.joiningPeers.add(jp) - channel.send(this.proxy.msg(JOIN_INIT, { - manager: this.settings.topology, - id: channel.peerId, - intermediaryId: this.myId}) - ) - this.manager.broadcast(this, this.proxy.msg(JOIN_NEW_MEMBER, { - id: channel.peerId, - intermediaryId: this.myId}) - ) - this.manager.add(channel) - .then(() => channel.send(this.proxy.msg(JOIN_FINILIZE))) - .catch((msg) => { - this.manager.broadcast(this, this.proxy.msg(REMOVE_NEW_MEMBER, { - id: channel.peerId}) - ) - this.removeJoiningPeer(jp.id) - }) - }) + this.initChannel(channel, false) + .then((channel) => { + let jp = new JoiningPeer(channel.peerId, this.myId) + jp.intermediaryChannel = channel + this.joiningPeers.add(jp) + channel.send(JOIN_INIT, { + manager: this.settings.topology, + id: channel.peerId, + intermediaryId: this.myId} + ) + this.manager.broadcast(this, JOIN_NEW_MEMBER, { + id: channel.peerId, + intermediaryId: this.myId} + ) + this.manager.add(channel) + .then(() => channel.send(JOIN_FINILIZE)) + .catch((msg) => { + this.manager.broadcast(this, REMOVE_NEW_MEMBER, {id: channel.peerId}) + this.removeJoiningPeer(jp.id) + }) + }) }).then((data) => { this.webRTCOpen = data.socket return {key: data.key, url: data.url} @@ -2364,15 +2318,14 @@ */ sendSrvMsg (serviceName, recepient, msg = {}) { let completeMsg = {serviceName, recepient, data: Object.assign({}, msg)} - let stringifiedMsg = this.proxy.msg(SERVICE_DATA, completeMsg) if (recepient === this.myId) { - this.proxy.onSrvMsg(this, completeMsg) + get(msg.serviceName, this.settings).onMessage(this, null, msg.data) } else { // If this function caller is a peer who is joining if (this.isJoining()) { let ch = this.getJoiningPeer(this.myId).intermediaryChannel if (ch.readyState !== 'closed') { - ch.send(stringifiedMsg) + ch.send(SERVICE_DATA, completeMsg) } } else { // If the recepient is a joining peer @@ -2380,14 +2333,14 @@ let jp = this.getJoiningPeer(recepient) // If I am an intermediary peer for recepient if (jp.intermediaryId === this.myId && jp.intermediaryChannel.readyState !== 'closed') { - jp.intermediaryChannel.send(stringifiedMsg) + jp.intermediaryChannel.send(SERVICE_DATA, completeMsg) // If not, then send this message to the recepient's intermediary peer } else { - this.manager.sendTo(jp.intermediaryId, this, stringifiedMsg) + this.manager.sendTo(jp.intermediaryId, this, SERVICE_DATA, completeMsg) } // If the recepient is a member of webChannel } else { - this.manager.sendTo(recepient, this, stringifiedMsg) + this.manager.sendTo(recepient, this, SERVICE_DATA, completeMsg) } } } @@ -2402,20 +2355,19 @@ return this.settings.topology } - initChannel (channel, isInitiator, id = '') { + initChannel (ch, isInitiator, id = this.generateId()) { return new Promise((resolve, reject) => { - channel.webChannel = this - channel.peerId = (id !== '') ? id : this.generateId() + let channel = new Channel(ch, this, id) // TODO: treat the case when the 'ping' or 'pong' message has not been received if (isInitiator) { - this.proxy.configChannel(channel) + channel.config() channel.onPong = () => resolve(channel) - channel.send('ping') + ch.send('ping') } else { - channel.onmessage = (msgEvt) => { + ch.onmessage = (msgEvt) => { if (msgEvt.data === 'ping') { - this.proxy.configChannel(channel) - channel.send(this.proxy.msg(INIT_CHANNEL_PONG)) + channel.config() + channel.send(INIT_CHANNEL_PONG) resolve(channel) } } diff --git a/dist/netflux.js b/dist/netflux.js index 1dcfdd16..948c6e7f 100644 --- a/dist/netflux.js +++ b/dist/netflux.js @@ -1134,7 +1134,7 @@ return /******/ (function(modules) { // webpackBootstrap var serviceProvider = _interopRequireWildcard(_serviceProvider); - var _channelProxy = __webpack_require__(7); + var _Channel = __webpack_require__(7); var _JoiningPeer = __webpack_require__(8); @@ -1220,8 +1220,6 @@ return /******/ (function(modules) { // webpackBootstrap /** @private */ this.connectWithRequests = new Map(); - /** @private */ - this.proxy = serviceProvider.get(serviceProvider.CHANNEL_PROXY); /** @private */ this.topology = this.settings.topology; } @@ -1263,7 +1261,7 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: 'leave', value: function leave() { - this.manager.broadcast(this, this.proxy.msg(_channelProxy.LEAVE, { id: this.myId })); + this.manager.broadcast(this, _Channel.LEAVE, { id: this.myId }); } /** @@ -1275,7 +1273,7 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: 'send', value: function send(data) { - this.manager.broadcast(this, this.proxy.msg(_channelProxy.USER_DATA, { id: this.myId, data: data })); + this.manager.broadcast(this, _Channel.USER_DATA, data); } /** @@ -1288,7 +1286,7 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: 'sendTo', value: function sendTo(id, data) { - this.manager.sendTo(id, this, this.proxy.msg(_channelProxy.USER_DATA, { id: this.myId, data: data })); + this.manager.sendTo(id, this, _Channel.USER_DATA, { id: this.myId, data: data }); } /** @@ -1315,18 +1313,17 @@ return /******/ (function(modules) { // webpackBootstrap var jp = new _JoiningPeer2.default(channel.peerId, _this.myId); jp.intermediaryChannel = channel; _this.joiningPeers.add(jp); - channel.send(_this.proxy.msg(_channelProxy.JOIN_INIT, { + channel.send(_Channel.JOIN_INIT, { manager: _this.settings.topology, id: channel.peerId, - intermediaryId: _this.myId })); - _this.manager.broadcast(_this, _this.proxy.msg(_channelProxy.JOIN_NEW_MEMBER, { + intermediaryId: _this.myId }); + _this.manager.broadcast(_this, _Channel.JOIN_NEW_MEMBER, { id: channel.peerId, - intermediaryId: _this.myId })); + intermediaryId: _this.myId }); _this.manager.add(channel).then(function () { - return channel.send(_this.proxy.msg(_channelProxy.JOIN_FINILIZE)); + return channel.send(_Channel.JOIN_FINILIZE); }).catch(function (msg) { - _this.manager.broadcast(_this, _this.proxy.msg(_channelProxy.REMOVE_NEW_MEMBER, { - id: channel.peerId })); + _this.manager.broadcast(_this, _Channel.REMOVE_NEW_MEMBER, { id: channel.peerId }); _this.removeJoiningPeer(jp.id); }); }); @@ -1444,15 +1441,14 @@ return /******/ (function(modules) { // webpackBootstrap var msg = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; var completeMsg = { serviceName: serviceName, recepient: recepient, data: Object.assign({}, msg) }; - var stringifiedMsg = this.proxy.msg(_channelProxy.SERVICE_DATA, completeMsg); if (recepient === this.myId) { - this.proxy.onSrvMsg(this, completeMsg); + serviceProvider.get(msg.serviceName, this.settings).onMessage(this, null, msg.data); } else { // If this function caller is a peer who is joining if (this.isJoining()) { var ch = this.getJoiningPeer(this.myId).intermediaryChannel; if (ch.readyState !== 'closed') { - ch.send(stringifiedMsg); + ch.send(_Channel.SERVICE_DATA, completeMsg); } } else { // If the recepient is a joining peer @@ -1460,40 +1456,39 @@ return /******/ (function(modules) { // webpackBootstrap var jp = this.getJoiningPeer(recepient); // If I am an intermediary peer for recepient if (jp.intermediaryId === this.myId && jp.intermediaryChannel.readyState !== 'closed') { - jp.intermediaryChannel.send(stringifiedMsg); + jp.intermediaryChannel.send(_Channel.SERVICE_DATA, completeMsg); // If not, then send this message to the recepient's intermediary peer } else { - this.manager.sendTo(jp.intermediaryId, this, stringifiedMsg); + this.manager.sendTo(jp.intermediaryId, this, _Channel.SERVICE_DATA, completeMsg); } // If the recepient is a member of webChannel } else { - this.manager.sendTo(recepient, this, stringifiedMsg); + this.manager.sendTo(recepient, this, _Channel.SERVICE_DATA, completeMsg); } } } } }, { key: 'initChannel', - value: function initChannel(channel, isInitiator) { + value: function initChannel(ch, isInitiator) { var _this3 = this; - var id = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2]; + var id = arguments.length <= 2 || arguments[2] === undefined ? this.generateId() : arguments[2]; return new Promise(function (resolve, reject) { - channel.webChannel = _this3; - channel.peerId = id !== '' ? id : _this3.generateId(); + var channel = new _Channel.Channel(ch, _this3, id); // TODO: treat the case when the 'ping' or 'pong' message has not been received if (isInitiator) { - _this3.proxy.configChannel(channel); + channel.config(); channel.onPong = function () { return resolve(channel); }; - channel.send('ping'); + ch.send('ping'); } else { - channel.onmessage = function (msgEvt) { + ch.onmessage = function (msgEvt) { if (msgEvt.data === 'ping') { - _this3.proxy.configChannel(channel); - channel.send(_this3.proxy.msg(_channelProxy.INIT_CHANNEL_PONG)); + channel.config(); + channel.send(_Channel.INIT_CHANNEL_PONG); resolve(channel); } }; @@ -1722,7 +1717,7 @@ return /******/ (function(modules) { // webpackBootstrap Object.defineProperty(exports, "__esModule", { value: true }); - exports.FULLY_CONNECTED = exports.WEBRTC = exports.CHANNEL_PROXY = undefined; + exports.FULLY_CONNECTED = exports.WEBRTC = undefined; exports.get = get; var _FullyConnectedService = __webpack_require__(4); @@ -1733,8 +1728,6 @@ return /******/ (function(modules) { // webpackBootstrap var _WebRTCService2 = _interopRequireDefault(_WebRTCService); - var _channelProxy = __webpack_require__(7); - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** @@ -1744,12 +1737,6 @@ return /******/ (function(modules) { // webpackBootstrap * @module serviceProvider */ - /** - * Constant used to get an instance of {@link ChannelProxyService}. - * @type {string} - */ - var CHANNEL_PROXY = exports.CHANNEL_PROXY = 'ChannelProxyService'; - /** * Constant used to get an instance of {@link WebRTCService}. * @type {string} @@ -1787,10 +1774,6 @@ return /******/ (function(modules) { // webpackBootstrap service = new _FullyConnectedService2.default(); services.set(name, service); return service; - case CHANNEL_PROXY: - service = new _channelProxy.ChannelProxyService(); - services.set(name, service); - return service; default: return null; } @@ -1853,7 +1836,7 @@ return /******/ (function(modules) { // webpackBootstrap } }, { key: 'broadcast', - value: function broadcast(webChannel, data) { + value: function broadcast(webChannel, code, data) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; @@ -1863,7 +1846,7 @@ return /******/ (function(modules) { // webpackBootstrap var c = _step.value; if (c.readyState !== 'closed') { - c.send(data); + c.send(code, data); } } } catch (err) { @@ -1883,7 +1866,7 @@ return /******/ (function(modules) { // webpackBootstrap } }, { key: 'sendTo', - value: function sendTo(id, webChannel, data) { + value: function sendTo(id, webChannel, code, data) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; @@ -1894,7 +1877,7 @@ return /******/ (function(modules) { // webpackBootstrap if (c.peerId === id) { if (c.readyState !== 'closed') { - c.send(data); + c.send(code, data); } return; } @@ -1945,7 +1928,7 @@ return /******/ (function(modules) { // webpackBootstrap var serviceProvider = _interopRequireWildcard(_serviceProvider); - var _channelProxy = __webpack_require__(7); + var _Channel = __webpack_require__(7); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } @@ -2011,22 +1994,17 @@ return /******/ (function(modules) { // webpackBootstrap var counter = 0; msg.peers.forEach(function (id) { cBuilder.connectMeTo(wc, id).then(function (channel) { - console.log('New channel established'); - return wc.initChannel(channel, true); + return wc.initChannel(channel, true, id); }).then(function (channel) { - console.log('New channel has been initialized'); wc.getJoiningPeer(msg.jpId).toAddList(channel); - channel.send(wc.proxy.msg(_channelProxy.THIS_CHANNEL_TO_JOINING_PEER, { id: msg.jpId, toBeAdded: true })); + channel.send(_Channel.THIS_CHANNEL_TO_JOINING_PEER, { id: msg.jpId, toBeAdded: true }); counter++; - console.log('Counter becomes: ' + counter); if (counter === msg.peers.length) { wc.sendSrvMsg(_this2.name, msg.sender, { code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed: failed }); } }).catch(function (reason) { - console.log('New channel catch error: ' + reason); counter++; - console.log('Counter becomes: ' + counter); - result.failed.push({ id: id, reason: reason }); + failed.push({ id: id, reason: reason }); if (counter === msg.peers.length) { wc.sendSrvMsg(_this2.name, msg.sender, { code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed: failed }); } @@ -2122,7 +2100,7 @@ return /******/ (function(modules) { // webpackBootstrap * Adds a new peer into Web Channel. * * @abstract - * @param {ChannelInterface} ch - Channel to be added (it should has + * @param {Channel} ch - Channel to be added (it should has * the `webChannel` property). * @return {Promise} - Resolved once the channel has been succesfully added, * rejected otherwise. @@ -2231,7 +2209,7 @@ return /******/ (function(modules) { // webpackBootstrap * * @abstract * @param {WebChannel} wc - Web Channel from which the message is arrived. - * @param {ChannelInterface} wc - Channel by which the message is arrived. + * @param {Channel} wc - Channel by which the message is arrived. * @param {string} msg - Message in stringified JSON format. */ value: function onMessage(wc, channel, msg) { @@ -2267,14 +2245,10 @@ return /******/ (function(modules) { // webpackBootstrap Object.defineProperty(exports, "__esModule", { value: true }); - exports.ChannelProxyService = exports.INIT_CHANNEL_PONG = exports.THIS_CHANNEL_TO_JOINING_PEER = exports.JOIN_SUCCESS = exports.JOIN_FINILIZE = exports.REMOVE_NEW_MEMBER = exports.JOIN_NEW_MEMBER = exports.JOIN_INIT = exports.LEAVE = exports.SERVICE_DATA = exports.USER_DATA = undefined; + exports.Channel = exports.INIT_CHANNEL_PONG = exports.THIS_CHANNEL_TO_JOINING_PEER = exports.JOIN_SUCCESS = exports.JOIN_FINILIZE = exports.REMOVE_NEW_MEMBER = exports.JOIN_NEW_MEMBER = exports.JOIN_INIT = exports.LEAVE = exports.SERVICE_DATA = exports.USER_DATA = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - var _service = __webpack_require__(6); - - var service = _interopRequireWildcard(_service); - var _serviceProvider = __webpack_require__(3); var serviceProvider = _interopRequireWildcard(_serviceProvider); @@ -2289,17 +2263,6 @@ return /******/ (function(modules) { // webpackBootstrap function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - - function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - /** - * Proxy module for configure channel event handlers and any message sent via - * a channel should be build here in order to be understand by the recepient - * peer. - * @module channelProxy - */ - /** * Constant used to build a message designated to API user. * @type {int} @@ -2356,208 +2319,178 @@ return /******/ (function(modules) { // webpackBootstrap var INIT_CHANNEL_PONG = exports.INIT_CHANNEL_PONG = 9; /** - * This is a special service class for {@link ChannelInterface}. It mostly - * contains event handlers (e.g. *onmessage*, *onclose* etc.) to configure - * a newly created channel. Thus be careful to use `this` in handlers, as - * it will refer to the instance of `ChannelInterface` and not to the - * instance of `ChannelProxyService`. + * Channel interface. + * [RTCDataChannel]{@link https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel} + * and + * [WebSocket]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket} + * implement it implicitly. Any other channel must implement this interface. + * + * @interface */ - var ChannelProxyService = function (_service$Interface) { - _inherits(ChannelProxyService, _service$Interface); - - function ChannelProxyService() { - _classCallCheck(this, ChannelProxyService); + var Channel = function () { + function Channel(channel, webChannel, peerId) { + _classCallCheck(this, Channel); - return _possibleConstructorReturn(this, Object.getPrototypeOf(ChannelProxyService).apply(this, arguments)); + this.channel = channel; + this.channel.binaryType = 'arraybuffer'; + this.webChannel = webChannel; + this.peerId = peerId; } - _createClass(ChannelProxyService, [{ - key: 'onMsg', - - - /** - * On message event handler. - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent} - * - * @param {MessageEvent} msgEvt - Message event - */ - value: function onMsg(msgEvt) { - var msg = JSON.parse(msgEvt.data); - var ch = msgEvt.currentTarget; - var wc = ch.webChannel; - var jp = void 0; - switch (msg.code) { - case USER_DATA: - wc.onMessage(msg.id, msg.data); - break; - case LEAVE: - wc.onLeaving(msg.id); - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; + _createClass(Channel, [{ + key: 'config', + value: function config() { + var _this = this; - try { - for (var _iterator = wc.channels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var c = _step.value; + this.channel.onmessage = function (msgEvt) { + var decoder = new TextDecoder(); + var i8array = new Uint8Array(msgEvt.data); + var code = i8array[0]; + var msg = {}; + // let msg = JSON.parse(msgEvt.data) + if (code === USER_DATA) { + var str = decoder.decode(i8array.subarray(1, i8array.length)); + _this.webChannel.onMessage(_this.peerId, str); + return; + } else { + var _str = decoder.decode(i8array.subarray(1, i8array.length)); + msg = JSON.parse(_str); + } + var jp = void 0; + switch (code) { + // case USER_DATA: + // this.webChannel.onMessage(msg.id, msg.data) + // break + case LEAVE: + _this.webChannel.onLeaving(msg.id); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; - if (c.peerId === msg.id) { - wc.channels.delete(c); - } - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); + for (var _iterator = _this.webChannel.channels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var c = _step.value; + + if (c.peerId === msg.id) { + _this.webChannel.channels.delete(c); + } } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; } finally { - if (_didIteratorError) { - throw _iteratorError; + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } } } - } - - break; - case SERVICE_DATA: - if (wc.myId === msg.recepient) { - wc.proxy.onSrvMsg(wc, msg); - } else { - wc.sendSrvMsg(msg.serviceName, msg.recepient, msg.data); - } - break; - case JOIN_INIT: - console.log('JOIN_INIT my new id: ' + msg.id); - wc.topology = msg.manager; - wc.myId = msg.id; - ch.peerId = msg.intermediaryId; - jp = new _JoiningPeer2.default(msg.id, msg.intermediaryId); - jp.intermediaryChannel = ch; - wc.addJoiningPeer(jp); - break; - case JOIN_NEW_MEMBER: - wc.addJoiningPeer(new _JoiningPeer2.default(msg.id, msg.intermediaryId)); - break; - case REMOVE_NEW_MEMBER: - wc.removeJoiningPeer(msg.id); - break; - case JOIN_FINILIZE: - wc.joinSuccess(wc.myId); - var nextMsg = wc.proxy.msg(JOIN_SUCCESS, { id: wc.myId }); - wc.manager.broadcast(wc, nextMsg); - wc.onJoin(); - break; - case JOIN_SUCCESS: - wc.joinSuccess(msg.id); - wc.onJoining(msg.id); - break; - case THIS_CHANNEL_TO_JOINING_PEER: - if (wc.hasJoiningPeer(msg.id)) { - jp = wc.getJoiningPeer(msg.id); - } else { - jp = new _JoiningPeer2.default(msg.id); - wc.addJoiningPeer(jp); - } - if (msg.toBeAdded) { - jp.toAddList(ch); - } else { - jp.toRemoveList(ch); - } - break; - case INIT_CHANNEL_PONG: - ch.onPong(); - delete ch.onPong; - break; - } - } - /** - * On channel close event handler. - * - For `RTCDataChannel` the type of `evt` is `Event` - * - For `WebSocket`, the type of `evt` is `CloseEvent`. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * @see [CloseEvent doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent} - * - * @param {Event} evt - Close event. - */ - - }, { - key: 'onClose', - value: function onClose(evt) { - console.log('DATA_CHANNEL CLOSE: ', evt); - } - - /** - * On error event handler. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * - * @param {Event} evt - Error event. - */ - - }, { - key: 'onError', - value: function onError(evt) { - console.log('DATA_CHANNEL ERROR: ', evt); - } - }, { - key: 'onDisconnect', - value: function onDisconnect() { - this.webChannel.channels.delete(this); - this.webChannel.onLeaving(this.peerId); - } - }, { - key: 'configChannel', - value: function configChannel(channel) { - channel.onmessage = this.onMsg; - channel.onerror = this.onError; - channel.onclose = this.onClose; - channel.ondisconnect = this.onDisconnect; + break; + case SERVICE_DATA: + if (_this.webChannel.myId === msg.recepient) { + serviceProvider.get(msg.serviceName, _this.webChannel.settings).onMessage(_this.webChannel, _this, msg.data); + } else { + _this.webChannel.sendSrvMsg(msg.serviceName, msg.recepient, msg.data); + } + break; + case JOIN_INIT: + _this.webChannel.topology = msg.manager; + _this.webChannel.myId = msg.id; + _this.peerId = msg.intermediaryId; + jp = new _JoiningPeer2.default(msg.id, msg.intermediaryId); + jp.intermediaryChannel = _this; + _this.webChannel.addJoiningPeer(jp); + break; + case JOIN_NEW_MEMBER: + _this.webChannel.addJoiningPeer(new _JoiningPeer2.default(msg.id, msg.intermediaryId)); + break; + case REMOVE_NEW_MEMBER: + _this.webChannel.removeJoiningPeer(msg.id); + break; + case JOIN_FINILIZE: + _this.webChannel.joinSuccess(_this.webChannel.myId); + _this.webChannel.manager.broadcast(_this.webChannel, JOIN_SUCCESS, { id: _this.webChannel.myId }); + _this.webChannel.onJoin(); + break; + case JOIN_SUCCESS: + _this.webChannel.joinSuccess(msg.id); + _this.webChannel.onJoining(msg.id); + break; + case THIS_CHANNEL_TO_JOINING_PEER: + if (_this.webChannel.hasJoiningPeer(msg.id)) { + jp = _this.webChannel.getJoiningPeer(msg.id); + } else { + jp = new _JoiningPeer2.default(msg.id); + _this.webChannel.addJoiningPeer(jp); + } + if (msg.toBeAdded) { + jp.toAddList(_this); + } else { + jp.toRemoveList(_this); + } + break; + case INIT_CHANNEL_PONG: + _this.onPong(); + delete _this.onPong; + break; + } + }; + this.channel.onerror = function (evt) { + console.log('DATA_CHANNEL ERROR: ', evt); + }; + this.channel.onclose = function (evt) { + console.log('DATA_CHANNEL CLOSE: ', evt); + }; } /** - * When the message is designated for a service. This is not an event handler - * for a channel. The main difference with the `SERVICE_DATA` message arriving - * for `onMessage` is that here the message could be sent by the peer to - * himself. + * send - description. * - * @param {WebChannel} wc - Web Channel. - * @param {Object} msg - Message. + * @abstract + * @param {string} msg - Message in stringified JSON format. */ }, { - key: 'onSrvMsg', - value: function onSrvMsg(wc, msg) { - var channel = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; + key: 'send', + value: function send(code) { + var data = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - serviceProvider.get(msg.serviceName, wc.settings).onMessage(wc, channel, msg.data); + var i8array = void 0; + var msgStr = code === USER_DATA ? data : JSON.stringify(data); + var encoder = new TextEncoder(); + var msgEncoded = encoder.encode(msgStr); + i8array = new Uint8Array(1 + msgEncoded.length); + i8array[0] = code; + var index = 1; + for (var i in msgEncoded) { + i8array[index++] = msgEncoded[i]; + } + this.channel.send(i8array); } /** - * Message builder. + * Close channel. * - * @param {int} code - One of the constant values in {@link constans}. - * @param {Object} [data={}] - Data to be send. - * @return {string} - Data in stringified JSON format. + * @abstract */ }, { - key: 'msg', - value: function msg(code) { - var data = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var msg = Object.assign({ code: code }, data); - return JSON.stringify(msg); + key: 'close', + value: function close() { + this.channel.close(); } }]); - return ChannelProxyService; - }(service.Interface); + return Channel; + }(); - exports. - /** @see module:channelProxy~ChannelProxyService */ - ChannelProxyService = ChannelProxyService; + exports.Channel = Channel; /***/ }, /* 8 */ @@ -2605,7 +2538,7 @@ return /******/ (function(modules) { // webpackBootstrap * The channel between the joining peer and intermediary peer. It is null * for every peer, but the joining and intermediary peers. * - * @type {ChannelInterface} + * @type {Channel} */ this.intermediaryChannel = null; @@ -2614,7 +2547,7 @@ return /******/ (function(modules) { // webpackBootstrap * added to the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToAdd = []; @@ -2623,7 +2556,7 @@ return /******/ (function(modules) { // webpackBootstrap * closed with the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToRemove = []; } @@ -2631,7 +2564,7 @@ return /******/ (function(modules) { // webpackBootstrap /** * Add channel to `channelsToAdd` array. * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ @@ -2644,7 +2577,7 @@ return /******/ (function(modules) { // webpackBootstrap /** * Add channel to `channelsToRemove` array * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ }, { @@ -3049,10 +2982,9 @@ return /******/ (function(modules) { // webpackBootstrap value: function createPeerConnectionAndOffer(onCandidate, sendOffer, onChannel) { var pc = this.createPeerConnection(onCandidate); var dc = pc.createDataChannel(null); - dc.ondisconnect = function () {}; pc.oniceconnectionstatechange = function () { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect(); + dc.onclose(); } }; dc.onopen = function (evt) { @@ -3083,10 +3015,10 @@ return /******/ (function(modules) { // webpackBootstrap var pc = this.createPeerConnection(onCandidate); pc.ondatachannel = function (dcEvt) { var dc = dcEvt.channel; - dc.ondisconnect = function () {}; pc.oniceconnectionstatechange = function () { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect(); + console.log('Data channel has been disconnected'); + dc.onclose(); } }; dc.onopen = function (evt) { @@ -3207,7 +3139,7 @@ return /******/ (function(modules) { // webpackBootstrap * Channel Builder module is responsible to create a connection between two * peers. * @module channelBuilder - * @see ChannelInterface + * @see Channel */ /** @@ -3215,7 +3147,7 @@ return /******/ (function(modules) { // webpackBootstrap * function. * * @callback module:channelBuilder~onChannelCallback - * @param {ChannelInterface} channel - A new channel. + * @param {Channel} channel - A new channel. */ /** @@ -3224,7 +3156,7 @@ return /******/ (function(modules) { // webpackBootstrap * ready to be used in the web channel. * * @callback module:channelBuilder~initChannel - * @param {ChannelInterface} ch - Channel. + * @param {Channel} ch - Channel. * @param {string} id - Unique channel identifier. */ diff --git a/dist/netflux.min.js b/dist/netflux.min.js index 526f367c..ef58d8ae 100644 --- a/dist/netflux.min.js +++ b/dist/netflux.min.js @@ -1,2 +1,2 @@ -!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.nf=n():e.nf=n()}(this,function(){return function(e){function n(r){if(t[r])return t[r].exports;var i=t[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,n),i.loaded=!0,i.exports}var t={};return n.m=e,n.c=t,n.p="",n(0)}([function(e,n,t){"use strict";function r(e){if(e&&e.__esModule)return e;var n={};if(null!=e)for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]=e[t]);return n["default"]=e,n}function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(n,"__esModule",{value:!0}),n.WebChannel=n.FULLY_CONNECTED=n.WEBRTC=void 0,t(1);var o=t(2),a=i(o),s=t(3),c=r(s),u=c.WEBRTC,d=c.FULLY_CONNECTED;n.WEBRTC=u,n.FULLY_CONNECTED=d,n.WebChannel=a["default"]},function(e,n,t){var r,r;!function i(e,n,t){function o(s,c){if(!n[s]){if(!e[s]){var u="function"==typeof r&&r;if(!c&&u)return r(s,!0);if(a)return a(s,!0);var d=new Error("Cannot find module '"+s+"'");throw d.code="MODULE_NOT_FOUND",d}var f=n[s]={exports:{}};e[s][0].call(f.exports,function(n){var t=e[s][1][n];return o(t?t:n)},f,f.exports,i,e,n,t)}return n[s].exports}for(var a="function"==typeof r&&r,s=0;s0&&"function"==typeof e)return i(e,n);var a=function(e){var n={},t=e.result();return t.forEach(function(e){var t={id:e.id,timestamp:e.timestamp,type:e.type};e.names().forEach(function(n){t[n]=e.stat(n)}),n[t.id]=t}),n};if(arguments.length>=2){var s=function(e){o[1](a(e))};return i.apply(this,[s,arguments[0]])}return new Promise(function(n,t){1===o.length&&"object"==typeof e?i.apply(r,[function(e){n.apply(null,[a(e)])},t]):i.apply(r,[n,t])})},t},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(e){var n=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var e=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var t=1===arguments.length?arguments[0]:void 0;return new Promise(function(r,i){n.apply(e,[r,i,t])})}return n.apply(this,arguments)}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(e){var n=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var t=arguments,r=this;return t[0]=new("addIceCandidate"===e?RTCIceCandidate:RTCSessionDescription)(t[0]),new Promise(function(e,i){n.apply(r,[t[0],function(){e(),t.length>=2&&t[1].apply(null,[])},function(e){i(e),t.length>=3&&t[2].apply(null,[e])}])})}})},attachMediaStream:function(e,n){r("DEPRECATED, attachMediaStream will soon be removed."),i.version>=43?e.srcObject=n:"undefined"!=typeof e.src?e.src=URL.createObjectURL(n):r("Error attaching stream to element.")},reattachMediaStream:function(e,n){r("DEPRECATED, reattachMediaStream will soon be removed."),i.version>=43?e.srcObject=n.srcObject:e.src=n.src}};n.exports={shimOnTrack:o.shimOnTrack,shimSourceObject:o.shimSourceObject,shimPeerConnection:o.shimPeerConnection,shimGetUserMedia:e("./getusermedia"),attachMediaStream:o.attachMediaStream,reattachMediaStream:o.reattachMediaStream}},{"../utils.js":8,"./getusermedia":4}],4:[function(e,n,t){"use strict";var r=e("../utils.js").log;n.exports=function(){var e=function(e){if("object"!=typeof e||e.mandatory||e.optional)return e;var n={};return Object.keys(e).forEach(function(t){if("require"!==t&&"advanced"!==t&&"mediaSource"!==t){var r="object"==typeof e[t]?e[t]:{ideal:e[t]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var i=function(e,n){return e?e+n.charAt(0).toUpperCase()+n.slice(1):"deviceId"===n?"sourceId":n};if(void 0!==r.ideal){n.optional=n.optional||[];var o={};"number"==typeof r.ideal?(o[i("min",t)]=r.ideal,n.optional.push(o),o={},o[i("max",t)]=r.ideal,n.optional.push(o)):(o[i("",t)]=r.ideal,n.optional.push(o))}void 0!==r.exact&&"number"!=typeof r.exact?(n.mandatory=n.mandatory||{},n.mandatory[i("",t)]=r.exact):["min","max"].forEach(function(e){void 0!==r[e]&&(n.mandatory=n.mandatory||{},n.mandatory[i(e,t)]=r[e])})}}),e.advanced&&(n.optional=(n.optional||[]).concat(e.advanced)),n},n=function(n,t,i){return n=JSON.parse(JSON.stringify(n)),n.audio&&(n.audio=e(n.audio)),n.video&&(n.video=e(n.video)),r("chrome: "+JSON.stringify(n)),navigator.webkitGetUserMedia(n,t,i)};navigator.getUserMedia=n;var t=function(e){return new Promise(function(n,t){navigator.getUserMedia(e,n,t)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:t,enumerateDevices:function(){return new Promise(function(e){var n={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(t){e(t.map(function(e){return{label:e.label,kind:n[e.kind],deviceId:e.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var i=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(n){return n&&(r("spec: "+JSON.stringify(n)),n.audio=e(n.audio),n.video=e(n.video),r("chrome: "+JSON.stringify(n))),i(n)}.bind(this)}else navigator.mediaDevices.getUserMedia=function(e){return t(e)};"undefined"==typeof navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){r("Dummy mediaDevices.addEventListener called.")}),"undefined"==typeof navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){r("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":8}],5:[function(e,n,t){"use strict";var r=e("../utils").log,i=e("../utils").browserDetails,o={shimOnTrack:function(){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(e){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=e),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(n){var t=new Event("track");t.track=n,t.receiver={track:n},t.streams=[e.stream],this.dispatchEvent(t)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(e){this.mozSrcObject=e}}))},shimPeerConnection:function(){window.RTCPeerConnection||(window.RTCPeerConnection=function(e,n){if(i.version<38&&e&&e.iceServers){for(var t=[],r=0;r=t&&parseInt(r[t],10)},detectBrowser:function(){var e={};if(e.browser=null,e.version=null,e.minVersion=null,"undefined"==typeof window||!window.navigator)return e.browser="Not a browser.",e;if(navigator.mozGetUserMedia)e.browser="firefox",e.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1),e.minVersion=31;else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)e.browser="chrome",e.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,2),e.minVersion=38;else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return e.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",e;e.browser="safari",e.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/([0-9]+)\./,1),e.minVersion=602}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return e.browser="Not a supported browser.",e;e.browser="edge",e.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2),e.minVersion=10547}return e.versiono;o++)r+=t[Math.round(Math.random()*(t.length-1))];return r}},{key:"topology",set:function(e){this.settings.topology=e,this.manager=c.get(this.settings.topology)},get:function(){return this.settings.topology}}]),e}();n["default"]=l},function(e,n,t){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function i(e){var n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if(h.has(e))return h.get(e);var t=void 0;switch(e){case f:return new c["default"](n);case l:return t=new a["default"],h.set(e,t),t;case d:return t=new u.ChannelProxyService,h.set(e,t),t;default:return null}}Object.defineProperty(n,"__esModule",{value:!0}),n.FULLY_CONNECTED=n.WEBRTC=n.CHANNEL_PROXY=void 0,n.get=i;var o=t(4),a=r(o),s=t(9),c=r(s),u=t(7),d=n.CHANNEL_PROXY="ChannelProxyService",f=n.WEBRTC="WebRTCService",l=n.FULLY_CONNECTED="FullyConnectedService",h=new Map},function(e,n,t){"use strict";function r(e){if(e&&e.__esModule)return e;var n={};if(null!=e)for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]=e[t]);return n["default"]=e,n}function i(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}function o(e,n){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!n||"object"!=typeof n&&"function"!=typeof n?e:n}function a(e,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+typeof n);e.prototype=Object.create(n&&n.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),n&&(Object.setPrototypeOf?Object.setPrototypeOf(e,n):e.__proto__=n)}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,n){for(var t=0;t0?p+Math.log10(e):p}},{key:"reUseIntermediaryChannelIfPossible",value:function(e,n,t){var r=null,i=void 0;return e.isJoining()?(i=e.getJoiningPeer(n),-1!==t.indexOf(i.intermediaryId)&&(r=i.intermediaryId)):-1!==t.indexOf(n)&&(i=e.getJoiningPeer(n),null!==i.intermediaryChannel&&(r=n)),null!==r&&(i.toAddList(i.intermediaryChannel),e.sendSrvMsg(this.name,r,{code:m,jpId:n}),t.splice(t.indexOf(r),1)),t}},{key:"add",value:function(e){throw new Error("Must be implemented by subclass!")}},{key:"broadcast",value:function(e,n){throw new Error("Must be implemented by subclass!")}},{key:"sendTo",value:function(e,n,t){throw new Error("Must be implemented by subclass!")}},{key:"leave",value:function(e){throw new Error("Must be implemented by subclass!")}}]),n}(u.Interface);n.Interface=g},function(e,n){"use strict";function t(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,n){for(var t=0;t0&&"function"==typeof e)return i(e,n);var a=function(e){var n={},t=e.result();return t.forEach(function(e){var t={id:e.id,timestamp:e.timestamp,type:e.type};e.names().forEach(function(n){t[n]=e.stat(n)}),n[t.id]=t}),n};if(arguments.length>=2){var s=function(e){o[1](a(e))};return i.apply(this,[s,arguments[0]])}return new Promise(function(n,t){1===o.length&&"object"==typeof e?i.apply(r,[function(e){n.apply(null,[a(e)])},t]):i.apply(r,[n,t])})},t},window.RTCPeerConnection.prototype=webkitRTCPeerConnection.prototype,webkitRTCPeerConnection.generateCertificate&&Object.defineProperty(window.RTCPeerConnection,"generateCertificate",{get:function(){return webkitRTCPeerConnection.generateCertificate}}),["createOffer","createAnswer"].forEach(function(e){var n=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var e=this;if(arguments.length<1||1===arguments.length&&"object"==typeof arguments[0]){var t=1===arguments.length?arguments[0]:void 0;return new Promise(function(r,i){n.apply(e,[r,i,t])})}return n.apply(this,arguments)}}),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(e){var n=webkitRTCPeerConnection.prototype[e];webkitRTCPeerConnection.prototype[e]=function(){var t=arguments,r=this;return t[0]=new("addIceCandidate"===e?RTCIceCandidate:RTCSessionDescription)(t[0]),new Promise(function(e,i){n.apply(r,[t[0],function(){e(),t.length>=2&&t[1].apply(null,[])},function(e){i(e),t.length>=3&&t[2].apply(null,[e])}])})}})},attachMediaStream:function(e,n){r("DEPRECATED, attachMediaStream will soon be removed."),i.version>=43?e.srcObject=n:"undefined"!=typeof e.src?e.src=URL.createObjectURL(n):r("Error attaching stream to element.")},reattachMediaStream:function(e,n){r("DEPRECATED, reattachMediaStream will soon be removed."),i.version>=43?e.srcObject=n.srcObject:e.src=n.src}};n.exports={shimOnTrack:o.shimOnTrack,shimSourceObject:o.shimSourceObject,shimPeerConnection:o.shimPeerConnection,shimGetUserMedia:e("./getusermedia"),attachMediaStream:o.attachMediaStream,reattachMediaStream:o.reattachMediaStream}},{"../utils.js":8,"./getusermedia":4}],4:[function(e,n,t){"use strict";var r=e("../utils.js").log;n.exports=function(){var e=function(e){if("object"!=typeof e||e.mandatory||e.optional)return e;var n={};return Object.keys(e).forEach(function(t){if("require"!==t&&"advanced"!==t&&"mediaSource"!==t){var r="object"==typeof e[t]?e[t]:{ideal:e[t]};void 0!==r.exact&&"number"==typeof r.exact&&(r.min=r.max=r.exact);var i=function(e,n){return e?e+n.charAt(0).toUpperCase()+n.slice(1):"deviceId"===n?"sourceId":n};if(void 0!==r.ideal){n.optional=n.optional||[];var o={};"number"==typeof r.ideal?(o[i("min",t)]=r.ideal,n.optional.push(o),o={},o[i("max",t)]=r.ideal,n.optional.push(o)):(o[i("",t)]=r.ideal,n.optional.push(o))}void 0!==r.exact&&"number"!=typeof r.exact?(n.mandatory=n.mandatory||{},n.mandatory[i("",t)]=r.exact):["min","max"].forEach(function(e){void 0!==r[e]&&(n.mandatory=n.mandatory||{},n.mandatory[i(e,t)]=r[e])})}}),e.advanced&&(n.optional=(n.optional||[]).concat(e.advanced)),n},n=function(n,t,i){return n=JSON.parse(JSON.stringify(n)),n.audio&&(n.audio=e(n.audio)),n.video&&(n.video=e(n.video)),r("chrome: "+JSON.stringify(n)),navigator.webkitGetUserMedia(n,t,i)};navigator.getUserMedia=n;var t=function(e){return new Promise(function(n,t){navigator.getUserMedia(e,n,t)})};if(navigator.mediaDevices||(navigator.mediaDevices={getUserMedia:t,enumerateDevices:function(){return new Promise(function(e){var n={audio:"audioinput",video:"videoinput"};return MediaStreamTrack.getSources(function(t){e(t.map(function(e){return{label:e.label,kind:n[e.kind],deviceId:e.id,groupId:""}}))})})}}),navigator.mediaDevices.getUserMedia){var i=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(n){return n&&(r("spec: "+JSON.stringify(n)),n.audio=e(n.audio),n.video=e(n.video),r("chrome: "+JSON.stringify(n))),i(n)}.bind(this)}else navigator.mediaDevices.getUserMedia=function(e){return t(e)};"undefined"==typeof navigator.mediaDevices.addEventListener&&(navigator.mediaDevices.addEventListener=function(){r("Dummy mediaDevices.addEventListener called.")}),"undefined"==typeof navigator.mediaDevices.removeEventListener&&(navigator.mediaDevices.removeEventListener=function(){r("Dummy mediaDevices.removeEventListener called.")})}},{"../utils.js":8}],5:[function(e,n,t){"use strict";var r=e("../utils").log,i=e("../utils").browserDetails,o={shimOnTrack:function(){"object"!=typeof window||!window.RTCPeerConnection||"ontrack"in window.RTCPeerConnection.prototype||Object.defineProperty(window.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(e){this._ontrack&&(this.removeEventListener("track",this._ontrack),this.removeEventListener("addstream",this._ontrackpoly)),this.addEventListener("track",this._ontrack=e),this.addEventListener("addstream",this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(n){var t=new Event("track");t.track=n,t.receiver={track:n},t.streams=[e.stream],this.dispatchEvent(t)}.bind(this))}.bind(this))}})},shimSourceObject:function(){"object"==typeof window&&(!window.HTMLMediaElement||"srcObject"in window.HTMLMediaElement.prototype||Object.defineProperty(window.HTMLMediaElement.prototype,"srcObject",{get:function(){return this.mozSrcObject},set:function(e){this.mozSrcObject=e}}))},shimPeerConnection:function(){window.RTCPeerConnection||(window.RTCPeerConnection=function(e,n){if(i.version<38&&e&&e.iceServers){for(var t=[],r=0;r=t&&parseInt(r[t],10)},detectBrowser:function(){var e={};if(e.browser=null,e.version=null,e.minVersion=null,"undefined"==typeof window||!window.navigator)return e.browser="Not a browser.",e;if(navigator.mozGetUserMedia)e.browser="firefox",e.version=this.extractVersion(navigator.userAgent,/Firefox\/([0-9]+)\./,1),e.minVersion=31;else if(navigator.webkitGetUserMedia)if(window.webkitRTCPeerConnection)e.browser="chrome",e.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/([0-9]+)\./,2),e.minVersion=38;else{if(!navigator.userAgent.match(/Version\/(\d+).(\d+)/))return e.browser="Unsupported webkit-based browser with GUM support but no WebRTC support.",e;e.browser="safari",e.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/([0-9]+)\./,1),e.minVersion=602}else{if(!navigator.mediaDevices||!navigator.userAgent.match(/Edge\/(\d+).(\d+)$/))return e.browser="Not a supported browser.",e;e.browser="edge",e.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2),e.minVersion=10547}return e.versiono;o++)r+=t[Math.round(Math.random()*(t.length-1))];return r}},{key:"topology",set:function(e){this.settings.topology=e,this.manager=c.get(this.settings.topology)},get:function(){return this.settings.topology}}]),e}();n["default"]=f},function(e,n,t){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function i(e){var n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if(l.has(e))return l.get(e);var t=void 0;switch(e){case u:return new c["default"](n);case d:return t=new a["default"],l.set(e,t),t;default:return null}}Object.defineProperty(n,"__esModule",{value:!0}),n.FULLY_CONNECTED=n.WEBRTC=void 0,n.get=i;var o=t(4),a=r(o),s=t(9),c=r(s),u=n.WEBRTC="WebRTCService",d=n.FULLY_CONNECTED="FullyConnectedService",l=new Map},function(e,n,t){"use strict";function r(e){if(e&&e.__esModule)return e;var n={};if(null!=e)for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(n[t]=e[t]);return n["default"]=e,n}function i(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}function o(e,n){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!n||"object"!=typeof n&&"function"!=typeof n?e:n}function a(e,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+typeof n);e.prototype=Object.create(n&&n.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),n&&(Object.setPrototypeOf?Object.setPrototypeOf(e,n):e.__proto__=n)}Object.defineProperty(n,"__esModule",{value:!0});var s=function(){function e(e,n){for(var t=0;t0?p+Math.log10(e):p}},{key:"reUseIntermediaryChannelIfPossible",value:function(e,n,t){var r=null,i=void 0;return e.isJoining()?(i=e.getJoiningPeer(n),-1!==t.indexOf(i.intermediaryId)&&(r=i.intermediaryId)):-1!==t.indexOf(n)&&(i=e.getJoiningPeer(n),null!==i.intermediaryChannel&&(r=n)),null!==r&&(i.toAddList(i.intermediaryChannel),e.sendSrvMsg(this.name,r,{code:m,jpId:n}),t.splice(t.indexOf(r),1)),t}},{key:"add",value:function(e){throw new Error("Must be implemented by subclass!")}},{key:"broadcast",value:function(e,n){throw new Error("Must be implemented by subclass!")}},{key:"sendTo",value:function(e,n,t){throw new Error("Must be implemented by subclass!")}},{key:"leave",value:function(e){throw new Error("Must be implemented by subclass!")}}]),n}(u.Interface);n.Interface=g},function(e,n){"use strict";function t(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function e(e,n){for(var t=0;t { + let decoder = new TextDecoder() + let i8array = new Uint8Array(msgEvt.data) + let code = i8array[0] + let msg = {} + // let msg = JSON.parse(msgEvt.data) + if (code === USER_DATA) { + let str = decoder.decode(i8array.subarray(1, i8array.length)) + this.webChannel.onMessage(this.peerId, str) + return + } else { + let str = decoder.decode(i8array.subarray(1, i8array.length)) + msg = JSON.parse(str) + } + let jp + switch (code) { + // case USER_DATA: + // this.webChannel.onMessage(msg.id, msg.data) + // break + case LEAVE: + this.webChannel.onLeaving(msg.id) + for (let c of this.webChannel.channels) { + if (c.peerId === msg.id) { + this.webChannel.channels.delete(c) + } + } + break + case SERVICE_DATA: + if (this.webChannel.myId === msg.recepient) { + serviceProvider.get(msg.serviceName, this.webChannel.settings).onMessage(this.webChannel, this, msg.data) + } else { + this.webChannel.sendSrvMsg(msg.serviceName, msg.recepient, msg.data) + } + break + case JOIN_INIT: + this.webChannel.topology = msg.manager + this.webChannel.myId = msg.id + this.peerId = msg.intermediaryId + jp = new JoiningPeer(msg.id, msg.intermediaryId) + jp.intermediaryChannel = this + this.webChannel.addJoiningPeer(jp) + break + case JOIN_NEW_MEMBER: + this.webChannel.addJoiningPeer(new JoiningPeer(msg.id, msg.intermediaryId)) + break + case REMOVE_NEW_MEMBER: + this.webChannel.removeJoiningPeer(msg.id) + break + case JOIN_FINILIZE: + this.webChannel.joinSuccess(this.webChannel.myId) + this.webChannel.manager.broadcast(this.webChannel, JOIN_SUCCESS, {id: this.webChannel.myId}) + this.webChannel.onJoin() + break + case JOIN_SUCCESS: + this.webChannel.joinSuccess(msg.id) + this.webChannel.onJoining(msg.id) + break + case THIS_CHANNEL_TO_JOINING_PEER: + if (this.webChannel.hasJoiningPeer(msg.id)) { + jp = this.webChannel.getJoiningPeer(msg.id) + } else { + jp = new JoiningPeer(msg.id) + this.webChannel.addJoiningPeer(jp) + } + if (msg.toBeAdded) { + jp.toAddList(this) + } else { + jp.toRemoveList(this) + } + break + case INIT_CHANNEL_PONG: + this.onPong() + delete this.onPong + break + } + } + this.channel.onerror = (evt) => { + console.log('DATA_CHANNEL ERROR: ', evt) + } + this.channel.onclose = (evt) => { + console.log('DATA_CHANNEL CLOSE: ', evt) + } + } + + /** + * send - description. + * + * @abstract + * @param {string} msg - Message in stringified JSON format. + */ + send (code, data = {}) { + let i8array + let msgStr = code === USER_DATA ? data : JSON.stringify(data) + let encoder = new TextEncoder() + let msgEncoded = encoder.encode(msgStr) + i8array = new Uint8Array(1 + msgEncoded.length) + i8array[0] = code + let index = 1 + for (let i in msgEncoded) { + i8array[index++] = msgEncoded[i] + } + this.channel.send(i8array) + } + + /** + * Close channel. + * + * @abstract + */ + close () { + this.channel.close() + } +} + +export { Channel } diff --git a/src/ChannelInterface.js b/src/ChannelInterface.js deleted file mode 100644 index 83ee6289..00000000 --- a/src/ChannelInterface.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Channel interface. - * [RTCDataChannel]{@link https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel} - * and - * [WebSocket]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket} - * implement it implicitly. Any other channel must implement this interface. - * - * @interface - */ -class ChannelInterface { - constructor () { - this.webChannel - this.peerId - } - - /** - * On message event handler. - * - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent} - * @abstract - * @param {MessageEvent} msgEvt - Message event. - */ - onmessage (msgEvt) { - throw new Error('Must be implemented by subclass!') - } - - /** - * On close event handler. - * - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent} - * @abstract - * @param {CloseEvent} evt - Close event. - */ - onclose (evt) { - throw new Error('Must be implemented by subclass!') - } - - /** - * On error event handler. - * - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * @abstract - * @param {Event} evt - Error event. - */ - onerror (evt) { - throw new Error('Must be implemented by subclass!') - } - - /** - * send - description. - * - * @abstract - * @param {string} msg - Message in stringified JSON format. - */ - send (msg) { - throw new Error('Must be implemented by subclass!') - } - - /** - * Close channel. - * - * @abstract - */ - close () { - throw new Error('Must be implemented by subclass!') - } -} - -export default ChannelInterface diff --git a/src/JoiningPeer.js b/src/JoiningPeer.js index 8ee5b62b..c70ebe6d 100644 --- a/src/JoiningPeer.js +++ b/src/JoiningPeer.js @@ -27,7 +27,7 @@ class JoiningPeer { * The channel between the joining peer and intermediary peer. It is null * for every peer, but the joining and intermediary peers. * - * @type {ChannelInterface} + * @type {Channel} */ this.intermediaryChannel = null @@ -36,7 +36,7 @@ class JoiningPeer { * added to the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToAdd = [] @@ -45,7 +45,7 @@ class JoiningPeer { * closed with the current peer once the joining peer become the member of the * web channel. * - * @type {Array[ChannelInterface]} + * @type {Array[Channel]} */ this.channelsToRemove = [] } @@ -53,7 +53,7 @@ class JoiningPeer { /** * Add channel to `channelsToAdd` array. * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ toAddList (channel) { this.channelsToAdd[this.channelsToAdd.length] = channel @@ -62,7 +62,7 @@ class JoiningPeer { /** * Add channel to `channelsToRemove` array * - * @param {ChannelInterface} channel - Channel to add. + * @param {Channel} channel - Channel to add. */ toRemoveList (channel) { this.channelsToAdd[this.channelsToAdd.length] = channel diff --git a/src/WebChannel.js b/src/WebChannel.js index b0769484..980570f8 100644 --- a/src/WebChannel.js +++ b/src/WebChannel.js @@ -1,5 +1,5 @@ import * as serviceProvider from './serviceProvider' -import { JOIN_NEW_MEMBER, LEAVE, USER_DATA, JOIN_INIT, JOIN_FINILIZE, REMOVE_NEW_MEMBER, SERVICE_DATA, INIT_CHANNEL_PONG } from './service/channelProxy/channelProxy' +import { Channel, JOIN_NEW_MEMBER, LEAVE, USER_DATA, JOIN_INIT, JOIN_FINILIZE, REMOVE_NEW_MEMBER, SERVICE_DATA, INIT_CHANNEL_PONG } from './Channel' import JoiningPeer from './JoiningPeer' /** @@ -70,8 +70,6 @@ class WebChannel { /** @private */ this.connectWithRequests = new Map() - /** @private */ - this.proxy = serviceProvider.get(serviceProvider.CHANNEL_PROXY) /** @private */ this.topology = this.settings.topology } @@ -100,9 +98,7 @@ class WebChannel { /** Leave `WebChannel`. No longer can receive and send messages to the group. */ leave () { - this.manager.broadcast(this, this.proxy.msg(LEAVE, - {id: this.myId} - )) + this.manager.broadcast(this, LEAVE, {id: this.myId}) } /** @@ -111,10 +107,7 @@ class WebChannel { * @param {string} data Message */ send (data) { - this.manager.broadcast(this, this.proxy.msg( - USER_DATA, - {id: this.myId, data} - )) + this.manager.broadcast(this, USER_DATA, data) } /** @@ -124,10 +117,7 @@ class WebChannel { * @param {type} data Message */ sendTo (id, data) { - this.manager.sendTo(id, this, this.proxy.msg( - USER_DATA, - {id: this.myId, data} - )) + this.manager.sendTo(id, this, USER_DATA, {id: this.myId, data}) } /** @@ -143,28 +133,27 @@ class WebChannel { let cBuilder = serviceProvider.get(settings.connector, settings) let key = this.id + this.myId return cBuilder.open(key, (channel) => { - this.initChannel(channel, false).then((channel) => { - let jp = new JoiningPeer(channel.peerId, this.myId) - jp.intermediaryChannel = channel - this.joiningPeers.add(jp) - channel.send(this.proxy.msg(JOIN_INIT, { - manager: this.settings.topology, - id: channel.peerId, - intermediaryId: this.myId}) - ) - this.manager.broadcast(this, this.proxy.msg(JOIN_NEW_MEMBER, { - id: channel.peerId, - intermediaryId: this.myId}) - ) - this.manager.add(channel) - .then(() => channel.send(this.proxy.msg(JOIN_FINILIZE))) - .catch((msg) => { - this.manager.broadcast(this, this.proxy.msg(REMOVE_NEW_MEMBER, { - id: channel.peerId}) - ) - this.removeJoiningPeer(jp.id) - }) - }) + this.initChannel(channel, false) + .then((channel) => { + let jp = new JoiningPeer(channel.peerId, this.myId) + jp.intermediaryChannel = channel + this.joiningPeers.add(jp) + channel.send(JOIN_INIT, { + manager: this.settings.topology, + id: channel.peerId, + intermediaryId: this.myId} + ) + this.manager.broadcast(this, JOIN_NEW_MEMBER, { + id: channel.peerId, + intermediaryId: this.myId} + ) + this.manager.add(channel) + .then(() => channel.send(JOIN_FINILIZE)) + .catch((msg) => { + this.manager.broadcast(this, REMOVE_NEW_MEMBER, {id: channel.peerId}) + this.removeJoiningPeer(jp.id) + }) + }) }).then((data) => { this.webRTCOpen = data.socket return {key: data.key, url: data.url} @@ -236,15 +225,14 @@ class WebChannel { */ sendSrvMsg (serviceName, recepient, msg = {}) { let completeMsg = {serviceName, recepient, data: Object.assign({}, msg)} - let stringifiedMsg = this.proxy.msg(SERVICE_DATA, completeMsg) if (recepient === this.myId) { - this.proxy.onSrvMsg(this, completeMsg) + serviceProvider.get(msg.serviceName, this.settings).onMessage(this, null, msg.data) } else { // If this function caller is a peer who is joining if (this.isJoining()) { let ch = this.getJoiningPeer(this.myId).intermediaryChannel if (ch.readyState !== 'closed') { - ch.send(stringifiedMsg) + ch.send(SERVICE_DATA, completeMsg) } } else { // If the recepient is a joining peer @@ -252,14 +240,14 @@ class WebChannel { let jp = this.getJoiningPeer(recepient) // If I am an intermediary peer for recepient if (jp.intermediaryId === this.myId && jp.intermediaryChannel.readyState !== 'closed') { - jp.intermediaryChannel.send(stringifiedMsg) + jp.intermediaryChannel.send(SERVICE_DATA, completeMsg) // If not, then send this message to the recepient's intermediary peer } else { - this.manager.sendTo(jp.intermediaryId, this, stringifiedMsg) + this.manager.sendTo(jp.intermediaryId, this, SERVICE_DATA, completeMsg) } // If the recepient is a member of webChannel } else { - this.manager.sendTo(recepient, this, stringifiedMsg) + this.manager.sendTo(recepient, this, SERVICE_DATA, completeMsg) } } } @@ -274,20 +262,19 @@ class WebChannel { return this.settings.topology } - initChannel (channel, isInitiator, id = '') { + initChannel (ch, isInitiator, id = this.generateId()) { return new Promise((resolve, reject) => { - channel.webChannel = this - channel.peerId = (id !== '') ? id : this.generateId() + let channel = new Channel(ch, this, id) // TODO: treat the case when the 'ping' or 'pong' message has not been received if (isInitiator) { - this.proxy.configChannel(channel) + channel.config() channel.onPong = () => resolve(channel) - channel.send('ping') + ch.send('ping') } else { - channel.onmessage = (msgEvt) => { + ch.onmessage = (msgEvt) => { if (msgEvt.data === 'ping') { - this.proxy.configChannel(channel) - channel.send(this.proxy.msg(INIT_CHANNEL_PONG)) + channel.config() + channel.send(INIT_CHANNEL_PONG) resolve(channel) } } diff --git a/src/service/channelBuilder/WebRTCService.js b/src/service/channelBuilder/WebRTCService.js index 40f5963f..7a3b8e16 100644 --- a/src/service/channelBuilder/WebRTCService.js +++ b/src/service/channelBuilder/WebRTCService.js @@ -321,10 +321,9 @@ class WebRTCService extends channelBuilder.Interface { createPeerConnectionAndOffer (onCandidate, sendOffer, onChannel) { let pc = this.createPeerConnection(onCandidate) let dc = pc.createDataChannel(null) - dc.ondisconnect = () => {} pc.oniceconnectionstatechange = () => { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect() + dc.onclose() } } dc.onopen = (evt) => onChannel(dc) @@ -350,10 +349,10 @@ class WebRTCService extends channelBuilder.Interface { let pc = this.createPeerConnection(onCandidate) pc.ondatachannel = (dcEvt) => { let dc = dcEvt.channel - dc.ondisconnect = () => {} pc.oniceconnectionstatechange = () => { if (pc.iceConnectionState === 'disconnected') { - dc.ondisconnect() + console.log('Data channel has been disconnected') + dc.onclose() } } dc.onopen = (evt) => onChannel(dc) diff --git a/src/service/channelBuilder/channelBuilder.js b/src/service/channelBuilder/channelBuilder.js index 6e2f7887..b6d3a2fe 100644 --- a/src/service/channelBuilder/channelBuilder.js +++ b/src/service/channelBuilder/channelBuilder.js @@ -3,7 +3,7 @@ import * as service from '../service' * Channel Builder module is responsible to create a connection between two * peers. * @module channelBuilder - * @see ChannelInterface + * @see Channel */ /** @@ -11,7 +11,7 @@ import * as service from '../service' * function. * * @callback module:channelBuilder~onChannelCallback - * @param {ChannelInterface} channel - A new channel. + * @param {Channel} channel - A new channel. */ /** @@ -20,7 +20,7 @@ import * as service from '../service' * ready to be used in the web channel. * * @callback module:channelBuilder~initChannel - * @param {ChannelInterface} ch - Channel. + * @param {Channel} ch - Channel. * @param {string} id - Unique channel identifier. */ diff --git a/src/service/channelProxy/channelProxy.js b/src/service/channelProxy/channelProxy.js deleted file mode 100644 index 0dc7c558..00000000 --- a/src/service/channelProxy/channelProxy.js +++ /dev/null @@ -1,214 +0,0 @@ -import * as service from '../service' -import * as serviceProvider from '../../serviceProvider' -import JoiningPeer from '../../JoiningPeer' - -/** - * Proxy module for configure channel event handlers and any message sent via - * a channel should be build here in order to be understand by the recepient - * peer. - * @module channelProxy - */ - -/** - * Constant used to build a message designated to API user. - * @type {int} - */ -export const USER_DATA = 0 - -/** - * Constant used to build a message designated to a specific service. - * @type {int} - */ -export const SERVICE_DATA = 1 -/** - * Constant used to build a message that a user has left Web Channel. - * @type {int} - */ -export const LEAVE = 2 -/** - * Constant used to build a message to be sent to a newly joining peer. - * @type {int} - */ -export const JOIN_INIT = 3 -/** - * Constant used to build a message to be sent to all peers in Web Channel to - * notify them about a new peer who is about to join the Web Channel. - * @type {int} - */ -export const JOIN_NEW_MEMBER = 4 -/** - * Constant used to build a message to be sent to all peers in Web Channel to - * notify them that the new peer who should join the Web Channel, refuse to join. - * @type {int} - */ -export const REMOVE_NEW_MEMBER = 5 -/** - * Constant used to build a message to be sent to a newly joining peer that he - * has can now succesfully join Web Channel. - * @type {int} - */ -export const JOIN_FINILIZE = 6 -/** - * Constant used to build a message to be sent by the newly joining peer to all - * peers in Web Channel to notify them that he has succesfully joined the Web - * Channel. - * @type {int} - */ -export const JOIN_SUCCESS = 7 -/** - * @type {int} - */ -export const THIS_CHANNEL_TO_JOINING_PEER = 8 -/** - * @type {int} - */ -export const INIT_CHANNEL_PONG = 9 - -/** - * This is a special service class for {@link ChannelInterface}. It mostly - * contains event handlers (e.g. *onmessage*, *onclose* etc.) to configure - * a newly created channel. Thus be careful to use `this` in handlers, as - * it will refer to the instance of `ChannelInterface` and not to the - * instance of `ChannelProxyService`. - */ -class ChannelProxyService extends service.Interface { - - /** - * On message event handler. - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent} - * - * @param {MessageEvent} msgEvt - Message event - */ - onMsg (msgEvt) { - let msg = JSON.parse(msgEvt.data) - let ch = msgEvt.currentTarget - let wc = ch.webChannel - let jp - switch (msg.code) { - case USER_DATA: - wc.onMessage(msg.id, msg.data) - break - case LEAVE: - wc.onLeaving(msg.id) - for (let c of wc.channels) { - if (c.peerId === msg.id) { - wc.channels.delete(c) - } - } - break - case SERVICE_DATA: - if (wc.myId === msg.recepient) { - wc.proxy.onSrvMsg(wc, msg) - } else { - wc.sendSrvMsg(msg.serviceName, msg.recepient, msg.data) - } - break - case JOIN_INIT: - console.log('JOIN_INIT my new id: ' + msg.id) - wc.topology = msg.manager - wc.myId = msg.id - ch.peerId = msg.intermediaryId - jp = new JoiningPeer(msg.id, msg.intermediaryId) - jp.intermediaryChannel = ch - wc.addJoiningPeer(jp) - break - case JOIN_NEW_MEMBER: - wc.addJoiningPeer(new JoiningPeer(msg.id, msg.intermediaryId)) - break - case REMOVE_NEW_MEMBER: - wc.removeJoiningPeer(msg.id) - break - case JOIN_FINILIZE: - wc.joinSuccess(wc.myId) - let nextMsg = wc.proxy.msg(JOIN_SUCCESS, {id: wc.myId}) - wc.manager.broadcast(wc, nextMsg) - wc.onJoin() - break - case JOIN_SUCCESS: - wc.joinSuccess(msg.id) - wc.onJoining(msg.id) - break - case THIS_CHANNEL_TO_JOINING_PEER: - if (wc.hasJoiningPeer(msg.id)) { - jp = wc.getJoiningPeer(msg.id) - } else { - jp = new JoiningPeer(msg.id) - wc.addJoiningPeer(jp) - } - if (msg.toBeAdded) { - jp.toAddList(ch) - } else { - jp.toRemoveList(ch) - } - break - case INIT_CHANNEL_PONG: - ch.onPong() - delete ch.onPong - break - } - } - - /** - * On channel close event handler. - * - For `RTCDataChannel` the type of `evt` is `Event` - * - For `WebSocket`, the type of `evt` is `CloseEvent`. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * @see [CloseEvent doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent} - * - * @param {Event} evt - Close event. - */ - onClose (evt) { - console.log('DATA_CHANNEL CLOSE: ', evt) - } - - /** - * On error event handler. - * @see [Event doc on MDN]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event} - * - * @param {Event} evt - Error event. - */ - onError (evt) { - console.log('DATA_CHANNEL ERROR: ', evt) - } - - onDisconnect () { - this.webChannel.channels.delete(this) - this.webChannel.onLeaving(this.peerId) - } - - configChannel (channel) { - channel.onmessage = this.onMsg - channel.onerror = this.onError - channel.onclose = this.onClose - channel.ondisconnect = this.onDisconnect - } - - /** - * When the message is designated for a service. This is not an event handler - * for a channel. The main difference with the `SERVICE_DATA` message arriving - * for `onMessage` is that here the message could be sent by the peer to - * himself. - * - * @param {WebChannel} wc - Web Channel. - * @param {Object} msg - Message. - */ - onSrvMsg (wc, msg, channel = null) { - serviceProvider.get(msg.serviceName, wc.settings).onMessage(wc, channel, msg.data) - } - - /** - * Message builder. - * - * @param {int} code - One of the constant values in {@link constans}. - * @param {Object} [data={}] - Data to be send. - * @return {string} - Data in stringified JSON format. - */ - msg (code, data = {}) { - let msg = Object.assign({code}, data) - return JSON.stringify(msg) - } -} - -export { -/** @see module:channelProxy~ChannelProxyService */ -ChannelProxyService } diff --git a/src/service/service.js b/src/service/service.js index 54a0f4de..c64c74b4 100644 --- a/src/service/service.js +++ b/src/service/service.js @@ -32,7 +32,7 @@ class Interface { * * @abstract * @param {WebChannel} wc - Web Channel from which the message is arrived. - * @param {ChannelInterface} wc - Channel by which the message is arrived. + * @param {Channel} wc - Channel by which the message is arrived. * @param {string} msg - Message in stringified JSON format. */ onMessage (wc, channel, msg) { diff --git a/src/service/webChannelManager/FullyConnectedService.js b/src/service/webChannelManager/FullyConnectedService.js index 67d40ea5..b15d4de5 100644 --- a/src/service/webChannelManager/FullyConnectedService.js +++ b/src/service/webChannelManager/FullyConnectedService.js @@ -21,19 +21,19 @@ class FullyConnectedService extends wcManager.Interface { return this.connectWith(wCh, ch.peerId, ch.peerId, peers) } - broadcast (webChannel, data) { + broadcast (webChannel, code, data) { for (let c of webChannel.channels) { if (c.readyState !== 'closed') { - c.send(data) + c.send(code, data) } } } - sendTo (id, webChannel, data) { + sendTo (id, webChannel, code, data) { for (let c of webChannel.channels) { if (c.peerId === id) { if (c.readyState !== 'closed') { - c.send(data) + c.send(code, data) } return } diff --git a/src/service/webChannelManager/webChannelManager.js b/src/service/webChannelManager/webChannelManager.js index 40a72ac6..aa0d21a5 100644 --- a/src/service/webChannelManager/webChannelManager.js +++ b/src/service/webChannelManager/webChannelManager.js @@ -1,6 +1,6 @@ import * as service from '../service' import * as serviceProvider from '../../serviceProvider' -import { THIS_CHANNEL_TO_JOINING_PEER } from '../channelProxy/channelProxy' +import { THIS_CHANNEL_TO_JOINING_PEER } from '../../Channel' /** * Web Channel Manager module is a submodule of {@link module:service} and the @@ -47,17 +47,15 @@ class Interface extends service.Interface { msg.peers.forEach((id) => { cBuilder.connectMeTo(wc, id) .then((channel) => { - console.log('New channel established') - return wc.initChannel(channel, true) + return wc.initChannel(channel, true, id) }) .then((channel) => { - console.log('New channel has been initialized') wc.getJoiningPeer(msg.jpId).toAddList(channel) - channel.send(wc.proxy.msg(THIS_CHANNEL_TO_JOINING_PEER, + channel.send( + THIS_CHANNEL_TO_JOINING_PEER, {id: msg.jpId, toBeAdded: true} - )) + ) counter++ - console.log('Counter becomes: ' + counter) if (counter === msg.peers.length) { wc.sendSrvMsg(this.name, msg.sender, {code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed} @@ -65,10 +63,8 @@ class Interface extends service.Interface { } }) .catch((reason) => { - console.log('New channel catch error: ' + reason) counter++ - console.log('Counter becomes: ' + counter) - result.failed.push({id, reason}) + failed.push({id, reason}) if (counter === msg.peers.length) { wc.sendSrvMsg(this.name, msg.sender, {code: CONNECT_WITH_FEEDBACK, id: wc.myId, failed} @@ -160,7 +156,7 @@ class Interface extends service.Interface { * Adds a new peer into Web Channel. * * @abstract - * @param {ChannelInterface} ch - Channel to be added (it should has + * @param {Channel} ch - Channel to be added (it should has * the `webChannel` property). * @return {Promise} - Resolved once the channel has been succesfully added, * rejected otherwise. diff --git a/src/serviceProvider.js b/src/serviceProvider.js index 66d6c955..2a0e6952 100644 --- a/src/serviceProvider.js +++ b/src/serviceProvider.js @@ -1,6 +1,5 @@ import FullyConnectedService from './service/webChannelManager/FullyConnectedService' import WebRTCService from './service/channelBuilder/WebRTCService' -import {ChannelProxyService} from './service/channelProxy/channelProxy' /** * Service Provider module is a helper module for {@link module:service}. It is * responsible to instantiate all services. This module must be used to get @@ -8,12 +7,6 @@ import {ChannelProxyService} from './service/channelProxy/channelProxy' * @module serviceProvider */ -/** - * Constant used to get an instance of {@link ChannelProxyService}. - * @type {string} - */ -export const CHANNEL_PROXY = 'ChannelProxyService' - /** * Constant used to get an instance of {@link WebRTCService}. * @type {string} @@ -49,10 +42,6 @@ export function get (name, options = {}) { service = new FullyConnectedService() services.set(name, service) return service - case CHANNEL_PROXY: - service = new ChannelProxyService() - services.set(name, service) - return service default: return null } diff --git a/test/scenarios/fullyConnected.webRTC.3peers.test.js b/test/scenarios/fullyConnected.webRTC.3peers.test.js index 1d805e94..fa1d0b9f 100644 --- a/test/scenarios/fullyConnected.webRTC.3peers.test.js +++ b/test/scenarios/fullyConnected.webRTC.3peers.test.js @@ -55,6 +55,7 @@ it('Client _1 creates a webChannel and open it to enable other clients to join', expect(msg).toEqual('And I am _1') done() } else { + console.log('FAILED: ' + id) done.fail() } } diff --git a/test/service/channelBuilder/webRTCService.test.js b/test/service/channelBuilder/webRTCService.test.js index 712ab266..ae4c524c 100644 --- a/test/service/channelBuilder/webRTCService.test.js +++ b/test/service/channelBuilder/webRTCService.test.js @@ -73,7 +73,31 @@ describe('WebRTCService ->', () => { }) }) - it('Open & Join: should open 1 dataChanne and exchange messages between 2 peers', (done) => { + it('Open & Join: should detect disconnected peer', (done) => { + let masterChannel + webRTCService.open(randKey(), (channel) => { + masterChannel = channel + channel.onclose = (closeEvt) => { + if (closeEvt) { + console.log('Close event: ', closeEvt) + console.log('Master channel state: ' + masterChannel.readyState) + } + done() + } + channel.onerror = done.fail + }) + .then((data) => { + webRTCService.join(data.key) + .then((channel) => { + channel.onerror = done.fail + setTimeout(() => { channel.close() }, 500) + }) + .catch(done.fail) + }) + .catch(done.fail) + }) + + it('Open & Join: should open 1 dataChannel and exchange messages between 2 peers', (done) => { const masterPeerMsg = 'Hello! Here is master' const peerMsg = 'Hi, I am a peer' webRTCService.open(randKey(), (channel) => { @@ -99,7 +123,7 @@ describe('WebRTCService ->', () => { .catch(done.fail) }) - it('Open & Join: should open 2 dataChannels exchange messages between 3 peers', (done) => { + it('Open & Join: should open 2 dataChannels and exchange messages between 3 peers', (done) => { const masterPeerMsg = 'Do or do not, there is no try' const peerMsg1 = 'Hi, I am a peer #1' const peerMsg2 = 'Hi, I am a peer #2' diff --git a/test/serviceProvider.test.js b/test/serviceProvider.test.js index 8f6cdaed..ed8afbd9 100644 --- a/test/serviceProvider.test.js +++ b/test/serviceProvider.test.js @@ -2,25 +2,16 @@ import * as sp from '../src/serviceProvider' it('serviceProvider -> service constant names should be exported', () => { expect(sp.WEBRTC).toBeDefined() - expect(sp.CHANNEL_PROXY).toBeDefined() expect(sp.FULLY_CONNECTED).toBeDefined() }) it('serviceProvider -> should provide a service', () => { let webRTC = sp.get(sp.WEBRTC) - let channelProxy = sp.get(sp.CHANNEL_PROXY) let fullyConnected = sp.get(sp.FULLY_CONNECTED) expect(webRTC.name).toEqual('WebRTCService') - expect(channelProxy.name).toEqual('ChannelProxyService') expect(fullyConnected.name).toEqual('FullyConnectedService') }) -it('serviceProvider -> ChannelProxyService should be a singleton', () => { - let channelProxy1 = sp.get(sp.CHANNEL_PROXY) - let channelProxy2 = sp.get(sp.CHANNEL_PROXY) - expect(channelProxy1 == channelProxy2).toBeTruthy() -}) - it('serviceProvider -> FullyConnectedService should be a singleton', () => { let fullyConnected1 = sp.get(sp.FULLY_CONNECTED) let fullyConnected2 = sp.get(sp.FULLY_CONNECTED)