webclient/js/Messaging.js

146 lines
3.6 KiB
JavaScript

import error as popError from GUI.Screen;
var wsLocation = window.location.origin.replace(/^http/, 'ws') + '/play/';
var ws;
var debug = getParameters().debug;
var doLog = debug != undefined && debug.match(/^(?:1|t(?:rue)?|v(?:rai)?)$/i);
var on = false;
var s = 1000; /* ms */
var keepAlivePeriod = 20;
var reconnectDelay = 1;
var routes = {callbacks: [], children: {}};
var messagesQueue = [];
var wsHandlers = {
open: [function() {on = true; reconnectDelay = 1}, catchUp, ping],
close: [function() {on = false;}, reconnect]
};
init();
return {
addEventListener: addEventListener,
isOn: isOn,
reset: reset,
send: send
};
function get(obj, path, write) {
write = write || false;
if(path.length < 1) {
return obj;
} else {
if(obj.children[path[0]] == undefined && write) {
obj.children[path[0]] = {callbacks: [], children: {}};
}
if(obj.children[path[0]] != undefined) {
return get(obj.children[path[0]], path.slice(1), write);
} else {
return null;
}
}
}
function getParameters() {
var o = {};
window.location.search.substr(1).split('&').forEach(function(s) {
var t = s.split('=');
o[t[0]] = t[1];
});
return o;
}
function addEventListener(path, callback) {
if(Array.isArray(path)) {
var route = get(routes, path, true);
route.callbacks.push(callback);
} else {
if(wsHandlers[path] != undefined) {
wsHandlers[path].push(callback);
} else {
log('Unsupported websocket event "' + path + '"');
}
}
}
function messageListener(event) {
var o = JSON.parse(event.data);
var path = [];
var tmp = o;
while(tmp != undefined && tmp.tag != undefined) {
path.push(tmp.tag);
tmp = tmp.message;
}
var route = get(routes, path);
if(route != undefined && route.callbacks != undefined) {
route.callbacks.forEach(function(f) {f(o);});
} else {
console.log("No route found for " + event.data);
}
o.direction = 'client < server';
log(o);
};
function send(o) {
if(isOn()) {
ws.send(JSON.stringify(o));
o.direction = 'client > server';
log(o);
} else {
messagesQueue.push(o);
}
}
function catchUp() {
var messages = messagesQueue;
messagesQueue = [];
messages.forEach(send);
}
function log(message) {
if(doLog) {
console.log(message);
}
}
function init() {
connect();
addEventListener(["Pong"], ping);
addEventListener(["Error"], function(o) {popError(o.error);});
}
function connect() {
ws = new WebSocket(window.location.origin.replace(/^http/, 'ws') + '/play/');
ws.addEventListener('message', messageListener);
ws.addEventListener('open', function(e) {
wsHandlers.open.forEach(function(handler) {handler(e);});
});
ws.addEventListener('close', function(e) {
wsHandlers.close.forEach(function(handler) {handler(e);});
});
}
function reconnect() {
setTimeout(connect, reconnectDelay * s);
if(reconnectDelay < 16) {
reconnectDelay *= 2;
}
}
function isOn() {
return on;
}
function ping() {
setTimeout(function() {
if(isOn()) {
send({tag: "Ping"});
}
}, keepAlivePeriod * s);
}
function reset() {
on = false; // this should be handled by the close event but when other operations are performed right after the reset, the event might not have had time to fire and the other functions, in particular send(), will assume the socket is still open and fail to actually send them instead of gently queueing them for when connectivity goes back up
reconnectDelay = 0.125; // since we're forcing the connection to close, there's no reason to assume the server went down so we manually lower the reconnectDelay to make the reconnection more fluid (there's no point making the user wait the usual 1 s. and the worse that could happen is we overflow the server a little with 3 connection attempts in 1 s.)
ws.close();
}