diff --git a/www/padrtc/TextPatcher.js b/www/padrtc/TextPatcher.js deleted file mode 100644 index a5d9b9d01..000000000 --- a/www/padrtc/TextPatcher.js +++ /dev/null @@ -1,144 +0,0 @@ -define(function () { - -/* diff takes two strings, the old content, and the desired content - it returns the difference between these two strings in the form - of an 'Operation' (as defined in chainpad.js). - - diff is purely functional. -*/ -var diff = function (oldval, newval) { - // Strings are immutable and have reference equality. I think this test is O(1), so its worth doing. - if (oldval === newval) { - return; - } - - var commonStart = 0; - while (oldval.charAt(commonStart) === newval.charAt(commonStart)) { - commonStart++; - } - - var commonEnd = 0; - while (oldval.charAt(oldval.length - 1 - commonEnd) === newval.charAt(newval.length - 1 - commonEnd) && - commonEnd + commonStart < oldval.length && commonEnd + commonStart < newval.length) { - commonEnd++; - } - - var toRemove = 0; - var toInsert = ''; - - /* throw some assertions in here before dropping patches into the realtime */ - if (oldval.length !== commonStart + commonEnd) { - toRemove = oldval.length - commonStart - commonEnd; - } - if (newval.length !== commonStart + commonEnd) { - toInsert = newval.slice(commonStart, newval.length - commonEnd); - } - - return { - type: 'Operation', - offset: commonStart, - toInsert: toInsert, - toRemove: toRemove - }; -}; - -/* patch accepts a realtime facade and an operation (which might be falsey) - it applies the operation to the realtime as components (remove/insert) - - patch has no return value, and operates solely through side effects on - the realtime facade. -*/ -var patch = function (ctx, op) { - if (!op) { return; } - if (op.toRemove) { ctx.remove(op.offset, op.toRemove); } - if (op.toInsert) { ctx.insert(op.offset, op.toInsert); } -}; - -/* format has the same signature as log, but doesn't log to the console - use it to get the pretty version of a diff */ -var format = function (text, op) { - return op?{ - insert: op.toInsert, - remove: text.slice(op.offset, op.offset + op.toRemove) - }: { insert: '', remove: '' }; -}; - -/* log accepts a string and an operation, and prints an object to the console - the object will display the content which is to be removed, and the content - which will be inserted in its place. - - log is useful for debugging, but can otherwise be disabled. -*/ -var log = function (text, op) { - if (!op) { return; } - console.log(format(text, op)); -}; - -/* applyChange takes: - ctx: the context (aka the realtime) - oldval: the old value - newval: the new value - - it performs a diff on the two values, and generates patches - which are then passed into `ctx.remove` and `ctx.insert`. - - Due to its reliance on patch, applyChange has side effects on the supplied - realtime facade. -*/ -var applyChange = function(ctx, oldval, newval, logging) { - var op = diff(oldval, newval); - if (logging) { log(oldval, op); } - patch(ctx, op); -}; - -var transformCursor = function (cursor, op) { - if (!op) { return cursor; } - var pos = op.offset; - var remove = op.toRemove; - var insert = op.toInsert.length; - if (typeof cursor === 'undefined') { return; } - if (typeof remove === 'number' && pos < cursor) { - cursor -= Math.min(remove, cursor - pos); - } - if (typeof insert === 'number' && pos < cursor) { - cursor += insert; - } - return cursor; -}; - -var create = function(config) { - var ctx = config.realtime; - var logging = config.logging; - - // initial state will always fail the !== check in genop. - // because nothing will equal this object - var content = {}; - - // *** remote -> local changes - ctx.onPatch(function(pos, length) { - content = ctx.getUserDoc(); - }); - - // propogate() - return function (newContent, force) { - if (newContent !== content || force) { - applyChange(ctx, ctx.getUserDoc(), newContent, logging); - if (ctx.getUserDoc() !== newContent) { - console.log("Expected that: `ctx.getUserDoc() === newContent`!"); - } - return true; - } - return false; - }; -}; - -return { - create: create, // create a TextPatcher object - diff: diff, // diff two strings - patch: patch, // apply an operation to a chainpad's realtime facade - format: format, - log: log, // print the components of an operation - transformCursor: transformCursor, // transform the position of a cursor - applyChange: applyChange, // a convenient wrapper around diff/log/patch -}; -}); diff --git a/www/padrtc/index.html b/www/padrtc/index.html deleted file mode 100644 index fccdfff02..000000000 --- a/www/padrtc/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - -
- - - - - diff --git a/www/padrtc/inner.html b/www/padrtc/inner.html deleted file mode 100644 index bf79dcd0d..000000000 --- a/www/padrtc/inner.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/www/padrtc/main.js b/www/padrtc/main.js deleted file mode 100644 index f71fa5f1d..000000000 --- a/www/padrtc/main.js +++ /dev/null @@ -1,354 +0,0 @@ -define([ - '/api/config?cb=' + Math.random().toString(16).substring(2), - '/common/messages.js', - '/common/crypto.js', - '/padrtc/realtime-input.js', - '/bower_components/hyperjson/hyperjson.amd.js', - '/common/hyperscript.js', - '/common/toolbar.js', - '/common/cursor.js', - '/common/json-ot.js', - '/bower_components/diff-dom/diffDOM.js', - '/bower_components/jquery/dist/jquery.min.js', - '/customize/pad.js' -], function (Config, Messages, Crypto, realtimeInput, Hyperjson, Hyperscript, Toolbar, Cursor, JsonOT) { - var $ = window.jQuery; - var ifrw = $('#pad-iframe')[0].contentWindow; - var Ckeditor; // to be initialized later... - var DiffDom = window.diffDOM; - - window.Toolbar = Toolbar; - window.Hyperjson = Hyperjson; - - var hjsonToDom = function (H) { - return Hyperjson.callOn(H, Hyperscript); - }; - - var module = window.REALTIME_MODULE = { - localChangeInProgress: 0 - }; - - var userName = Crypto.rand64(8), - toolbar; - - var isNotMagicLine = function (el) { - // factor as: - // return !(el.tagName === 'SPAN' && el.contentEditable === 'false'); - var filter = (el.tagName === 'SPAN' && el.contentEditable === 'false'); - if (filter) { - console.log("[hyperjson.serializer] prevented an element" + - "from being serialized:", el); - return false; - } - return true; - }; - - var andThen = function (Ckeditor) { - // $(window).on('hashchange', function() { - // window.location.reload(); - // }); - var key; - var channel = ''; - if (window.location.href.indexOf('#') === -1) { - key = Crypto.genKey(); - // window.location.href = window.location.href + '#' + Crypto.genKey(); - // return; - } - else { - var hash = window.location.hash.substring(1); - var sep = hash.indexOf('|'); - channel = hash.substr(0,sep); - key = hash.substr(sep+1); - } - - var fixThings = false; - // var key = Crypto.parseKey(window.location.hash.substring(1)); - var editor = window.editor = Ckeditor.replace('editor1', { - // https://dev.ckeditor.com/ticket/10907 - needsBrFiller: fixThings, - needsNbspFiller: fixThings, - removeButtons: 'Source,Maximize', - // magicline plugin inserts html crap into the document which is not part of the - // document itself and causes problems when it's sent across the wire and reflected back - removePlugins: 'resize' - }); - - editor.on('instanceReady', function (Ckeditor) { - editor.execCommand('maximize'); - var documentBody = ifrw.$('iframe')[0].contentDocument.body; - - documentBody.innerHTML = Messages.initialState; - - var inner = window.inner = documentBody; - var cursor = window.cursor = Cursor(inner); - - var setEditable = function (bool) { - inner.setAttribute('contenteditable', - (typeof (bool) !== 'undefined'? bool : true)); - }; - - // don't let the user edit until the pad is ready - setEditable(false); - - var diffOptions = { - preDiffApply: function (info) { - /* Don't remove local instances of the magicline plugin */ - if (info.node && info.node.tagName === 'SPAN' && - info.node.getAttribute('contentEditable') === 'false') { - return true; - } - - if (!cursor.exists()) { return; } - var frame = info.frame = cursor.inNode(info.node); - if (!frame) { return; } - if (typeof info.diff.oldValue === 'string' && - typeof info.diff.newValue === 'string') { - var pushes = cursor.pushDelta(info.diff.oldValue, - info.diff.newValue); - if (frame & 1) { - if (pushes.commonStart < cursor.Range.start.offset) { - cursor.Range.start.offset += pushes.delta; - } - } - if (frame & 2) { - if (pushes.commonStart < cursor.Range.end.offset) { - cursor.Range.end.offset += pushes.delta; - } - } - } - }, - postDiffApply: function (info) { - if (info.frame) { - if (info.node) { - if (info.frame & 1) { cursor.fixStart(info.node); } - if (info.frame & 2) { cursor.fixEnd(info.node); } - } else { console.log("info.node did not exist"); } - - var sel = cursor.makeSelection(); - var range = cursor.makeRange(); - - cursor.fixSelection(sel, range); - } - } - }; - - var now = function () { return new Date().getTime(); }; - - var initializing = true; - var userList = {}; // List of pretty name of all users (mapped with their server ID) - var toolbarList; // List of users still connected to the channel (server IDs) - var addToUserList = function(data) { - for (var attrname in data) { userList[attrname] = data[attrname]; } - if(toolbarList && typeof toolbarList.onChange === "function") { - toolbarList.onChange(userList); - } - }; - - var myData = {}; - var myUserName = ''; // My "pretty name" - var myID; // My server ID - - var setMyID = function(info) { - myID = info.myID || null; - myUserName = myID; - }; - - var createChangeName = function(id, $container) { - var buttonElmt = $container.find('#'+id)[0]; - buttonElmt.addEventListener("click", function() { - var newName = prompt("Change your name :", myUserName) - if (newName && newName.trim()) { - var myUserNameTemp = newName.trim(); - if(newName.trim().length > 32) { - myUserNameTemp = myUserNameTemp.substr(0, 32); - } - myUserName = myUserNameTemp; - myData[myID] = { - name: myUserName - }; - addToUserList(myData); - editor.fire( 'change' ); - } - }); - }; - - var DD = new DiffDom(diffOptions); - - // apply patches, and try not to lose the cursor in the process! - var applyHjson = function (shjson) { - // var hjson = JSON.parse(shjson); - // var peerUserList = hjson[hjson.length-1]; - // if(peerUserList.metadata) { - // var userData = peerUserList.metadata; - // addToUserList(userData); - // delete hjson[hjson.length-1]; - // } - var userDocStateDom = hjsonToDom(JSON.parse(shjson)); - userDocStateDom.setAttribute("contenteditable", "true"); // lol wtf - var patch = (DD).diff(inner, userDocStateDom); - (DD).apply(inner, patch); - }; - - var realtimeOptions = { - // provide initialstate... - initialState: JSON.stringify(Hyperjson.fromDOM(inner, isNotMagicLine)), - - // the websocket URL (deprecated?) - websocketURL: Config.websocketURL, - webrtcURL: Config.webrtcURL, - - // our username - userName: userName, - - // the channel we will communicate over - channel: channel, - - // our encryption key - cryptKey: key, - - setMyID: setMyID, - - // really basic operational transform - transformFunction : JsonOT.validate, - - crypto: Crypto, - }; - - var onRemote = realtimeOptions.onRemote = function (info) { - if (initializing) { return; } - - var shjson = info.realtime.getUserDoc(); - - // remember where the cursor is - cursor.update(); - - // Extract the user list (metadata) from the hyperjson - var hjson = JSON.parse(shjson); - var peerUserList = hjson[hjson.length-1]; - if(peerUserList.metadata) { - var userData = peerUserList.metadata; - // Update the local user data - userList = userData; - // Send the new data to the toolbar - if(toolbarList && typeof toolbarList.onChange === "function") { - toolbarList.onChange(userList); - } - hjson.pop(); - } - - // build a dom from HJSON, diff, and patch the editor - applyHjson(shjson); - - // Build a new stringified Chainpad hyperjson without metadata to compare with the one build from the dom - shjson = JSON.stringify(hjson); - - var hjson2 = Hyperjson.fromDOM(inner); - var shjson2 = JSON.stringify(hjson2); - if (shjson2 !== shjson) { - console.error("shjson2 !== shjson"); - module.realtimeInput.patchText(shjson2); - } - }; - - var onInit = realtimeOptions.onInit = function (info) { - var $bar = $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox'); - toolbarList = info.userList; - var config = { - userData: userList, - changeNameID: 'cryptpad-changeName' - }; - toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.webChannel, info.userList, config); - createChangeName('cryptpad-changeName', $bar); - /* TODO handle disconnects and such*/ - }; - - var onReady = realtimeOptions.onReady = function (info) { - console.log("Unlocking editor"); - initializing = false; - setEditable(true); - var shjson = info.realtime.getUserDoc(); - applyHjson(shjson); - }; - - var onAbort = realtimeOptions.onAbort = function (info) { - console.log("Aborting the session!"); - // stop the user from continuing to edit - setEditable(false); - // TODO inform them that the session was torn down - toolbar.failed(); - }; - - - - - - var rti = module.realtimeInput = realtimeInput.start(realtimeOptions); - - /* catch `type="_moz"` before it goes over the wire */ - var brFilter = function (hj) { - if (hj[1].type === '_moz') { hj[1].type = undefined; } - return hj; - }; - - // $textarea.val(JSON.stringify(Convert.dom.to.hjson(inner))); - - /* It's incredibly important that you assign 'rti.onLocal' - It's used inside of realtimeInput to make sure that all changes - make it into chainpad. - - It's being assigned this way because it can't be passed in, and - and can't be easily returned from realtime input without making - the code less extensible. - */ - var propogate = rti.onLocal = function () { - /* if the problem were a matter of external patches being - applied while a local patch were in progress, then we would - expect to be able to check and find - 'module.localChangeInProgress' with a non-zero value while - we were applying a remote change. - */ - var hjson = Hyperjson.fromDOM(inner, isNotMagicLine, brFilter); - if(Object.keys(myData).length > 0) { - hjson[hjson.length] = {metadata: userList}; - } - var shjson = JSON.stringify(hjson); - if (!rti.patchText(shjson)) { - return; - } - rti.onEvent(shjson); - }; - - /* hitting enter makes a new line, but places the cursor inside - of the
instead of the

. This makes it such that you - cannot type until you click, which is rather unnacceptable. - If the cursor is ever inside such a
, you probably want - to push it out to the parent element, which ought to be a - paragraph tag. This needs to be done on keydown, otherwise - the first such keypress will not be inserted into the P. */ - inner.addEventListener('keydown', cursor.brFix); - - editor.on('change', propogate); - // editor.on('change', function () { - // var hjson = Convert.core.hyperjson.fromDOM(inner); - // if(myData !== {}) { - // hjson[hjson.length] = {metadata: userList}; - // } - // $textarea.val(JSON.stringify(hjson)); - // rti.bumpSharejs(); - // }); - }); - }; - - var interval = 100; - var first = function () { - Ckeditor = ifrw.CKEDITOR; - if (Ckeditor) { - andThen(Ckeditor); - } else { - console.log("Ckeditor was not defined. Trying again in %sms",interval); - setTimeout(first, interval); - } - }; - - $(first); -}); diff --git a/www/padrtc/netflux.js b/www/padrtc/netflux.js deleted file mode 100644 index d01302980..000000000 --- a/www/padrtc/netflux.js +++ /dev/null @@ -1,1473 +0,0 @@ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["nf"] = factory(); - else - root["nf"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _Facade = __webpack_require__(1); - - var _Facade2 = _interopRequireDefault(_Facade); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - module.exports = new _Facade2.default(); - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _WebChannel = __webpack_require__(2); - - var _WebChannel2 = _interopRequireDefault(_WebChannel); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var Facade = function () { - function Facade() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, Facade); - - this.defaults = { - webrtc: {} - }; - this.settings = Object.assign({}, this.defaults, options); - } - - _createClass(Facade, [{ - key: 'create', - value: function create() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - return new _WebChannel2.default(); - } - }, { - key: 'join', - value: function join(key) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var defaults = { - connector: 'WebRTCService', - protocol: 'ExchangeProtocolService' - }; - var settings = Object.assign({}, defaults, options); - var connector = _ServiceProvider2.default.get(settings.connector); - var protocol = _ServiceProvider2.default.get(settings.protocol); - var connectorOptions = { signaling: settings.signaling, facade: this }; - return new Promise(function (resolve, reject) { - connector.join(key, connectorOptions).then(function (channel) { - var webChannel = new _WebChannel2.default(options); - channel.webChannel = webChannel; - channel.onmessage = protocol.onmessage; - webChannel.channels.add(channel); - webChannel.onopen = function () { - resolve(webChannel); - }; - }, reject); - }); - } - }, { - key: 'invite', - value: function invite() { - // TODO - } - }, { - key: '_onJoining', - value: function _onJoining() { - // TODO - } - }, { - key: '_onLeaving', - value: function _onLeaving() { - // TODO - } - }, { - key: '_onMessage', - value: function _onMessage() { - // TODO - } - }, { - key: '_onPeerMessage', - value: function _onPeerMessage() { - // TODO - } - }, { - key: '_onInvite', - value: function _onInvite() { - // TODO - } - }]); - - return Facade; - }(); - - exports.default = Facade; - -/***/ }, -/* 2 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var WebChannel = function () { - function WebChannel() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, WebChannel); - - this.defaults = { - connector: cs.WEBRTC_SERVICE, - topology: cs.FULLYCONNECTED_SERVICE, - protocol: cs.EXCHANGEPROTOCOL_SERVICE - }; - this.settings = Object.assign({}, this.defaults, options); - - // Private attributes - this.protocol = cs.EXCHANGEPROTOCOL_SERVICE; - - // Public attributes - this.id; - this.myID = this._generateID(); - this.channels = new Set(); - this.onjoining; - this.onleaving; - this.onmessage; - } - - _createClass(WebChannel, [{ - key: 'leave', - value: function leave() {} - }, { - key: 'send', - value: function send(data) { - var channel = this; - return new Promise(function (resolve, reject) { - if (channel.channels.size === 0) { - resolve(); - } - var protocol = _ServiceProvider2.default.get(channel.settings.protocol); - channel.topologyService.broadcast(channel, protocol.message(cs.USER_DATA, { id: channel.myID, data: data })).then(resolve, reject); - }); - } - }, { - key: 'sendPing', - value: function sendPing() { - var channel = this; - return new Promise(function (resolve, reject) { - if (channel.channels.size === 0) { - resolve(); - } - var protocol = _ServiceProvider2.default.get(channel.settings.protocol); - channel.topologyService.broadcast(channel, protocol.message(cs.PING, { data: '' })).then(resolve, reject); - }); - } - }, { - key: 'getHistory', - value: function getHistory(historyKeeperID) { - var channel = this; - return new Promise(function (resolve, reject) { - var protocol = _ServiceProvider2.default.get(channel.settings.protocol); - channel.topologyService.sendTo(historyKeeperID, channel, protocol.message(cs.GET_HISTORY, { id: channel.myID, data: '' })).then(resolve, reject); - }); - } - }, { - key: 'sendTo', - value: function sendTo(id, msg) { - var channel = this; - return new Promise(function (resolve, reject) { - var protocol = _ServiceProvider2.default.get(channel.settings.protocol); - channel.topologyService.sendTo(id, channel, protocol.message(cs.USER_DATA, { id: channel.myID, data: msg })).then(resolve, reject); - }); - } - }, { - key: 'openForJoining', - value: function openForJoining() { - var _this = this; - - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - var settings = Object.assign({}, this.settings, options); - var connector = _ServiceProvider2.default.get(settings.connector); - return connector.open(function (channel) { - // 1) New dataChannel connection established. - // NEXT: add it to the network - var protocol = _ServiceProvider2.default.get(_this.protocol); - _this.topologyService = _ServiceProvider2.default.get(_this.settings.topology); - channel.webChannel = _this; - channel.onmessage = protocol.onmessage; - - // 2.1) Send to the new client the webChannel topology name - channel.send(protocol.message(cs.JOIN_START, _this.settings.topology)); - - // 2.2) Ask to topology to add the new client to this webChannel - _this.topologyService.addStart(channel, _this).then(function (id) { - _this.topologyService.broadcast(_this, protocol.message(cs.JOIN_FINISH, id)); - _this.onJoining(id); - }); - }, settings).then(function (data) { - return data; - }); - } - }, { - key: 'closeForJoining', - value: function closeForJoining() {} - }, { - key: 'isInviting', - value: function isInviting() {} - }, { - key: '_generateID', - value: function _generateID() { - var MIN_LENGTH = 10; - var DELTA_LENGTH = 10; - var MASK = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - var result = ''; - var length = MIN_LENGTH + Math.round(Math.random() * DELTA_LENGTH); - - for (var i = 0; i < length; i++) { - result += MASK[Math.round(Math.random() * (MASK.length - 1))]; - } - return result; - } - }, { - key: 'topology', - set: function set(topologyServiceName) { - this.settings.topology = topologyServiceName; - this.topologyService = _ServiceProvider2.default.get(topologyServiceName); - }, - get: function get() { - return this.settigns.topology; - } - }]); - - return WebChannel; - }(); - - exports.default = WebChannel; - -/***/ }, -/* 3 */ -/***/ function(module, exports) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - // API user's message - var USER_DATA = exports.USER_DATA = 0; - var GET_HISTORY = exports.GET_HISTORY = 6; - - // Internal messages - var JOIN_START = exports.JOIN_START = 2; - var JOIN_FINISH = exports.JOIN_FINISH = 4; - var YOUR_NEW_ID = exports.YOUR_NEW_ID = 5; - var PING = exports.PING = 7; - - // Internal message to a specific Service - var SERVICE_DATA = exports.SERVICE_DATA = 3; - - var WEBRTC_SERVICE = exports.WEBRTC_SERVICE = 'WebRTCService'; - var WEBSOCKET_SERVICE = exports.WEBSOCKET_SERVICE = 'WebSocketService'; - var FULLYCONNECTED_SERVICE = exports.FULLYCONNECTED_SERVICE = 'FullyConnectedService'; - var STAR_SERVICE = exports.STAR_SERVICE = 'StarTopologyService'; - var EXCHANGEPROTOCOL_SERVICE = exports.EXCHANGEPROTOCOL_SERVICE = 'ExchangeProtocolService'; - var WSPROTOCOL_SERVICE = exports.WSPROTOCOL_SERVICE = 'WebSocketProtocolService'; - -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _FullyConnectedService = __webpack_require__(5); - - var _FullyConnectedService2 = _interopRequireDefault(_FullyConnectedService); - - var _StarTopologyService = __webpack_require__(6); - - var _StarTopologyService2 = _interopRequireDefault(_StarTopologyService); - - var _WebRTCService = __webpack_require__(7); - - var _WebRTCService2 = _interopRequireDefault(_WebRTCService); - - var _WebSocketService = __webpack_require__(8); - - var _WebSocketService2 = _interopRequireDefault(_WebSocketService); - - var _ExchangeProtocolService = __webpack_require__(9); - - var _ExchangeProtocolService2 = _interopRequireDefault(_ExchangeProtocolService); - - var _WebSocketProtocolService = __webpack_require__(10); - - var _WebSocketProtocolService2 = _interopRequireDefault(_WebSocketProtocolService); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var services = new Map(); - - var ServiceProvider = function () { - function ServiceProvider() { - _classCallCheck(this, ServiceProvider); - } - - _createClass(ServiceProvider, null, [{ - key: 'get', - value: function get(code) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var service = undefined; - switch (code) { - case cs.WEBRTC_SERVICE: - service = new _WebRTCService2.default(options); - break; - case cs.WEBSOCKET_SERVICE: - service = new _WebSocketService2.default(options); - break; - case cs.FULLYCONNECTED_SERVICE: - service = new _FullyConnectedService2.default(options); - break; - case cs.STAR_SERVICE: - service = new _StarTopologyService2.default(options); - break; - case cs.EXCHANGEPROTOCOL_SERVICE: - service = new _ExchangeProtocolService2.default(options); - break; - case cs.WSPROTOCOL_SERVICE: - service = new _WebSocketProtocolService2.default(options); - break; - } - services.set(code, service); - return service; - } - }]); - - return ServiceProvider; - }(); - - exports.default = ServiceProvider; - -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var FullyConnectedService = function () { - function FullyConnectedService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, FullyConnectedService); - } - - _createClass(FullyConnectedService, [{ - key: 'addStart', - value: function addStart(channel, webChannel) { - var _this = this; - - var protocol = _ServiceProvider2.default.get(cs.EXCHANGEPROTOCOL_SERVICE); - return new Promise(function (resolve, reject) { - channel.peerID = _this._generateID(); - channel.send(protocol.message(cs.YOUR_NEW_ID, { - newID: channel.peerID, - myID: webChannel.myID - })); - if (Reflect.has(webChannel, 'aboutToJoin') && webChannel.aboutToJoin instanceof Map) { - webChannel.aboutToJoin.set(channel.peerID, channel); - } else { - webChannel.aboutToJoin = new Map(); - } - - if (webChannel.channels.size === 0) { - webChannel.channels.add(channel); - channel.onclose = function () { - webChannel.onLeaving(channel.peerID); - webChannel.channels.delete(channel); - }; - resolve(channel.peerID); - } else { - (function () { - webChannel.successfullyConnected = new Map(); - webChannel.successfullyConnected.set(channel.peerID, 0); - webChannel.connectionSucceed = function (id, withId) { - var counter = webChannel.successfullyConnected.get(withId); - webChannel.successfullyConnected.set(withId, ++counter); - if (webChannel.successfullyConnected.get(withId) === webChannel.channels.size) { - _this.addFinish(webChannel, withId); - resolve(withId); - } - }; - var connector = _ServiceProvider2.default.get(cs.WEBRTC_SERVICE); - webChannel.channels.forEach(function (c) { - connector.connect(channel.peerID, webChannel, c.peerID); - }); - })(); - } - }); - } - }, { - key: 'addFinish', - value: function addFinish(webChannel, id) { - if (id != webChannel.myID) { - (function () { - var channel = webChannel.aboutToJoin.get(id); - webChannel.channels.add(webChannel.aboutToJoin.get(id)); - channel.onclose = function () { - webChannel.onLeaving(channel.peerID); - webChannel.channels.delete(channel); - }; - //webChannel.aboutToJoin.delete(id) - if (Reflect.has(webChannel, 'successfullyConnected')) { - webChannel.successfullyConnected.delete(id); - } - })(); - } else { - webChannel.onopen(); - } - } - }, { - key: 'broadcast', - value: function broadcast(webChannel, data) { - return new Promise(function (resolve, reject) { - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = webChannel.channels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var c = _step.value; - - c.send(data); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - resolve(); - }); - } - }, { - key: 'sendTo', - value: function sendTo(id, webChannel, data) { - return new Promise(function (resolve, reject) { - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = webChannel.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var c = _step2.value; - - if (c.peerID == id) { - c.send(data); - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - resolve(); - }); - } - }, { - key: 'leave', - value: function leave(webChannel) { - this.broadcast(webChannel); - } - }, { - key: '_generateID', - value: function _generateID() { - var MIN_LENGTH = 10; - var DELTA_LENGTH = 10; - var MASK = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - var length = MIN_LENGTH + Math.round(Math.random() * DELTA_LENGTH); - var maskLastIndex = MASK.length - 1; - var result = ''; - - for (var i = 0; i < length; i++) { - result += MASK[Math.round(Math.random() * maskLastIndex)]; - } - return result; - } - }]); - - return FullyConnectedService; - }(); - - exports.default = FullyConnectedService; - -/***/ }, -/* 6 */ -/***/ function(module, exports) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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; }; }(); - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var StarTopologyService = function () { - function StarTopologyService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, StarTopologyService); - } - - _createClass(StarTopologyService, [{ - key: 'broadcast', - value: function broadcast(webChannel, data) { - return new Promise(function (resolve, reject) { - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = webChannel.channels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var c = _step.value; - - var msg = undefined; - // Create the string message - var date = new Date().getTime(); - if (data.type === 'PING') { - msg = JSON.stringify([c.seq++, 'PING', date]); - } else { - msg = JSON.stringify([c.seq++, data.type, webChannel.id, data.msg]); - } - // Store the message with his sequence number to know what message has caused the reception of an ACK - // This is used in WebSocketProtocolService - var srvMsg = JSON.parse(msg); - srvMsg.shift(); - srvMsg.unshift(webChannel.myID); - srvMsg.unshift(0); - webChannel.waitingAck[c.seq - 1] = { resolve: resolve, reject: reject, time: date, data: srvMsg }; - // Send the message to the server - c.send(msg); - } - // resolve(); - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - }); - } - }, { - key: 'sendTo', - value: function sendTo(id, webChannel, data) { - return new Promise(function (resolve, reject) { - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = webChannel.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var c = _step2.value; - - var msg = JSON.stringify([c.seq++, data.type, id, data.msg]); - c.send(msg); - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - resolve(); - }); - } - }]); - - return StarTopologyService; - }(); - - exports.default = StarTopologyService; - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var WEBRTC_DATA = 0; - var CONNECT_WITH = 1; - var CONNECT_WITH_SUCCEED = 2; - - var WebRTCService = function () { - function WebRTCService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, WebRTCService); - - this.NAME = this.constructor.name; - this.protocol = _ServiceProvider2.default.get(cs.EXCHANGEPROTOCOL_SERVICE); - this.defaults = { - signaling: 'ws://localhost:8000', - webRTCOptions: { - iceServers: [{ - urls: ['stun:23.21.150.121', 'stun:stun.l.google.com:19302'] - }, { - urls: 'turn:numb.viagenie.ca', - credential: 'webrtcdemo', - username: 'louis%40mozilla.com' - }] - } - }; - this.settings = Object.assign({}, this.defaults, options); - - // Declare WebRTC related global(window) constructors - this.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.msRTCPeerConnection; - - this.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.RTCIceCandidate || window.msRTCIceCandidate; - - this.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.msRTCSessionDescription; - } - - _createClass(WebRTCService, [{ - key: 'connect', - value: function connect(newPeerID, webChannel, peerID) { - webChannel.topologyService.sendTo(peerID, webChannel, this._msg(CONNECT_WITH, { key: newPeerID, intermediaryID: webChannel.myID })); - } - }, { - key: 'open', - value: function open(onchannel) { - var _this = this; - - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var defaults = { - key: this._randomKey() - }; - var settings = Object.assign({}, this.settings, defaults, options); - - return new Promise(function (resolve, reject) { - var connections = []; - var socket = new window.WebSocket(settings.signaling); - socket.onopen = function () { - socket.send(JSON.stringify({ key: settings.key })); - resolve({ url: _this.settings.signaling, key: settings.key }); - }; - socket.onmessage = function (e) { - var msg = JSON.parse(e.data); - if (Reflect.has(msg, 'id') && Reflect.has(msg, 'data')) { - if (Reflect.has(msg.data, 'offer')) { - (function () { - var connection = new _this.RTCPeerConnection(settings.webRTCOptions); - connections.push(connection); - connection.ondatachannel = function (e) { - e.channel.onopen = function () { - onchannel(e.channel); - }; - }; - connection.onicecandidate = function (e) { - if (e.candidate !== null) { - var candidate = { - candidate: e.candidate.candidate, - sdpMLineIndex: e.candidate.sdpMLineIndex - }; - socket.send(JSON.stringify({ id: msg.id, data: { candidate: candidate } })); - } - }; - var sd = Object.assign(new _this.RTCSessionDescription(), msg.data.offer); - connection.setRemoteDescription(sd, function () { - connection.createAnswer(function (answer) { - connection.setLocalDescription(answer, function () { - socket.send(JSON.stringify({ - id: msg.id, - data: { answer: connection.localDescription.toJSON() } })); - }, function () {}); - }, function () {}); - }, function () {}); - })(); - } else if (Reflect.has(msg.data, 'candidate')) { - var candidate = new _this.RTCIceCandidate(msg.data.candidate); - connections[msg.id].addIceCandidate(candidate); - } - } - }; - socket.onerror = reject; - }); - } - }, { - key: 'join', - value: function join(key) { - var _this2 = this; - - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var settings = Object.assign({}, this.settings, options); - return new Promise(function (resolve, reject) { - var connection = undefined; - var socket = new window.WebSocket(settings.signaling); - socket.onopen = function () { - connection = new _this2.RTCPeerConnection(settings.webRTCOptions); - connection.onicecandidate = function (e) { - if (e.candidate !== null) { - var candidate = { - candidate: e.candidate.candidate, - sdpMLineIndex: e.candidate.sdpMLineIndex - }; - socket.send(JSON.stringify({ data: { candidate: candidate } })); - } - }; - var dc = connection.createDataChannel(key); - dc.onopen = function () { - resolve(dc); - }; - connection.createOffer(function (offer) { - connection.setLocalDescription(offer, function () { - socket.send(JSON.stringify({ join: key, data: { offer: connection.localDescription.toJSON() } })); - }, reject); - }, reject); - }; - socket.onclose = function (e) { - reject(e); - }; - socket.onmessage = function (e) { - var msg = JSON.parse(e.data); - if (Reflect.has(msg, 'data')) { - if (Reflect.has(msg.data, 'answer')) { - var sd = Object.assign(new _this2.RTCSessionDescription(), msg.data.answer); - connection.setRemoteDescription(sd, function () {}, reject); - } else if (Reflect.has(msg.data, 'candidate')) { - var candidate = new _this2.RTCIceCandidate(msg.data.candidate); - connection.addIceCandidate(candidate); - } else { - reject(); - } - } else { - reject(); - } - }; - socket.onerror = reject; - }); - } - }, { - key: '_randomKey', - value: function _randomKey() { - var MIN_LENGTH = 10; - var DELTA_LENGTH = 10; - var MASK = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - var result = ''; - var length = MIN_LENGTH + Math.round(Math.random() * DELTA_LENGTH); - - for (var i = 0; i < length; i++) { - result += MASK[Math.round(Math.random() * (MASK.length - 1))]; - } - return result; - } - }, { - key: '_msg', - value: function _msg(code, data) { - var msg = { service: this.constructor.name }; - msg.data = {}; - msg.data.code = code; - Object.assign(msg.data, data); - return this.protocol.message(cs.SERVICE_DATA, msg); - } - }, { - key: 'onmessage', - value: function onmessage(channel, msg) { - var _this3 = this; - - var webChannel = channel.webChannel; - if (!Reflect.has(webChannel, 'connections')) { - webChannel.connections = new Map(); - } - switch (msg.code) { - case WEBRTC_DATA: - if (webChannel.myID === msg.recipientPeerID) { - if (Reflect.has(msg, 'sdp')) { - if (msg.sdp.type === 'offer') { - (function () { - var connection = new _this3.RTCPeerConnection(_this3.settings.webRTCOptions); - webChannel.connections.set(msg.senderPeerID, connection); - connection.ondatachannel = function (e) { - e.channel.onopen = function () { - e.channel.peerID = msg.senderPeerID; - e.channel.webChannel = webChannel; - e.channel.onmessage = _this3.protocol.onmessage; - webChannel.channels.add(e.channel); - e.channel.onclose = function () { - webChannel.onLeaving(e.channel.peerID); - webChannel.channels.delete(e.channel); - }; - }; - }; - connection.onicecandidate = function (e) { - if (e.candidate !== null) { - var candidate = { - candidate: e.candidate.candidate, - sdpMLineIndex: e.candidate.sdpMLineIndex - }; - channel.send(_this3._msg(WEBRTC_DATA, { - senderPeerID: webChannel.myID, - recipientPeerID: msg.senderPeerID, - candidate: candidate - })); - } - }; - var sd = Object.assign(new _this3.RTCSessionDescription(), msg.sdp); - connection.setRemoteDescription(sd, function () { - connection.createAnswer(function (answer) { - connection.setLocalDescription(answer, function () { - channel.send(_this3._msg(WEBRTC_DATA, { - senderPeerID: webChannel.myID, - recipientPeerID: msg.senderPeerID, - sdp: connection.localDescription.toJSON() - })); - }, function () {}); - }, function () {}); - }, function () {}); - })(); - } else if (msg.sdp.type === 'answer') { - var sd = Object.assign(new this.RTCSessionDescription(), msg.sdp); - webChannel.connections.get(msg.senderPeerID).setRemoteDescription(sd, function () {}, function () {}); - } - } else if (Reflect.has(msg, 'candidate')) { - webChannel.connections.get(msg.senderPeerID).addIceCandidate(new this.RTCIceCandidate(msg.candidate)); - } - } else { - var data = this._msg(WEBRTC_DATA, msg); - if (webChannel.aboutToJoin.has(msg.recipientPeerID)) { - webChannel.aboutToJoin.get(msg.recipientPeerID).send(data); - } else { - webChannel.topologyService.sendTo(msg.recipientPeerID, webChannel, data); - } - } - break; - case CONNECT_WITH: - var connection = new this.RTCPeerConnection(this.settings.webRTCOptions); - connection.onicecandidate = function (e) { - if (e.candidate !== null) { - var candidate = { - candidate: e.candidate.candidate, - sdpMLineIndex: e.candidate.sdpMLineIndex - }; - webChannel.topologyService.sendTo(msg.intermediaryID, webChannel, _this3._msg(WEBRTC_DATA, { - senderPeerID: webChannel.myID, - recipientPeerID: msg.key, - candidate: candidate - })); - } - }; - var dc = connection.createDataChannel(msg.key); - dc.onopen = function () { - if (!Reflect.has(webChannel, 'aboutToJoin')) { - webChannel.aboutToJoin = new Map(); - } - webChannel.aboutToJoin.set(dc.label, dc); - dc.onmessage = _this3.protocol.onmessage; - dc.peerID = dc.label; - dc.webChannel = webChannel; - webChannel.topologyService.sendTo(msg.intermediaryID, webChannel, _this3._msg(CONNECT_WITH_SUCCEED, { - senderPeerID: webChannel.myID, - recipientPeerID: dc.label - })); - }; - connection.createOffer(function (offer) { - connection.setLocalDescription(offer, function () { - webChannel.topologyService.sendTo(msg.intermediaryID, webChannel, _this3._msg(WEBRTC_DATA, { - senderPeerID: webChannel.myID, - recipientPeerID: msg.key, - sdp: connection.localDescription.toJSON() - })); - webChannel.connections.set(msg.key, connection); - }, function () {}); - }, function () {}); - break; - case CONNECT_WITH_SUCCEED: - webChannel.connectionSucceed(msg.senderPeerID, msg.recipientPeerID); - break; - } - } - }]); - - return WebRTCService; - }(); - - exports.default = WebRTCService; - -/***/ }, -/* 8 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var WebSocketService = function () { - function WebSocketService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, WebSocketService); - - this.NAME = this.constructor.name; - this.protocol = _ServiceProvider2.default.get(cs.EXCHANGEPROTOCOL_SERVICE); - this.defaults = { - signaling: 'ws://localhost:9000', - REQUEST_TIMEOUT: 5000 - }; - this.settings = Object.assign({}, this.defaults, options); - } - - _createClass(WebSocketService, [{ - key: 'join', - value: function join(key) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var settings = Object.assign({}, this.settings, options); - return new Promise(function (resolve, reject) { - var connection = undefined; - var socket = new window.WebSocket(settings.signaling); - setInterval(function () { - if (socket.webChannel && socket.webChannel.waitingAck) { - var waitingAck = socket.webChannel.waitingAck; - for (var id in waitingAck) { - var req = waitingAck[id]; - var now = new Date().getTime(); - if (now - req.time > settings.REQUEST_TIMEOUT) { - delete socket.webChannel.waitingAck[id]; - req.reject({ type: 'TIMEOUT', message: 'waited ' + now - req.time + 'ms' }); - } - } - } - }, 5000); - socket.seq = 1; - socket.facade = options.facade || null; - socket.onopen = function () { - if (key && key !== '') { - socket.send(JSON.stringify([socket.seq++, 'JOIN', key])); - } else { - socket.send(JSON.stringify([socket.seq++, 'JOIN'])); - } - resolve(socket); - }; - socket.onerror = reject; - }); - } - }]); - - return WebSocketService; - }(); - - exports.default = WebSocketService; - -/***/ }, -/* 9 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var ExchangeProtocolService = function () { - function ExchangeProtocolService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, ExchangeProtocolService); - } - - _createClass(ExchangeProtocolService, [{ - key: 'onmessage', - value: function onmessage(e) { - var msg = JSON.parse(e.data); - var channel = e.currentTarget; - var webChannel = channel.webChannel; - - switch (msg.code) { - case cs.USER_DATA: - webChannel.onmessage(msg.id, msg.data); - break; - case cs.GET_HISTORY: - webChannel.onPeerMessage(msg.id, msg.code); - break; - case cs.SERVICE_DATA: - var service = _ServiceProvider2.default.get(msg.service); - service.onmessage(channel, msg.data); - break; - case cs.YOUR_NEW_ID: - // TODO: change names - webChannel.myID = msg.newID; - channel.peerID = msg.myID; - break; - case cs.JOIN_START: - // 2.1) Send to the new client the webChannel topology - webChannel.topology = msg.topology; - webChannel.topologyService = _ServiceProvider2.default.get(msg.topology); - break; - case cs.JOIN_FINISH: - webChannel.topologyService.addFinish(webChannel, msg.id); - if (msg.id != webChannel.myID) { - // A new user has just registered - webChannel.onJoining(msg.id); - } else { - (function () { - // We're fully synced, trigger onJoining for all existing users - var waitForOnJoining = function waitForOnJoining() { - if (typeof webChannel.onJoining !== "function") { - setTimeout(waitForOnJoining, 500); - return; - } - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = webChannel.channels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var c = _step.value; - - webChannel.onJoining(c.peerID); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - }; - waitForOnJoining(); - })(); - } - break; - } - } - }, { - key: 'message', - value: function message(code, data) { - var msg = { code: code }; - switch (code) { - case cs.USER_DATA: - msg.id = data.id; - msg.data = data.data; - break; - case cs.GET_HISTORY: - msg.id = data.id; - break; - case cs.SERVICE_DATA: - msg.service = data.service; - msg.data = Object.assign({}, data.data); - break; - case cs.YOUR_NEW_ID: - msg.newID = data.newID; - msg.myID = data.myID; - break; - case cs.JOIN_START: - msg.topology = data; - break; - case cs.JOIN_FINISH: - msg.id = data; - break; - } - return JSON.stringify(msg); - } - }]); - - return ExchangeProtocolService; - }(); - - exports.default = ExchangeProtocolService; - -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - 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 _constants = __webpack_require__(3); - - var cs = _interopRequireWildcard(_constants); - - var _ServiceProvider = __webpack_require__(4); - - var _ServiceProvider2 = _interopRequireDefault(_ServiceProvider); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - - 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; } } - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - - var WebSocketProtocolService = function () { - function WebSocketProtocolService() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - _classCallCheck(this, WebSocketProtocolService); - } - - _createClass(WebSocketProtocolService, [{ - key: 'onmessage', - value: function onmessage(e) { - var msg = JSON.parse(e.data); - var socket = e.currentTarget; - var webChannel = socket.webChannel; - var topology = cs.STAR_SERVICE; - var topologyService = _ServiceProvider2.default.get(topology); - var history_keeper = webChannel.hc; - - if (msg[0] !== 0 && msg[1] !== 'ACK') { - return; - } - - if (msg[2] === 'IDENT' && msg[1] === '') { - socket.uid = msg[3]; - webChannel.myID = msg[3]; - webChannel.peers = []; - webChannel.waitingAck = []; - webChannel.topology = topology; - return; - } - if (msg[1] === 'PING') { - msg[1] = 'PONG'; - socket.send(JSON.stringify(msg)); - return; - } - if (msg[1] === 'ACK') { - var seq = msg[0]; - if (webChannel.waitingAck[seq]) { - var waitingAck = webChannel.waitingAck[seq]; - waitingAck.resolve(); - var newMsg = waitingAck.data; - if (newMsg[2] === 'PING') { - // PING message : set the lag - var lag = new Date().getTime() - newMsg[3]; - webChannel.getLag = function () { - return lag; - }; - } - delete webChannel.waitingAck[seq]; - } - return; - } - // We have received a new direct message from another user - if (msg[2] === 'MSG' && msg[3] === socket.uid) { - // If it comes from the history keeper, send it to the user - if (msg[1] === history_keeper) { - if (msg[4] === 0) { - webChannel.onmessage(msg[1], msg[4]); - return; - } - var msgHistory = JSON.parse(msg[4]); - webChannel.onmessage(msgHistory[1], msgHistory[4]); - } - return; - } - if (msg[2] === 'JOIN' && (webChannel.id == null || webChannel.id === msg[3])) { - if (!webChannel.id) { - // New unnamed channel : get its name from the first "JOIN" message - if (!window.location.hash) { - var chanName = window.location.hash = msg[3]; - } - webChannel.id = msg[3]; - } - - if (msg[1] === socket.uid) { - // If the user catches himself registering, he is synchronized with the server - webChannel.onopen(); - } else { - // Trigger onJoining() when another user is joining the channel - // Register the user in the list of peers in the channel - if (webChannel.peers.length === 0 && msg[1].length === 16) { - // We've just catched the history keeper (16 characters length name) - history_keeper = msg[1]; - webChannel.hc = history_keeper; - } - var linkQuality = msg[1] === history_keeper ? 1000 : 0; - var sendToPeer = function sendToPeer(data) { - topologyService.sendTo(msg[1], webChannel, { type: 'MSG', msg: data }); - }; - var peer = { id: msg[1], connector: socket, linkQuality: linkQuality, send: sendToPeer }; - if (webChannel.peers.indexOf(peer) === -1) { - webChannel.peers.push(peer); - } - - if (msg[1] !== history_keeper) { - // Trigger onJoining with that peer once the function is loaded (i.e. once the channel is synced) - var waitForOnJoining = function waitForOnJoining() { - if (typeof webChannel.onJoining !== "function") { - setTimeout(waitForOnJoining, 500); - return; - } - webChannel.onJoining(msg[1]); - }; - waitForOnJoining(); - } - } - return; - } - // We have received a new message in that channel from another peer - if (msg[2] === 'MSG' && msg[3] === webChannel.id) { - // Find the peer who sent the message and display it - //TODO Use Peer instead of peer.id (msg[1]) : - if (typeof webChannel.onmessage === "function") webChannel.onmessage(msg[1], msg[4]); - return; - } - // Someone else has left the channel, remove him from the list of peers - if (msg[2] === 'LEAVE' && msg[3] === webChannel.id) { - //TODO Use Peer instead of peer.id (msg[1]) : - if (typeof webChannel.onLeaving === "function") webChannel.onLeaving(msg[1], webChannel); - return; - } - } - }, { - key: 'message', - value: function message(code, data) { - var type = undefined; - switch (code) { - case cs.USER_DATA: - type = 'MSG'; - break; - case cs.JOIN_START: - type = 'JOIN'; - break; - case cs.PING: - type = 'PING'; - break; - } - return { type: type, msg: data.data }; - } - }]); - - return WebSocketProtocolService; - }(); - - exports.default = WebSocketProtocolService; - -/***/ } -/******/ ]) -}); -; \ No newline at end of file diff --git a/www/padrtc/realtime-input.js b/www/padrtc/realtime-input.js deleted file mode 100644 index 568781209..000000000 --- a/www/padrtc/realtime-input.js +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright 2014 XWiki SAS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -window.Reflect = { has: (x,y) => { return (y in x); } }; -define([ - '/common/messages.js', - '/padrtc/netflux.js', - '/common/crypto.js', - '/common/toolbar.js', - '/padrtc/TextPatcher.js', - '/common/es6-promise.min.js', - '/common/chainpad.js', - '/bower_components/jquery/dist/jquery.min.js', -], function (Messages, Netflux, Crypto, Toolbar, TextPatcher) { - var $ = window.jQuery; - var ChainPad = window.ChainPad; - var PARANOIA = true; - var module = { exports: {} }; - - /** - * If an error is encountered but it is recoverable, do not immediately fail - * but if it keeps firing errors over and over, do fail. - */ - var MAX_RECOVERABLE_ERRORS = 15; - - var debug = function (x) { console.log(x); }, - warn = function (x) { console.error(x); }, - verbose = function (x) { console.log(x); }; - verbose = function () {}; // comment out to enable verbose logging - - // ------------------ Trapping Keyboard Events ---------------------- // - - var bindEvents = function (element, events, callback, unbind) { - for (var i = 0; i < events.length; i++) { - var e = events[i]; - if (element.addEventListener) { - if (unbind) { - element.removeEventListener(e, callback, false); - } else { - element.addEventListener(e, callback, false); - } - } else { - if (unbind) { - element.detachEvent('on' + e, callback); - } else { - element.attachEvent('on' + e, callback); - } - } - } - }; - - var getParameterByName = function (name, url) { - if (!url) { url = window.location.href; } - name = name.replace(/[\[\]]/g, "\\$&"); - var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), - results = regex.exec(url); - if (!results) { return null; } - if (!results[2]) { return ''; } - return decodeURIComponent(results[2].replace(/\+/g, " ")); - }; - - var start = module.exports.start = - function (config) - { - var websocketUrl = config.websocketURL; - var webrtcUrl = config.webrtcURL; - var userName = config.userName; - var channel = config.channel; - var chanKey = config.cryptKey; - var cryptKey = Crypto.parseKey(chanKey).cryptKey; - var passwd = 'y'; - - // make sure configuration is defined - config = config || {}; - - var doc = config.doc || null; - - var allMessages = []; - var initializing = true; - var recoverableErrorCount = 0; - var toReturn = {}; - var messagesHistory = []; - var chainpadAdapter = {}; - var realtime; - - // define this in case it gets called before the rest of our stuff is ready. - var onEvent = toReturn.onEvent = function (newText) { }; - - var parseMessage = function (msg) { - var res ={}; - // two or more? use a for - ['pass','user','channelId','content'].forEach(function(attr){ - var len=msg.slice(0,msg.indexOf(':')), - // taking an offset lets us slice out the prop - // and saves us one string copy - o=len.length+1, - prop=res[attr]=msg.slice(o,Number(len)+o); - // slice off the property and its descriptor - msg = msg.slice(prop.length+o); - }); - // content is the only attribute that's not a string - res.content=JSON.parse(res.content); - return res; - }; - - var mkMessage = function (user, chan, content) { - content = JSON.stringify(content); - return user.length + ':' + user + - chan.length + ':' + chan + - content.length + ':' + content; - }; - - var onPeerMessage = function(toId, type, wc) { - if(type === 6) { - messagesHistory.forEach(function(msg) { - wc.sendTo(toId, '1:y'+msg); - }); - wc.sendTo(toId, '0'); - } - }; - - var whoami = new RegExp(userName.replace(/[\/\+]/g, function (c) { - return '\\' +c; - })); - - var onMessage = function(peer, msg, wc) { - - if(msg === 0 || msg === '0') { - onReady(wc); - return; - } - var message = chainpadAdapter.msgIn(peer, msg); - - verbose(message); - allMessages.push(message); - // if (!initializing) { - // if (toReturn.onLocal) { - // toReturn.onLocal(); - // } - // } - realtime.message(message); - if (/\[5,/.test(message)) { verbose("pong"); } - - if (!initializing) { - if (/\[2,/.test(message)) { - //verbose("Got a patch"); - if (whoami.test(message)) { - //verbose("Received own message"); - } else { - //verbose("Received remote message"); - // obviously this is only going to get called if - if (config.onRemote) { - config.onRemote({ - realtime: realtime - }); - } - } - } - } - }; - - var userList = { - onChange : function() {}, - users: [] - }; - var onJoining = function(peer) { - var list = userList.users; - if(list.indexOf(peer) === -1) { - userList.users.push(peer); - } - userList.onChange(); - }; - - var onLeaving = function(peer) { - var list = userList.users; - var index = list.indexOf(peer); - if(index !== -1) { - userList.users.splice(index, 1); - } - userList.onChange(); - }; - - chainpadAdapter = { - msgIn : function(peerId, msg) { - var parsed = parseMessage(msg); - // Remove the password from the message - var passLen = msg.substring(0,msg.indexOf(':')); - var message = msg.substring(passLen.length+1 + Number(passLen)); - try { - var decryptedMsg = Crypto.decrypt(message, cryptKey); - messagesHistory.push(decryptedMsg); - return decryptedMsg; - } catch (err) { - return message; - } - - }, - msgOut : function(msg, wc) { - var parsed = parseMessage(msg); - if(parsed.content[0] === 0) { // We're registering : send a REGISTER_ACK to Chainpad - onMessage('', '1:y'+mkMessage('', channel, [1,0])); - return; - } - if(parsed.content[0] === 4) { // PING message from Chainpad - parsed.content[0] = 5; - onMessage('', '1:y'+mkMessage(parsed.user, parsed.channelId, parsed.content)); - wc.sendPing(); - return; - } - return Crypto.encrypt(msg, cryptKey); - } - }; - - var options = {}; - - var rtc = true; - - if(channel.trim().length > 0) { - options.key = channel; - } - if(!webrtcUrl) { - rtc = false; - options.signaling = websocketUrl; - options.topology = 'StarTopologyService'; - options.protocol = 'WebSocketProtocolService'; - options.connector = 'WebSocketService'; - options.openWebChannel = true; - } - else { - options.signaling = webrtcUrl; - } - - var createRealtime = function(chan) { - return ChainPad.create(userName, - passwd, - channel, - config.initialState || {}, - { - transformFunction: config.transformFunction - }); - }; - - var onReady = function(wc) { - if(config.onInit) { - config.onInit({ - myID: wc.myID, - realtime: realtime, - getLag: wc.getLag, - userList: userList - }); - } - // Trigger onJoining with our own Cryptpad username to tell the toolbar that we are synced - onJoining(wc.myID); - - // we're fully synced - initializing = false; - - // execute an onReady callback if one was supplied - if (config.onReady) { - config.onReady({ - realtime: realtime - }); - } - } - - var onOpen = function(wc) { - channel = wc.id; - window.location.hash = channel + '|' + chanKey; - // Add the handlers to the WebChannel - wc.onmessage = function(peer, msg) { // On receiving message - onMessage(peer, msg, wc); - }; - wc.onJoining = onJoining; // On user joining the session - wc.onLeaving = onLeaving; // On user leaving the session - wc.onPeerMessage = function(peerId, type) { - onPeerMessage(peerId, type, wc); - }; - if(config.setMyID) { - config.setMyID({ - myID: wc.myID - }); - } - // Open a Chainpad session - realtime = createRealtime(); - - // Sending a message... - realtime.onMessage(function(message) { - // Filter messages sent by Chainpad to make it compatible with Netflux - message = chainpadAdapter.msgOut(message, wc); - if(message) { - wc.send(message).then(function() { - // Send the message back to Chainpad once it is sent to the recipients. - onMessage(wc.myID, message); - }, function(err) { - // The message has not been sent, display the error. - console.error(err); - }); - } - }); - - // Get the channel history - var hc; - if(rtc) { - wc.channels.forEach(function (c) { if(!hc) { hc = c; } }); - if(hc) { - wc.getHistory(hc.peerID); - } - } - else { - // TODO : Improve WebSocket service to use the latest Netflux's API - wc.peers.forEach(function (p) { if (!hc || p.linkQuality > hc.linkQuality) { hc = p; } }); - hc.send(JSON.stringify(['GET_HISTORY', wc.id])); - } - - - toReturn.patchText = TextPatcher.create({ - realtime: realtime - }); - - realtime.start(); - }; - - var createRTCChannel = function () { - // Check if the WebRTC channel exists and create it if necessary - var webchannel = Netflux.create(); - webchannel.openForJoining(options).then(function(data) { - console.log(data); - webchannel.id = data.key - onOpen(webchannel); - onReady(webchannel); - }, function(error) { - warn(error); - }); - }; - - var joinChannel = function() { - // Connect to the WebSocket/WebRTC channel - Netflux.join(channel, options).then(function(wc) { - if(channel.trim().length > 0) { - wc.id = channel - } - onOpen(wc); - }, function(error) { - if(rtc && error.code === 1008) {// Unexisting RTC channel - createRTCChannel(); - } - else { warn(error); } - }); - }; - joinChannel(); - - var checkConnection = function(wc) { - if(wc.channels && wc.channels.size > 0) { - var channels = Array.from(wc.channels); - var channel = channels[0]; - - var socketChecker = setInterval(function () { - if (channel.checkSocket(realtime)) { - warn("Socket disconnected!"); - - recoverableErrorCount += 1; - - if (recoverableErrorCount >= MAX_RECOVERABLE_ERRORS) { - warn("Giving up!"); - realtime.abort(); - try { channel.close(); } catch (e) { warn(e); } - if (config.onAbort) { - config.onAbort({ - socket: channel - }); - } - if (socketChecker) { clearInterval(socketChecker); } - } - } else { - // it's working as expected, continue - } - }, 200); - } - }; - - return toReturn; - }; - return module.exports; -});