Skip to content

Commit

Permalink
Added connection loss reliability.
Browse files Browse the repository at this point in the history
  • Loading branch information
ashmind committed Sep 14, 2016
1 parent 094b88e commit 2e019e5
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 24 deletions.
41 changes: 41 additions & 0 deletions MirrorSharp.WebAssets/wwwroot/css/mirrorsharp.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,47 @@
font-size: inherit;
}

/*.mirrorsharp-status {
position: absolute;
width: 0.7em;
height: 0.7em;
right: 0.35em;
top: 0.35em;
transform: rotate(45deg);
opacity: 0.7;
}
.mirrorsharp-status-connected {
background-color: #2ecc71;
}*/

.mirrorsharp-connection-issue {
display: none;
position: absolute;
top: 0;
background: #aaa;
right: 0;
left: 0;
color: #fff;
padding: 0.2em 0.4em;
}

.mirrorsharp-connection-has-issue .mirrorsharp-connection-issue {
display: block;
}

.CodeMirror.mirrorsharp-connection-has-issue {
padding-top: 1.6em;
}

.CodeMirror.mirrorsharp-connection-has-issue .CodeMirror-code {
color: #aaa;
}

.CodeMirror.mirrorsharp-connection-has-issue .CodeMirror-code * {
color: inherit;
}

.mirrorsharp-hint {
display: flex;
padding-left: 0;
Expand Down
114 changes: 90 additions & 24 deletions MirrorSharp.WebAssets/wwwroot/js/mirrorsharp.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
(function (root, factory) {
/* globals define:false */
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['CodeMirror'], factory);
} else if (typeof module === 'object' && module.exports) {
Expand All @@ -7,21 +8,55 @@
root.mirrorsharp = factory(root.CodeMirror);
}
}(this, function (CodeMirror) {
function Connection(socket) {
const openPromise = new Promise(function(resolve) {
socket.addEventListener('open', function (e) {
//console.debug("[open]");
resolve();
});
'use strict';

function Connection(openSocket) {
var socket;
var openPromise;
const handlers = {
open: [],
message: [],
close: []
};

open();
on('close', function() {
setTimeout(function() { open(); }, 1000);
});

function open() {
socket = openSocket();
openPromise = new Promise(function (resolve) {
socket.addEventListener('open', function() {
resolve();
});
});

for (var key in handlers) {
const keyFixed = key;
const handlersByKey = handlers[key];
socket.addEventListener(key, function (e) {
var argument = (keyFixed === 'message') ? JSON.parse(e.data) : undefined;
for (var handler of handlersByKey) {
handler(argument);
}
});
}
}

function on(key, handler) {
handlers[key].push(handler);
}

function sendWhenOpen(command) {
openPromise.then(function () {
//console.debug("[=>]", command);
socket.send(command);
});
}

this.on = on;

this.sendReplaceText = function (isLastOrOnly, start, length, newText, cursorIndexAfter) {
const command = isLastOrOnly ? 'R' : 'P';
return sendWhenOpen(command + start + ':' + length + ':' + cursorIndexAfter + ':' + newText);
Expand All @@ -42,14 +77,6 @@
this.sendGetDiagnostics = function () {
return sendWhenOpen('D');
}

this.onMessage = function(handler) {
socket.addEventListener('message', function (e) {
//console.debug("[<=]", e.data);
const message = JSON.parse(e.data);
handler(message);
});
}
}

function Editor(textarea, connection, options) {
Expand All @@ -58,20 +85,39 @@
cmOptions.gutters.push('CodeMirror-lint-markers');
const cm = CodeMirror.fromTextArea(textarea, cmOptions);

var initialTextSent = false;
/*(function createStatusElement() {
const cmWrapper = cm.getWrapperElement();
const element = document.createElement('div');
element.className = 'mirrorsharp-status';
cmWrapper.appendChild(element);
connection.onOpen(function () {
element.classList.add('mirrorsharp-status-connected');
});
return element;
})();*/

var lintingSuspended = true;
var updateLinting;
(function sendOnStart() {
connection.on('open', function () {
hideConnectionLoss();

const text = cm.getValue();
if (text === '' || text == null) {
initialTextSent = true;
lintingSuspended = false;
return;
}

connection.sendReplaceText(true, 0, 0, text, 0);
initialTextSent = true;
connection.sendReplaceText(true, 0, 0, text, getCursorIndex(cm));
lintingSuspended = false;
if (updateLinting)
requestDiagnostics(text, updateLinting);
})();
});

connection.on('close', function () {
lintingSuspended = true;
showConnectionLoss();
});

const indexKey = '$mirrorsharp-index';
var changePending = false;
Expand Down Expand Up @@ -106,7 +152,7 @@
}
});

connection.onMessage(function (message) {
connection.on('message', function (message) {
switch (message.type) {
case 'changes':
applyChangesFromServer(message.changes);
Expand Down Expand Up @@ -174,7 +220,7 @@

function requestDiagnostics(text, updateLintingValue) {
updateLinting = updateLintingValue;
if (initialTextSent)
if (!lintingSuspended)
connection.sendGetDiagnostics();
}

Expand All @@ -201,10 +247,30 @@
if (clientCursorIndex !== serverCursorIndex)
console.error('Client cursor position does not match server position:', { clientPosition: clientCursorIndex, serverPosition: serverCursorIndex });
}

var connectionLossElement;
function showConnectionLoss() {
const wrapper = cm.getWrapperElement();
if (!connectionLossElement) {
connectionLossElement = document.createElement("div");
connectionLossElement.setAttribute('class', 'mirrorsharp-connection-issue');
connectionLossElement.innerText = 'Server connection lost, reconnecting…';
wrapper.appendChild(connectionLossElement);
}

wrapper.classList.add('mirrorsharp-connection-has-issue');
}

function hideConnectionLoss() {
cm.getWrapperElement().classList.remove('mirrorsharp-connection-has-issue');
}
}

return function(textarea, options) {
const connection = new Connection(new WebSocket(options.serviceUrl));
const connection = new Connection(function() {
return new WebSocket(options.serviceUrl);
});

return new Editor(textarea, connection, options);
}
}));
4 changes: 4 additions & 0 deletions MirrorSharp.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<s:String x:Key="/Default/CodeInspection/Browsers/Browsers/@EntryValue">C27+,E12+,FF21+,IE11+,S8+</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=70BCCC0E_002D6EEF_002D40D0_002D932A_002D87F9C42BD67B_002Fd_003Awwwroot_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=D2EB1CDD_002D12B5_002D4FDC_002DA56C_002D8A327200E759_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=Html_002EEventNotResolved/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ThisInGlobalContext/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ACCESSOR_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ACCESSOR_OWNER_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
Expand All @@ -11,6 +13,8 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/TYPE_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
Expand Down

0 comments on commit 2e019e5

Please sign in to comment.