summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorAleš Smodiš <aless@guru.si>2015-10-08 18:56:48 +0200
committerAleš Smodiš <aless@guru.si>2015-10-08 18:56:48 +0200
commit76bfb287b51bd97c9ca0bfc4e7760b7ee8e15b47 (patch)
tree1124ec688054e2adb31f8a12c84115ec55381d7a /web
parentb6eeda1a66da16f90d02dd5d439d5cc5088c1a88 (diff)
Reworked session handling.
* All requests have a session ID, except for the initial create_session system messages. * User session can be in an authenticated or anonymous state. * In anonymous state it is not possible to perform user actions. * Logout has been implemented. * Sessions timeout and are cleared after a period of inactivity (1 hour). * Bugfixed the lang setting handling. * Renamed get_problem -> get_current_solution, return only the user's current solution, not the whole problem data.
Diffstat (limited to 'web')
-rw-r--r--web/main.js172
1 files changed, 118 insertions, 54 deletions
diff --git a/web/main.js b/web/main.js
index 37729b9..b3c096f 100644
--- a/web/main.js
+++ b/web/main.js
@@ -32,12 +32,29 @@ var server = new engine.Server({
});
http_server.on('request', function (request, response) {
- var uriParts = request.url.split('/'); // uriParts[0] will be an empty string, because uri must start with a /
+ var uriParts = request.url.split('/'), // uriParts[0] will be an empty string, because uri must start with a /
+ params, session;
logger.debug('HTTP server request, URL: ' + request.url);
if ((uriParts.length <= 1) || (uriParts[1] === 'ws')) {
- server.handleRequest(request, response);
+ if ((uriParts.length == 3) && (uriParts[2].substring(0, 7) === 'logout?')) {
+ // special logout service
+ params = uriParts[2].substring(7).split('&')[0].split('=');
+ if ((params.length == 2) && (params[0] === 'sid')) {
+ session = sessions[params[1]];
+ if (session) {
+ logger.debug('Logging out via AJAX, sid=' + params[1]);
+ guiHandlers.logout(session, {'sid': params[1], 'action': 'logout'});
+ }
+ }
+ response.writeHead(200, {'Content-Type': 'text/plain'});
+ response.write('OK');
+ response.end();
+ }
+ else {
+ server.handleRequest(request, response);
+ }
}
else {
response.writeHead(404, {'Content-Type': 'text/plain'});
@@ -59,69 +76,83 @@ var sessions = {
// GUI action handlers, keyed by the action name, values are functions that take the session and the message, or truthy values
var guiHandlers = {
// special-case action handlers
- 'login': function actionLogin(session, message) {
- // first-time connect: login
- var tid = message['tid']; // remember any TID that is set
- delete message['tid']; // delete any TID, we must use an internal one
- logger.debug('Received a login request from GUI');
- sendDataToPython(message).then(
- function loginRequestOK(response) {
+ 'logout': function actionLogout(session, message) {
+ // logout, the user quit the app
+ logger.debug('Logout GUI');
+ sendDataToPython(message).finally(function () {
+ session.end({'type': 'reset', 'code': 9999, 'message': 'Bye.'});
+ }).done();
+ },
+
+ // actions to use default handling should define truthy values that are not functions
+ // (this is to filter out unnecessary traffic before it hits Python)
+ 'login': true,
+ 'signup': true,
+ 'change_password': true,
+ 'activity': true,
+ 'query': true,
+ 'python_exec': true,
+ 'python_push': true,
+ 'python_stop': true,
+ 'hint': true,
+ 'test': true,
+ 'get_current_solution': true,
+ 'update_settings': true,
+ 'load_problem': true,
+ 'end_problem': true,
+ 'system': true
+};
+
+var system_handlers = {
+ 'create_session': function (session, message) {
+ sendDataToPython({'action': 'create_session'})
+ .then(function (response) {
var sid, existingSession;
- if ((typeof tid !== 'undefined') && (tid !== null)) response['tid'] = tid;
- else delete response['tid'];
if (response.code !== 0) {
- logger.debug('Python rejected login request from GUI');
- session.end(response);
+ logger.debug('Python rejected create_session request from GUI');
+ session.send({'type': 'reset', 'message': response.message});
}
else {
- logger.debug('Python accepted login request from GUI');
+ logger.debug('Python accepted create_session request from GUI');
session.sid = sid = response.sid;
existingSession = sessions[sid];
sessions[sid] = session;
- session.send(response);
- if (existingSession) {
- existingSession.end({'code': -40, 'message': 'Supplanted with a new connection for the same session', 'sid': sid});
+ if (existingSession && (existingSession !== session)) {
+ existingSession.end({'type': 'reset', 'message': 'Supplanted with a new connection for the same session', 'sid': sid});
}
+ session.send({'type': 'sid', 'sid': sid});
}
- },
- function loginRequestFailed(err) {
- var response = {
- 'code': -30
- },
- reason;
- logger.debug('Failed to request login from Python');
- if ((typeof tid !== 'undefined') && (tid !== null)) response['tid'] = tid;
- if ((typeof err === 'object') && (err !== null)) reason = err.toString();
- else reason = '' + err;
- response['message'] = 'Login request failed: ' + reason;
- session.end(response);
- }
- ).done();
- },
-
- 'logout': function actionLogout(session, message) {
- // logout, the user quit the app
- logger.debug('Logout GUI');
- sendDataToPython(message).finally(function () {
- session.end({'code': 9999, 'message': 'Bye.'});
- }).done();
+ })
+ .catch(function (error) {
+ session.send({'type': 'reset', 'message': 'Could not create a new session: ' + (error || 'unknown error')});
+ })
+ .done();
},
- // actions to use default handling should define truthy values that are not functions
- // (this is to filter out unnecessary traffic before it hits Python)
- 'signup': true,
- 'change_password': true,
- 'activity': true,
- 'query': true,
- 'python_exec': true,
- 'python_push': true,
- 'python_stop': true,
- 'hint': true,
- 'test': true,
- 'get_problem': true,
- 'settings': true,
- 'load_problem': true,
- 'end_problem': true
+ 'connect_session': function (session, message) {
+ sendDataToPython({'action': 'login', 'sid': session.sid, 'username': message.username, 'password': message.password})
+ .then(function (response) {
+ var sid, existingSession;
+ if (response.code !== 0) {
+ logger.debug('Python rejected connect_session request from GUI');
+ session.send({'type': 'reset', 'message': response.message});
+ }
+ else {
+ logger.debug('Python accepted connect_session request from GUI');
+ session.sid = sid = response.sid;
+ existingSession = sessions[sid];
+ sessions[sid] = session;
+ if (existingSession && (existingSession !== session)) {
+ existingSession.end({'type': 'reset', 'message': 'Supplanted with a new connection for the same session', 'sid': sid});
+ }
+ session.send({'type': 'sid', 'sid': sid});
+ }
+ })
+ .catch(function (error) {
+ session.send({'type': 'reset', 'message': 'Could not connect the existing session: ' + (error || 'unknown error')});
+ })
+ .done();
+ }
};
server.on('connection', function (socket) {
@@ -205,6 +236,14 @@ server.on('connection', function (socket) {
return;
}
+ if (typeof m.type === 'string') {
+ // a system (meta) protocol message
+ handler = system_handlers[m.type];
+ if (!handler) logger.error('Received an unknown system message from client: ' + m.type);
+ else handler(session, m);
+ return;
+ }
+
tid = m['tid']; // transaction ID
if (typeof tid !== 'number') {
fatal({"code": -3, "message": "Transaction ID is missing or is not an integer."});
@@ -266,6 +305,10 @@ server.on('connection', function (socket) {
});
});
+//var sessionActivityTimeout = setInterval(function () {
+// var sid;
+//}, 4200000); // once every 70 minutes
+
// ========== Python server connection ==========
@@ -304,6 +347,27 @@ var processPacketFromPython = function processPacketFromPythonFunc(packetString)
return;
}
+ if (typeof m.type === 'string') {
+ // system (meta) protocol message
+ switch (m.type) {
+ case 'session_expire':
+ if (typeof m.sid === 'string') {
+ session = sessions[m.sid];
+ if (session) session.end({'type': 'reset', 'message': 'Session expired'}); // send a system message to force the client to reset
+ else logger.warn('Received the session_expire system message from Python for a sid not handled by me: ' + m.sid);
+ }
+ else {
+ logger.error('Received the session_expire system message from Python, but no sid was included');
+ }
+ break;
+
+ default:
+ logger.warn('An unknown system message from Python: ' + m.type);
+ break;
+ }
+ return;
+ }
+
if ((typeof m.tid !== 'undefined') && (m.tid !== null)) {
if ((typeof m.tid === 'string') && (m.tid.charAt(0) === 'i')) {
// internal TID: only one way to key this one