Initial commit
This commit is contained in:
385
client/jsFiles/SEAWebClientCommunication.js
Normal file
385
client/jsFiles/SEAWebClientCommunication.js
Normal file
@ -0,0 +1,385 @@
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// % COMMUNICATION
|
||||
|
||||
var timeoutID; // We need this ID to reset the timer every 30 seconds
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Server Sent Event
|
||||
|
||||
|
||||
function buildUpdateConnection() {
|
||||
// Establishes server-sent-event-connection, which is used for all sorts of
|
||||
// updates and exists as long as the client is running.
|
||||
// Executed at programstart (see also SEAWebClientMain.js).
|
||||
|
||||
var path = "http://" + hostPort + "/update";
|
||||
if (debugCommunication) {
|
||||
console.log("%cto server (SSE): " + path,
|
||||
"color:white;background:lightblue");
|
||||
}
|
||||
|
||||
try {
|
||||
var src = new EventSource(path);
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
alertify.prompt(
|
||||
"NETWORK ERROR",
|
||||
"Failed to establish connection to data-server at the given address!"
|
||||
+ "Try to enter HOST and PORT of the data-server manually!",
|
||||
hostPort, function(evt, value) {
|
||||
hostPort = value;
|
||||
buildUpdateConnection();
|
||||
}, function() {
|
||||
})
|
||||
}
|
||||
|
||||
src.onmessage = function(e) {
|
||||
var message = JSON.parse(e.data);
|
||||
if (message) {
|
||||
handleUpdateMessage(src, message);
|
||||
}
|
||||
};
|
||||
|
||||
src.onerror = function(e) {
|
||||
console.log(e);
|
||||
console.log('EVTSRC error')
|
||||
alertify
|
||||
.prompt(
|
||||
"NETWORK ERROR",
|
||||
"Failed to establish connection to data-server at the given address!"
|
||||
+ "Try to enter HOST and PORT of the data-server manually!",
|
||||
hostPort, function(evt, value) {
|
||||
hostPort = value;
|
||||
buildUpdateConnection();
|
||||
}, function() {
|
||||
})
|
||||
src.close();
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdateMessage(src, message) {
|
||||
// Handles incoming SSE-messages depending on type of message.
|
||||
|
||||
if (debugCommunication > 1) {
|
||||
console.log("%cfrom server (SSE): " + message.type,
|
||||
"color:white;background:lightgray", message);
|
||||
}
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// <---------------------------------------------------------------------------------BUG!!!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
resetTimer(src);
|
||||
switch (message.type) {
|
||||
// id-message: Confirms establishment of SSE-connection and determines
|
||||
// specific ID of the client
|
||||
case "id":
|
||||
for (var i = 0; i < swiper.length; i++) {
|
||||
swiper[i].removeAllSlides();
|
||||
}
|
||||
clientID = message.id;
|
||||
if ("device" in message) {
|
||||
if (message.device == "_inst_select") {
|
||||
clientTitle = "select instrument";
|
||||
console.log('IDselect')
|
||||
pushInitCommand("getblock?path=_inst_select&", "instrument selection");
|
||||
menuMode = true;
|
||||
sizeChange();
|
||||
} else {
|
||||
clientTitle = message.instrument + " " + message.device;
|
||||
console.log('loadBlocks')
|
||||
loadFirstBlocks();
|
||||
}
|
||||
document.title = "SEA "+clientTitle;
|
||||
} else {
|
||||
document.title = "SEA "+clientTitle + " " + message.title;
|
||||
}
|
||||
var header = document.getElementById("header");
|
||||
header.setAttribute("style", "width: auto;");
|
||||
header.innerHTML = clientTitle;
|
||||
console.log('ID', initCommands);
|
||||
nextInitCommand();
|
||||
break;
|
||||
// console-update-message: Confirms a command.
|
||||
case "command":
|
||||
var histories = document.getElementsByClassName("history");
|
||||
for (var i = 0; i < histories.length; i++) {
|
||||
var line = document.createElement('div');
|
||||
line.innerHTML = htmlEscape(message.line);
|
||||
line.style.color = "cornflowerblue";
|
||||
if (message.origin == "self") {
|
||||
line.style.fontWeight = "bold";
|
||||
}
|
||||
histories[i].appendChild(document.createElement('br'));
|
||||
histories[i].appendChild(line);
|
||||
histories[i].scrollTop = histories[i].scrollHeight;
|
||||
}
|
||||
var cmd = htmlEscape(message.line);
|
||||
if (commandHistory.indexOf(cmd) === -1) {
|
||||
commandHistory.unshift(cmd);
|
||||
}
|
||||
break;
|
||||
// console-update-message: Confirms execution of command.
|
||||
case "reply":
|
||||
var histories = document.getElementsByClassName("history");
|
||||
for (var i = 0; i < histories.length; i++) {
|
||||
var line = document.createElement('div');
|
||||
line.innerHTML = htmlEscape(message.line);
|
||||
line.style.color = "black";
|
||||
if (message.origin == "self") {
|
||||
line.style.fontWeight = "bold";
|
||||
} else if (message.origin == "async") {
|
||||
line.style.color = "green";
|
||||
if (!showAsync) continue;
|
||||
}
|
||||
histories[i].appendChild(line);
|
||||
histories[i].scrollTop = histories[i].scrollHeight;
|
||||
}
|
||||
break;
|
||||
// graph-message: Evokes redraw of graphics.
|
||||
case "graph":
|
||||
console.log("graph");
|
||||
createCharts2(message.graph);
|
||||
break;
|
||||
// redraw.message: Communicates changes requiring reset of a whole group
|
||||
case "redraw": // SHOULD BE TESTED
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// SPECIAL CASE: is message.title = "main possible? It should evoke
|
||||
// redraw of client
|
||||
|
||||
// special meaning: s < 0: replace slides in all swiper instances
|
||||
reqJSON(-1, "http://" + hostPort + "/getblock?path=" + message.path
|
||||
+ "&id=" + clientID, successHandler, errorHandler);
|
||||
|
||||
break;
|
||||
// graph-update-message:
|
||||
case "graph-update":
|
||||
//if (getUpdatesGraphics) {
|
||||
//timeServer = message.time;
|
||||
console.log("graph-update");
|
||||
updateCharts2(message.graph);
|
||||
//}
|
||||
break;
|
||||
// update-message: Communicates change of values.
|
||||
case "update":
|
||||
if (debugCommunication > 1) {
|
||||
console.log(message);
|
||||
}
|
||||
updateValues(message, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function htmlEscape(str) {
|
||||
if (!str) return "";
|
||||
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g,
|
||||
''').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
function resetTimer(src) {
|
||||
// Executed every time a heartbeat-message is obtained.
|
||||
// If no heartbeat-messages are obtained for a certain amount of time,
|
||||
// an error-message is thrown.
|
||||
|
||||
clearTimeout(timeoutID);
|
||||
timeoutID = setTimeout(function(src) {
|
||||
console.log("timeout");
|
||||
alertify.error("connection lost");
|
||||
if (src) {
|
||||
src.close();
|
||||
}
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
function updateValues(message, src) {
|
||||
// Handles changes of parameter-values
|
||||
|
||||
for (var i = 0; i < message.updates.length; i++) {
|
||||
var component = message.updates[i];
|
||||
var value = component.value;
|
||||
var matches = document.getElementsByName(component.name);
|
||||
for (var j = 0; j < matches.length; j++) {
|
||||
var type = matches[j].getAttribute("__ctype__");
|
||||
if (type == "rdonly") {
|
||||
var text = htmlEscape(value);
|
||||
if (text) {
|
||||
matches[j].innerHTML = text;
|
||||
}
|
||||
} else if (type == "input") {
|
||||
var row = matches[j].parentNode.parentNode.parentNode;
|
||||
row.style.backgroundColor = "white";
|
||||
var oldValue = matches[j].getAttribute("oldValue")
|
||||
|| matches[j].value;
|
||||
if (value != matches[j].value && value != oldValue) {
|
||||
if (matches[j] == document.activeElement
|
||||
|| oldValue != matches[j].value) {
|
||||
row.style.backgroundColor = "orange";
|
||||
} else {
|
||||
matches[j].value = value;
|
||||
}
|
||||
}
|
||||
matches[j].setAttribute("actualValue", value);
|
||||
resizeTextfield(matches[j]);
|
||||
} else if (type == "checkbox") {
|
||||
var row = matches[j].parentNode.parentNode;
|
||||
row.style.backgroundColor = "white";
|
||||
matches[j].checked = value == 1 && value == "1";
|
||||
} else if (type == "enum") {
|
||||
matches[j].style.display = "block";
|
||||
var row = matches[j].parentNode.parentNode;
|
||||
row.style.backgroundColor = "white";
|
||||
matches[j].value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// XMLHttpRequest
|
||||
|
||||
function reqJSON(s, url, successHandler, errorHandler) {
|
||||
var xhr = typeof XMLHttpRequest != 'undefined' ? new XMLHttpRequest()
|
||||
: new ActiveXObject('Microsoft.XMLHTTP');
|
||||
if (debugCommunication) {
|
||||
console.log("%cto server (reqJSON): " + url,
|
||||
"color:white;background:lightgreen");
|
||||
}
|
||||
xhr.open('get', url, true);
|
||||
xhr.onreadystatechange = function() {
|
||||
// console.log(xhr)
|
||||
var status;
|
||||
var data;
|
||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
|
||||
if (xhr.readyState == 4) { // `DONE`
|
||||
status = xhr.status;
|
||||
if (status == 200) {
|
||||
data = JSON.parse(xhr.responseText);
|
||||
successHandler && successHandler(s, data);
|
||||
} else {
|
||||
errorHandler && errorHandler(status);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function successHandler(s, message) {
|
||||
// Handles incoming XMLHttp-messages depending on type of message.
|
||||
// s: slide number or -1 for replacing slide in all slider instances
|
||||
if (debugCommunication) {
|
||||
console.log("%cfrom server (reqJSON): " + message.type,
|
||||
"color:white;background:dimgray", message);
|
||||
}
|
||||
switch (message.type) {
|
||||
// Response to a "getblock"-server-request.
|
||||
case "draw":
|
||||
if (debugCommunication) {
|
||||
console.log(message);
|
||||
}
|
||||
if (message.path == "main") {
|
||||
// Happens only initially or at device change.
|
||||
for (var sLocal = 0; sLocal < MAXBLOCK; sLocal++) {
|
||||
insertSlide(sLocal, message.title, "main", createContent(
|
||||
sLocal, message));
|
||||
}
|
||||
} else {
|
||||
if (s < 0) { // redraw: check for slides in all swiper instances
|
||||
for (var isw = 0; isw < MAXBLOCK; isw ++) {
|
||||
var slide = findSlide(isw, message.path);
|
||||
if (slide) {
|
||||
console.log("redraw", isw);
|
||||
replaceSlideContent(slide, message.title,
|
||||
createContent(isw, message));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
insertSlide(s, message.title, message.path, createContent(s,
|
||||
message));
|
||||
}
|
||||
}
|
||||
nextInitCommand();
|
||||
// Request for updates.
|
||||
if (getUpdates) {
|
||||
reqJSON(s, "http://" + hostPort + "/updateblock?path="
|
||||
+ message.path + "&id=" + clientID, successHandler,
|
||||
errorHandler);
|
||||
}
|
||||
break;
|
||||
// Response to a "update-block"-server-request.
|
||||
case "accept-block":
|
||||
break;
|
||||
// Response to a "console"-server-request.
|
||||
case "accept-console":
|
||||
// draw console, only on the first and the last swiper
|
||||
insertSlide(0, "console", "console",
|
||||
createContentConsole(sLocal));
|
||||
insertSlide(3, "console", "console",
|
||||
createContentConsole(sLocal));
|
||||
nextInitCommand();
|
||||
// send empty command in order to trigger getting history
|
||||
reqJSON(0, "http://" + hostPort + "/sendcommand?command=&id=" + clientID, successHandler,
|
||||
errorHandler);
|
||||
break;
|
||||
// Response to a "gettime"-server-request.
|
||||
case "time":
|
||||
timeRange = message.time;
|
||||
/*createGraphics();
|
||||
// By default mostleft swiper-instance shows graphics.
|
||||
swiper[0].slideTo(0);
|
||||
|
||||
// Update time-selection. (see also SEAWebClientGraphics.js)
|
||||
var select = document.getElementsByClassName("select-time")[0];
|
||||
begin = timeRange[0] - timeRange[1];
|
||||
select.value = begin;
|
||||
// Server-request for variable-list.*/
|
||||
reqJSON(0, "http://" + hostPort + "/getvars?time=" + timeRange + "&id="
|
||||
+ clientID, successHandler, errorHandler);
|
||||
break;
|
||||
// Response to a "getvars"-server-request.
|
||||
case "var_list":
|
||||
//blocks = message.blocks;
|
||||
/*var varlist = [];
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
for (var j = 0; j < blocks[i].curves.length; j++) {
|
||||
varlist.push(blocks[i].curves[j].name);
|
||||
}
|
||||
}
|
||||
// Update graphics
|
||||
if (varlist.length > 0) {
|
||||
reqJSON(0, "http://" + hostPort + "/graph?time=" + timeRange
|
||||
+ "&variables=" + varlist + "&id=" + clientID,
|
||||
successHandler, errorHandler);
|
||||
} else {
|
||||
nextInitCommand();
|
||||
}*/
|
||||
graphs.receivedVars(message.blocks);
|
||||
nextInitCommand();
|
||||
break;
|
||||
// Response to a "graph"-server-request.
|
||||
case "graph-draw":
|
||||
// obsolete?
|
||||
if (debugCommunication) {
|
||||
console.log("graph-draw", message);
|
||||
}
|
||||
createCharts2(message.graph);
|
||||
nextInitCommand();
|
||||
// Request for updates.
|
||||
reqJSON(s, "http://" + hostPort + "/updategraph?id=" + clientID,
|
||||
successHandler, errorHandler);
|
||||
break;
|
||||
// Response to a "updategraph"-server-request.
|
||||
case "accept-graph":
|
||||
break;
|
||||
case "error":
|
||||
console.log("%cError-Message received!", "color:white;background:red");
|
||||
console.log(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function errorHandler(status) {
|
||||
if (debugCommunication) {
|
||||
console.log("error", status);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user