move padrtc to .git

pull/1/head
ansuz 9 years ago
parent 18ce69b756
commit 3bdfee71e1

@ -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
};
});

@ -1,79 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script data-main="main" src="/bower_components/requirejs/require.js"></script>
<style>
html, body {
margin: 0px;
padding: 0px;
}
#pad-iframe {
position:fixed;
top:0px;
left:0px;
bottom:0px;
right:0px;
width:100%;
height:100%;
border:none;
margin:0;
padding:0;
overflow:hidden;
}
#feedback {
display: none;
position: fixed;
top: 0px;
right: 0px;
border: 0px;
height: 100vh;
width: 30vw;
background-color: #222;
color: #ccc;
}
#debug {
height: 20px;
position: absolute;
right: 0px;
top: 70px;
}
#debug button {
visibility: hidden;
}
#debug:hover button {
visibility: visible;
}
</style>
</head>
<body>
<iframe id="pad-iframe" src="inner.html"></iframe>
<div id="debug"><button>DEBUG</button></div>
<textarea id="feedback"></textarea>
<script>
require(['/bower_components/jquery/dist/jquery.min.js'], function() {
var $ = window.$;
$('#debug').on('click', function() {
if($('#feedback').is(':visible')) {
$('#pad-iframe').css({
'width' : '100%'
});
$('#debug').css({
'right' : '0%'
});
}
else {
$('#pad-iframe').css({
'width' : '70%'
});
$('#debug').css({
'right' : '30%'
});
}
$('#feedback').toggle();
});
});
</script>
</body>
</html>

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/ckeditor/ckeditor.js"></script>
</head>
<body>
<textarea style="display:none" id="editor1" name="editor1"></textarea>
</body>
</html>

@ -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 <br> instead of the <p>. This makes it such that you
cannot type until you click, which is rather unnacceptable.
If the cursor is ever inside such a <br>, 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);
});

File diff suppressed because it is too large Load Diff

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
});
Loading…
Cancel
Save