summaryrefslogtreecommitdiff
path: root/js/codeq
diff options
context:
space:
mode:
Diffstat (limited to 'js/codeq')
-rw-r--r--js/codeq/comms.js130
-rw-r--r--js/codeq/core.js17
-rw-r--r--js/codeq/login.js6
-rw-r--r--js/codeq/problem_list.js2
4 files changed, 116 insertions, 39 deletions
diff --git a/js/codeq/comms.js b/js/codeq/comms.js
index 54a912f..54f5d24 100644
--- a/js/codeq/comms.js
+++ b/js/codeq/comms.js
@@ -69,7 +69,8 @@
}
},
onMessage = function (data) {
- var m, waiter, event, handlers, i, N;
+ var m, waiter, event, handlers, i, N,
+ tid, sortedWaiters = [], s;
try {
m = parseData(data);
@@ -79,6 +80,68 @@
return;
}
+ if ('type' in m) {
+ // system (meta) protocol
+ switch (m.type) {
+ case 'sid':
+ // the peer created or changed our session ID
+ sid = m.sid;
+ break;
+
+ case 'reset':
+ // the server forced us to reset to the login page
+ // * could not re-register the connection with an existing session ID, username, and password
+ // * the user logged in elsewhere
+ s = 'The server forced us to disconnect';
+ if (typeof m.message === 'string') s += ': ' + m.message;
+ codeq.reset(s);
+ return;
+
+ default:
+ codeq.log.warn('Unknown system message type: ' + m.type);
+ }
+ if (!connected) {
+ if (sid !== null) {
+ // our connection registration was successful
+ connected = true;
+ if (connectPromise) {
+ // manual connect
+ connectPromise.resolve();
+ connectPromise = null;
+ }
+ else {
+ // auto re-connect
+ }
+ // resend anything not already sent
+ for (tid in waiters) {
+ if (waiters.hasOwnProperty(tid)) {
+ sortedWaiters.push(waiters[tid]);
+ }
+ }
+ // sort by ascending transaction ID before sending
+ sortedWaiters.sort(function (a, b) {return a.tid - b.tid;});
+ for (i = 0; i < sortedWaiters.length; i++) {
+ (function (waiter) {
+ if (!waiter.sent) {
+ socket.send(JSON.stringify(waiter.packet), function () {
+ waiter.sent = true;
+ });
+ }
+ })(sortedWaiters[i]);
+ }
+ }
+ else {
+ codeq.log.error('Operating outside a session!');
+ codeq.reset('Protocol error: server sent a bogus message instead of acknowledging our connection');
+ }
+ }
+ return;
+ }
+
+ if (!connected) {
+ codeq.log.warn('Not in the connected state, but receiving a user message anyway');
+ }
+
if ('tid' in m) {
waiter = waiters[m.tid];
if (waiter) {
@@ -112,33 +175,9 @@
}
},
onConnect = function () {
- var tid, sortedWaiters = [], i;
- connected = true;
- if (connectPromise) {
- // manual connect
- connectPromise.resolve();
- connectPromise = null;
- }
- else {
- // auto re-connect
- }
- // resend anything not already sent
- for (tid in waiters) {
- if (waiters.hasOwnProperty(tid)) {
- sortedWaiters.push(waiters[tid]);
- }
- }
- // sort by ascending transaction ID before sending
- sortedWaiters.sort(function (a, b) {return a.tid - b.tid;});
- for (i = 0; i < sortedWaiters.length; i++) {
- (function (waiter) {
- if (!waiter.sent) {
- socket.send(JSON.stringify(waiter.packet), function () {
- waiter.sent = true;
- });
- }
- })(sortedWaiters[i]);
- }
+ // register our connection
+ if (sid === null) socket.send(JSON.stringify({'type': 'create_session'}));
+ else socket.send(JSON.stringify({'type': 'connect_session', 'sid': sid, 'username': login_username, 'password': login_password}));
},
onClose = function () {
connected = false;
@@ -209,6 +248,21 @@
ajaxResPrefix = ajaxPrefix + 'res/';
// ================================================================================
+ // Try to be polite and logout on page close/reload
+ // ================================================================================
+
+ window.onbeforeunload = function () {
+ if (sid) {
+ // we need to perform an action inside the current iteration of the event loop
+ // so no fancy promises etc., just the raw AJAX request
+ $.ajax({
+ type: 'GET',
+ url: '/ws/logout?sid=' + sid + '&t=' + Date.now()
+ });
+ }
+ };
+
+ // ================================================================================
// This module's API methods
// ================================================================================
@@ -245,7 +299,8 @@
return deferred.promise;
},
- 'disconnect': function () {
+ 'disconnect': function (reason) { // reason is optional
+ var tid;
if (socket) {
socket.off('open', onConnect);
socket.off('close', onClose);
@@ -264,6 +319,13 @@
}
login_password = null; // manual disconnect will prevent auto-login
sid = null;
+ // reject any outstanding promises
+ for (tid in waiters) {
+ if (waiters.hasOwnProperty(tid)) {
+ waiters[id].promise.reject(new Error(reason || 'Forced disconnect'));
+ delete waiters[tid];
+ }
+ }
},
'send': function (packet) {
return Q.Promise(function (resolve, reject, notify) {
@@ -321,7 +383,7 @@
},
'updateSettings': function (new_settings){
- return this.send({'action': 'settings', 'sid': sid, 'settings': new_settings});
+ return this.send({'action': 'update_settings', 'settings': new_settings});
},
sendActivity: function commsSendActivity (trace, solution, problem_id) {
@@ -358,12 +420,10 @@
return this.send(json);
},
- getProblem: function commsGetProblem (language, problem_group, problem) {
+ getCurrentSolution: function commsGetCurrentSolution (problem_id) {
return this.send({
- 'action': 'get_problem',
- 'language': language,
- 'problem_group': problem_group,
- 'problem': problem
+ 'action': 'get_current_solution',
+ 'problem_id': problem_id
});
},
diff --git a/js/codeq/core.js b/js/codeq/core.js
index 02bc2f0..d60c7e4 100644
--- a/js/codeq/core.js
+++ b/js/codeq/core.js
@@ -569,6 +569,23 @@
if (listeners[i] === callback) listeners.splice(i, 1);
}
}
+ },
+
+ // reset the app
+ 'reset': function (reason) {
+ codeq.log.info('App reset: ' + (reason || 'no reason given'));
+ codeq.globalStateMachine.transition('login');
+ codeq.wait(
+ codeq.comms.logout()
+ .finally(codeq.comms.disconnect)
+ .fail(function () {}) // ignore errors
+ )
+ .then(function () {
+ if (reason) {
+ alert(reason);
+ }
+ })
+ .done();
}
};
})();
diff --git a/js/codeq/login.js b/js/codeq/login.js
index d5bcd90..538cd3d 100644
--- a/js/codeq/login.js
+++ b/js/codeq/login.js
@@ -21,9 +21,9 @@
//merge these settings into the already existing default settings
var sett = data.settings;
$.merge(true, codeq.settings, sett);
- if('lan' in sett && sett['lan'] in codeq.supportedLangs){
- codeq.setLang(sett['lan']);
- $("#gui_lang_select").val(sett['lan']);
+ if('lang' in sett && sett['lang'] in codeq.supportedLangs){
+ codeq.setLang(sett['lang']);
+ $("#gui_lang_select").val(sett['lang']);
}
codeq.globalStateMachine.transition('language');
diff --git a/js/codeq/problem_list.js b/js/codeq/problem_list.js
index 1b20fe2..eae86ed 100644
--- a/js/codeq/problem_list.js
+++ b/js/codeq/problem_list.js
@@ -260,7 +260,7 @@
}
codeq.wait(
Q.all([
- codeq.comms.getProblem(language, ref.g, ref.p), // TODO: use ref.id instead // the current solution
+ codeq.comms.getCurrentSolution(ref.id), // the current user's solution to the selected problem
getProblemData(language, ref.g, ref.p) // the (cached) result of processProblemData()
])
.spread(function (userProblemData, generalProblemData) {