From 43b3578dd8bf93cbfca7f5203175ac6dda6ec412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Mon, 14 Sep 2015 17:00:51 +0200 Subject: Implemented async delivery of server events. Fixed center alignment: only the login page needs to be centered. --- js/codeq/comms.js | 209 +++++++++++++----------------------------------------- 1 file changed, 50 insertions(+), 159 deletions(-) (limited to 'js/codeq/comms.js') 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; + } + } } }; })(); -- cgit v1.2.1