Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wip] Collaboration using WebRTC #801

Merged
merged 9 commits into from
Jul 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"q": "1.4.1",
"semver": "^4.1.0",
"wolfy87-eventemitter": "^5.1.0",
"simplewebrtc": "^3.0.0",
"xmldoc": "^0.1.2"
},
"devDependencies": {
Expand Down
103 changes: 103 additions & 0 deletions src/editor/Collaboration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
define(function (require, exports, module) {
"use strict";

var SimpleWebRTC = require("simplewebrtc");

function Collaboration() {
var webrtc = new SimpleWebRTC({
// the id/element dom element that will hold "our" videos
localVideoEl: 'localVideo',
// the id/element dom element that will hold remote videos
remoteVideosEl: 'remotesVideos',
// immediately ask for camera access
autoRequestMedia: false
});
this.webrtc = webrtc;
this.pending = []; // pending clients that need to be initialized.
this.changing = false;
};

Collaboration.prototype.init = function(codemirror) {
var self = this;
this.webrtc.joinRoom('thimble', function() {
self.codemirror = codemirror;
self.webrtc.sendToAll("new client", {});
self.webrtc.on("createdPeer", function(peer) {
self.initializeNewClient(peer);
});

self.webrtc.connection.on('message', function (msg) {
self.handleMessage(msg);
});
});
};

Collaboration.prototype.handleMessage = function(msg) {
switch(msg.type) {
case "new client":
this.pending.push(msg.from);
break;
case "codemirror-change":
this.handleCodemirrorChange(msg.payload);
break;
case "initClient":
if(this.changing) {
return;
}
this.changing = true;
this.codemirror.setValue(msg.payload);
this.changing = false;
break;
}
};


Collaboration.prototype.initializeNewClient = function(peer) {
this.changing = true;
for(var i = 0; i<this.pending.length; i++) {
if(this.pending[i] === peer.id) {
peer.send("initClient", this.codemirror.getValue());
this.pending.splice(i, 1);
break;
}
}
this.changing = false;
};

Collaboration.prototype.handleCodemirrorChange = function(delta) {
if(this.changing) {
return;
}
this.changing = true;
var cm = this.codemirror;
var start = cm.indexFromPos(delta.from);
// apply the delete operation first
if (delta.removed.length > 0) {
var delLength = 0;
for (var i = 0; i < delta.removed.length; i++) {
delLength += delta.removed[i].length;
}
delLength += delta.removed.length - 1;
var from = cm.posFromIndex(start);
var to = cm.posFromIndex(start + delLength);
cm.replaceRange('', from, to);
}
// apply insert operation
var param = delta.text.join('\n');
var from = cm.posFromIndex(start);
var to = from;
cm.replaceRange(param, from, to);
this.changing = false;
};

Collaboration.prototype.triggerCodemirrorChange = function(changeList) {
if(this.changing) {
return;
}
for(var i = 0; i<changeList.length; i++) {
this.webrtc.sendToAll("codemirror-change",changeList[i]);
}
};

exports.Collaboration = Collaboration;
});
4 changes: 4 additions & 0 deletions src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ define(function (require, exports, module) {
ValidationUtils = require("utils/ValidationUtils"),
ViewUtils = require("utils/ViewUtils"),
MainViewManager = require("view/MainViewManager"),
Collaboration = require("editor/Collaboration").Collaboration,
_ = require("thirdparty/lodash");

/** Editor preferences */
Expand All @@ -102,6 +103,7 @@ define(function (require, exports, module) {


var cmOptions = {};
var collabInstance = new Collaboration();

/**
* Constants
Expand Down Expand Up @@ -430,6 +432,7 @@ define(function (require, exports, module) {
// CodeMirror-focused. Instead, track focus via onFocus and onBlur
// options and track state with this._focused
this._focused = false;
collabInstance.init(this._codeMirror);

this._installEditorListeners();

Expand Down Expand Up @@ -928,6 +931,7 @@ define(function (require, exports, module) {
// whereas the "change" event should be listened to on the document. Also the
// Editor dispatches a change event before this event is dispatched, because
// CodeHintManager needs to hook in here when other things are already done.
collabInstance.triggerCodemirrorChange(changeList);
this.trigger("editorChange", this, changeList);
};

Expand Down
3 changes: 2 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ require.config({

// In various places in the code, it's useful to know if this is a dev vs. prod env.
// See Gruntfile for prod override of this to config.prod.js.
"envConfig": "bramble/config/config.dev"
"envConfig": "bramble/config/config.dev",
"simplewebrtc": "../node_modules/simplewebrtc/out/simplewebrtc.bundle",
},
map: {
"*": {
Expand Down