summaryrefslogtreecommitdiff
path: root/js/codeq
diff options
context:
space:
mode:
authorAleš Smodiš <aless@guru.si>2015-09-14 17:00:51 +0200
committerAleš Smodiš <aless@guru.si>2015-09-14 17:00:51 +0200
commit43b3578dd8bf93cbfca7f5203175ac6dda6ec412 (patch)
tree42c9456c044ad3ee209406664fb61072e901d02d /js/codeq
parent18a575e02816622706f740e9938515869b58a375 (diff)
Implemented async delivery of server events.
Fixed center alignment: only the login page needs to be centered.
Diffstat (limited to 'js/codeq')
-rw-r--r--js/codeq/comms.js209
1 files changed, 50 insertions, 159 deletions
diff --git a/js/codeq/comms.js b/js/codeq/comms.js
index f32b4db..de6f918 100644
--- a/js/codeq/comms.js
+++ b/js/codeq/comms.js
@@ -1,157 +1,3 @@
-/*(function () {
-
- var send = function (service, json) {
- if (json instanceof Object) json = codeq.jsonize(json);
- return Q.Promise(function (resolve, reject, notify) {
- $.ajax({
- 'type': 'POST',
- 'url': codeq.urlPrefix + service,
- 'accepts': 'application/json',
- 'contentType': 'application/json; charset=UTF-8', // type of our request
- 'data': json,
- 'processData': false, // don't process outgoing data
- 'dataType': 'json', // expected type of the response
- 'timeout': 60000, // one minute
- 'error': function sendErrorHandler(jqXHR, textStatus, errorThrown) {
- reject(new Error(errorThrown || textStatus));
- },
- 'success': function sendSuccessHandler(data, textStatus, jqXHR) {
- resolve(data);
- }
- });
- });
- };
-
- var activities = {}, // keyed by problem_id: activity info waiting to be sent to the server
- activityKeys = [], // the keys to activities dictionary
- resolveActivity = function (promiseResolvers) {
- var i;
- // signal everyone that the queue is flushed
- for (i = 0; i < promiseResolvers.length; i++) {
- try {
- promiseResolvers[i][0]();
- }
- catch (e) {}
- }
- promiseResolvers.length = 0;
- },
- sendActivityInternal = function () {
- var activityKey, activityDescriptor, trace, sendCount;
- // send max. 100 activities, do not be excessive
- if (activityKeys.length == 0) return;
- activityKey = activityKeys[0];
- activityDescriptor = activities[activityKey];
- trace = activityDescriptor.trace;
- if (trace.length > 100) {
- sendCount = 100;
- trace = trace.slice(0, 100);
- }
- else {
- sendCount = trace.length;
- }
- send('activity', {'trace': trace, 'solution': activityDescriptor.solution, 'problem_id': activityDescriptor.problem_id, 'sid': codeq.sid}).then(
- function sendActivitySuccess() {
- activityDescriptor.trace.splice(0, sendCount);
- if (activityDescriptor.trace.length > 0) sendActivityInternal();
- else {
- delete activities[activityKey];
- activityKeys.shift();
- resolveActivity(activityDescriptor.promiseResolvers);
- }
- },
- function sendActivityFailure() {
- Q.delay(500).then(sendActivityInternal).done();
- }
- ).done();
- };
-
- codeq.comms = {
- sendActivity: function commsSendActivity (trace, solution, problem_id) {
- return Q.Promise(function (resolve, reject, notify) {
- var triggerSending = activityKeys.length == 0,
- activityDescriptor = activities[problem_id],
- problemTrace, promiseResolvers, i;
- if (!activityDescriptor) {
- problemTrace = [];
- promiseResolvers = [];
- activityDescriptor = {
- 'problem_id': problem_id,
- 'trace': problemTrace,
- 'solution': solution,
- 'promiseResolvers': promiseResolvers
- };
- activities[problem_id] = activityDescriptor;
- activityKeys.push(problem_id);
- }
- else {
- problemTrace = activityDescriptor.trace;
- promiseResolvers = activityDescriptor.promiseResolvers;
- if (solution) activityDescriptor.solution = solution;
- }
- if (trace instanceof Array) {
- for (i = 0; i < trace.length; i++) {
- problemTrace.push(trace[i]);
- }
- }
- else {
- problemTrace.push(trace);
- }
- promiseResolvers.push([resolve, reject]);
- if (triggerSending) {
- setTimeout(sendActivityInternal, 0); // async trigger: see if you can collect some more payload
- }
- });
- },
-
- sendQuery: function commsSendQuery (query, problem_id) {
- var existingActivity = activities[problem_id],
- tmp;
- query['sid'] = codeq.sid;
- if (existingActivity) {
- tmp = query['trace'];
- if (tmp) {
- // the trace will be sent separately, so it will be in the proper order
- tmp.splice(0, 0, existingActivity.trace.length, 0); // add two parameters in front, they will form the first two parameters to the following splice() invocation
- existingActivity.trace.splice.apply(existingActivity.trace, tmp);
- delete query['trace'];
- }
- tmp = query['program'];
- if (tmp) existingActivity.solution = tmp;
- }
- return send('query', query);
- },
-
- sendPush: function commsSendPush (json) {
- json['sid'] = codeq.sid;
- return send('python_push', json);
- },
-
- sendPull: function commsSendPull (json) {
- json['sid'] = codeq.sid;
- return send('python_pull', json);
- },
-
- sendHint: function commsSendHint (json) {
- json['sid'] = codeq.sid;
- return send('hint', json);
- },
-
- sendTest: function commsSendTest (json) {
- json['sid'] = codeq.sid;
- return send('test', json);
- },
-
- getProblem: function commsGetProblem (language, problem_group, problem) {
- return send('get_problem', {
- 'sid': codeq.sid,
- 'language': language,
- 'problem_group': problem_group,
- 'problem': problem
- });
- }
- };
-})();*/
-
(function () {
var BinaryMessageError = function (message) {
var e = new Error(message);
@@ -182,10 +28,10 @@
reconnectTimer = null,
login_username = null,
login_password = null,
-
waiters = {}, // keyed by TID: {packet, created, promise}
connected = false,
connectPromise = null,
+ requestHandlers = {}, // handlers for requests (events) from the server, keyed by event ID, value is an array of handlers
handleIncomingMessageError = function (error, data) {
if (error instanceof BinaryMessageError) {
codeq.log.error('Incoming message is not a string, attempting reconnect');
@@ -215,7 +61,7 @@
}
},
onMessage = function (data) {
- var m, waiter;
+ var m, waiter, event, handlers, i, N;
try {
m = parseData(data);
@@ -237,11 +83,25 @@
codeq.log.debug('There is noone waiting for the incoming message, TID=' + m.tid);
}
}
- else {
- codeq.log.debug('Incoming message without a TID, handing it off to handlers');
+
+ event = m.event;
+ if (typeof event !== 'string') {
+ codeq.log.warn('Incoming message without a TID and with no event name, dropping it on the floor: ' + data);
+ return;
}
- // TODO handle message delivery
+ handlers = requestHandlers[event];
+ if (!handlers) {
+ codeq.log.warn('Incoming event message cannot be handled: no handler registered for ' + event);
+ return;
+ }
+
+ N = handlers.length;
+ for (i = 0; i < N; i++) {
+ setTimeout((function (handler) {return function () {
+ handler(m);
+ }})(handlers[i]), 0);
+ }
},
onConnect = function () {
var tid, sortedWaiters = [], i;
@@ -417,6 +277,37 @@
'problem_group': problem_group,
'problem': problem
});
+ },
+
+ 'on': function (event, handler) {
+ var handlers = requestHandlers[event],
+ N, i;
+ if (!handlers) {
+ handlers = [handler];
+ requestHandlers[event] = handlers;
+ return;
+ }
+ N = handlers.length;
+ for (i = 0; i < N; i++) {
+ if (handlers[i] === handler) return; // already registered
+ }
+ handlers.push(handler);
+ },
+
+ 'off': function (event, handler) {
+ var handlers = requestHandlers[event],
+ N, i;
+ if (!handlers) return; // none registered
+ N = handlers.length;
+ for (i = 0; i < N; i++) {
+ if (handlers[i] === handler) {
+ handlers.splice(i, 1);
+ if (handlers.length === 0) {
+ delete requestHandlers[event];
+ }
+ return;
+ }
+ }
}
};
})();