/************************************************************************************************************************* File: alternateConnections.js Purpose: This file provides interface and utiltiy methods for communicating with the server from the view. See the individual function documentation for details on what each one does. Written by John McGorey - Spring 2019 - Using Microsoft Visual Studio Code 2019 For use in the St. Norbert College CSCI460 Senior Capstone Experience **************************************************************************************************************************/ const url = "http://localhost:3000/"; // Change this to reflect where the server is being hosted const start_page_url = "index.html"; // This is the filename of the start page // URL Parameter Constants // These are used to send information to the server via the querystring const TRAIN_SPEED = "speed"; const TRAIN_ID = "train_id"; const TURNOUT_ID = "turnout_id"; // Response Status Constants const ERROR_STATUS = "ERROR"; // The requested operation was a failure const SUCCESS_STATUS = "SUCCESS"; // The requested operation was a success // Network error handling variables const MAX_TIMEOUTS = 10; // Number of timeouts allowed before the client redirects to prompt the user to start a new server var TimeoutCount = 0; // The number of timeouts that have happened var RequestLock = false; // Bool flag to lock any further requests after too many timeouts have happened var firstCancel = true; // Flag to make to redirect prompt only show up once function startServer(options, callback) { /*************************************************************************************** Function: startServer Purpose: This function sends a request to the server to start a new simulator instance with the specified options. Input: options - an array containing key value pairs for configuring the simulator instance callback - The function to call when the server starts the new simulator instance ****************************************************************************************/ let request_url = url + "startServer/"; request_url += "?options=" + JSON.stringify(options); // Add the query string parameters console.log(request_url); sendRequest(request_url, function(status, response) { if (status == "SUCCESS") { callback(response); } else { alert('Cannot connect to the server right now. It is either not currently running or there is something wrong with the network.'); } }); } function stopServer() { /*************************************************************************************** Function: stopServer Purpose: This function sends a request to the server to stop the current simulation instance and redirects the user back to the start page to start a new one. ****************************************************************************************/ let request_url = url + "stopServer/"; sendRequest(request_url, function(status, resposnse) { window.location.href = start_page_url; }); } function getRails() { /*************************************************************************************** Function: getRails Purpose: This function sends a request to the server to get a list of the rails in the simulation & their statuses. The response from the server contains a JSON string describing the rails' information. This info is then parsed into an array of objects and passed on to the loadRails in sketch.js for processing ****************************************************************************************/ let request_url = url + "getRails/"; sendRequest(request_url, function(status, response) { if (status == SUCCESS_STATUS) { // In this case, the response is a JSON string containing a bunch of rail objects let rail_objs = JSON.parse(response); loadRails(rail_objs); // In sketch.js -> Populates the rails array } }); } function getTurnouts(callback) { /*************************************************************************************** Function: getTurnouts Purpose: This function sends a request to the server to get a list of the turnouts in the simulation & their statuses. The response from the server contains a JSON string describing the turnouts' information. This info is then parsed into an array of objects and passed on to the callback for processing Input: callback - The function to call when the server returns the list of turnouts ****************************************************************************************/ let request_url = url + "getTurnouts/"; sendRequest(request_url, function(status, response) { if (status == SUCCESS_STATUS) { // In this case, the response is a JSON string contaning all of the turnouts in the sim let turnout_objs = JSON.parse(response); if (callback) callback(turnout_objs); } }); } function getTrains(callback) { /*************************************************************************************** Function: getTrains Purpose: This function sends a request to the server to get a list of the trains in the simiulation & their statuses. The response from the server contains a JSON string containing the train information, which is parsed into an array of objects and passed on to the callback. Input: callback - The function to call when the server returns the list of trains ****************************************************************************************/ let request_url = url + "getTrains/"; sendRequest(request_url, function(status, response) { if (status == SUCCESS_STATUS) { // In this case, the response is a JSON string containing the trains in the sim let train_objs = JSON.parse(response); if (callback) callback(train_objs); } }); } function getLayouts(callback) { /*************************************************************************************** Function: getLayouts Purpose: This function sends a request to the server to get a list of the layouts that are possible to run a simulation on. These are passed back as a JSON string containing a list of strings. Then, they are parsed into a real list of strings and sent to a the callback for processing. Input: callback - The function to call when the server returns the list of layouts ****************************************************************************************/ let request_url = url + "getLayouts/"; sendRequest(request_url, function(status, response) { if (status == SUCCESS_STATUS) { // In this case, the response body will be a JSON array containing the layout names console.log("Get Layouts:", response); let layoutArr = JSON.parse(response); callback(layoutArr); // Call the callback using the layout array } }); } function setTrainSpeed(train_id, speed) { /*************************************************************************************** Function: setTrainSpeed Purpose: This function takes in a train id number and a speed value and sets the speed of the specified train to that value via an HTTP request to the server. Input: train_id - The id of the train whose speed to modify speed - The speed value to set the train to Note: There is nothing of import in the response to this request, so this function only logs if something went wrong. ****************************************************************************************/ let request_url = url + "setTrainSpeed/?"; request_url += TRAIN_ID + "=" + train_id; request_url += "&" + TRAIN_SPEED + "=" + speed; sendRequest(request_url, function(status, response) { if (status == "SUCCESS") { // Train speed updated successfully } else { console.log(response); // If something goes wrong, log it } }); } function switchTurnout(turnout_id) { /*************************************************************************************** Function: switchTurnout Purpose: This function takes in a turnout ID number and sends a request to the server to switch that particular turnout. Input: turnout_id - The id number of the turnout to switch ****************************************************************************************/ let request_url = url + "switchTurnout/?" + TURNOUT_ID + "=" + turnout_id; sendRequest(request_url, function(status, response) { console.log("Switching Turnout " + turnout_id + ": ", response); }); } function pauseServer() { /*************************************************************************************** Function: pauseServer Purpose: This function sends a request to the server to pause the simulation's update loop. ****************************************************************************************/ let request_url = url + "pauseServer/"; sendRequest(request_url, function(status, response) { // Do something with the response (ex: enable and disable controls) }); } function resumeServer() { /*************************************************************************************** Function: resumeServer Purpose: This function sends a request to the server to resume the simulation's update loop if it is paused. ****************************************************************************************/ let request_url = url + "resumeServer/"; sendRequest(request_url, function(status, response) { // Do something with the response (ex: enable and disable controls) }); } function sendRequest(requestUrl, callback) { /*************************************************************************************** Function: sendRequest Purpose: Sends an HTTP request to the URL specified by requestUrl. When the request returns with a response, execute the specified callback with status of the response and the response body. Input: requestUrl - The URL to send the http request to. If the request operation requires parameters, those should be added to the URL as a queryString before the URL is passed to this function. callback - The function to call when the request returns a response Output: (Via callback) status - Either ERROR_STATUS or SUCCESS_STATUS, depending if the response body contained the word 'Error'. request.response - The body of the response, containing the info the server sends back Note: If the request times out more than 10 times in a single run of a simulation, the user is redirected back to the start page to try again to start a new sim ****************************************************************************************/ if (!RequestLock) { // If the server hasn't locked up, continue sending requests let request = new XMLHttpRequest(); request.timeout = 10000; // Timeout of 10 seconds request.ontimeout = function() { console.log('Request timed out...'); TimeoutCount++; // Increment the number of times the server has timed out if (TimeoutCount > MAX_TIMEOUTS && firstCancel == true) { RequestLock = true; alert("Maximum number of Timeouts reached. Cannot service requests. Redirecting to server state page."); window.location.href = start_page_url; firstCancel = false; } } request.open('GET', requestUrl); request.onerror = function () { RequestLock = true; if (firstCancel == true) { alert('Cannot connect to the server right now. It is either not currently running or there is something wrong with the network.'); firstCancel = false; } } request.responseType = 'text'; request.onload = function() { // Determine if the request was successful let status; if (request.response.includes('Error')) status = ERROR_STATUS; else status = SUCCESS_STATUS; callback(status , request.response); }; // This function will be called when the HTTP request gets a response request.send(); // Send out the request and wait for a response } }