From 88a5cd83b47a9dfb5a832936095c7b99ce0d8179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Tue, 25 Aug 2015 14:20:42 +0200 Subject: Implemented methods to fetch a list of available problems and the problem description. JavaScript no longer parses pythonic problem descriptions, instead they are loaded by server and JSONized. --- wsgi_server.py | 128 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 42 deletions(-) (limited to 'wsgi_server.py') diff --git a/wsgi_server.py b/wsgi_server.py index 0f70b40..9b3a51e 100644 --- a/wsgi_server.py +++ b/wsgi_server.py @@ -12,7 +12,15 @@ api = application = falcon.API() def get_json_payload(req, session_is_optional=False): - if not ((req.content_type == 'application/json') or (req.content_type == 'text/json')): + content_type_parts = req.content_type.split(';') + content_type = content_type_parts[0].strip() + encoding = 'utf-8' + if len(content_type_parts) > 1: + for part in content_type_parts[1:]: + subparts = part.strip().split('=') + if (len(subparts) == 2) and subparts[0] == 'charset': + encoding = subparts[1] + if not ((content_type == 'application/json') or (content_type == 'text/json')): raise falcon.HTTPUnsupportedMediaType('Unsupported content-type: {0}'.format(req.content_type)) length = req.get_header('Content-Length') if length is None: @@ -28,95 +36,121 @@ def get_json_payload(req, session_is_optional=False): except Exception as e: raise falcon.HTTPBadRequest('Error reading request', 'Error while reading the request body: {0}'.format(e.message)) try: - js = json.loads(txt, encoding="utf-8") + js = json.loads(txt.decode(encoding=encoding, errors='replace')) except ValueError as e: raise falcon.HTTPBadRequest('Error parsing JSON payload', 'Error while parsing the request as JSON: {0}'.format(e.message)) sid = js.get('sid') if sid is None: if session_is_optional: - return js + return js, None raise falcon.HTTPBadRequest('No Session', 'Request is missing a session-ID') del js['sid'] try: session = client.get_session_by_id(sid) except NoSuchSession: if session_is_optional: - return js + return js, None raise falcon.HTTPBadRequest('Session Expired', 'This user session has expired. Please log-in again.') - req.context['session'] = session - return js + return js, session -class Login(object): +class CodeqService(object): + """Base class for all CodeQ services. + It only support the POST method and JSON data. + Handles JSON decoding and encoding, and session retrieval which can be optional. + """ + session_is_optional = False + def on_post(self, req, resp): + js, session = get_json_payload(req, self.session_is_optional) + resp.body = json.dumps(self.process(js, session)) resp.cache_control = 'private, no-cache, no-store' - js = get_json_payload(req, True) + resp.content_type = 'application/json' + resp.status = falcon.HTTP_200 + + def process(self, js, session): + raise falcon.HTTPNotFound() + +class ProblemList(CodeqService): + session_is_optional = True + + def process(self, js, session): + language = js.get('language') + if language is None: + return {'code': 1, 'message': 'Language was not provided'} + else: + return {'code': 0, 'message': 'ok', 'problems': client.list_problems_in_groups(language)} + +class Login(CodeqService): + session_is_optional = True + + def process(self, js, old_session): username = js.get('username') password = js.get('password') if username is None: - response = {'code': 1, 'message': 'Username was not provided'} + return {'code': 1, 'message': 'Username was not provided'} elif password is None: - response = {'code': 2, 'message': 'Password was not provided'} + return {'code': 2, 'message': 'Password was not provided'} else: try: session = client.authenticate_and_create_session(username, password) except AuthenticationFailed: - response = {'code': 3, 'message': 'Username or password do not match'} + return {'code': 3, 'message': 'Username or password do not match'} else: - response = {'code': 0, 'message': 'OK', 'sid':session.get_sid()} - old_session = req.context.get('session') if old_session: old_session.destroy() - resp.body = json.dumps(response) - resp.content_type = 'application/json' - resp.status = falcon.HTTP_200 + return {'code': 0, 'message': 'OK', 'sid':session.get_sid()} -class Activity(object): +class Activity(CodeqService): def on_get(self, req, resp): resp.body = '{}' resp.status = falcon.HTTP_200 -class Query(object): - def on_post(self, req, resp): - resp.cache_control = 'private, no-cache, no-store' - js = get_json_payload(req) - session = req.context['session'] +class Query(CodeqService): + def process(self, js, session): step = js.get('step') if step is None: - response = {'code': 1, 'message': '"step" is not set'} + return {'code': 1, 'message': '"step" is not set'} else: prolog = session.get_prolog() if step == 'run': program = js.get('program') query = js.get('query') - language = js.get('language') - problem_group = js.get('problem_group') - problem = js.get('problem') + problem_id = js.get('problem_id') if program is None: - response = {'code': 2, 'message': 'No program specified'} + return {'code': 2, 'message': 'No program specified'} elif query is None: - response = {'code': 3, 'message': 'No query specified'} - elif language is None: - response = {'code': 4, 'message': 'Language identifier not given'} - elif problem_group is None: - response = {'code': 5, 'message': 'Problem group identifier not given'} - elif problem is None: - response = {'code': 6, 'message': 'Problem identifier not given'} + return {'code': 3, 'message': 'No query specified'} + elif problem_id is None: + return {'code': 4, 'message': 'Problem ID not given'} else: - messages, status, have_more = prolog.run_for_user(session.get_uid(), language, problem_group, problem, program, query) - response = {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} + messages, status, have_more = prolog.run_for_user(session.get_uid(), problem_id, program, query) + return {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} elif step == 'next': messages, status, have_more = prolog.step() - response = {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} + return {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} elif step == 'end': messages, status, have_more = prolog.end() - response = {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} + return {'code': 0, 'message': 'ok', 'terminal': {'messages': messages, 'status': status, 'have_more': have_more}} else: - response = {'code': 7, 'message': 'Unknown prolog step: {0}'.format(step)} + return {'code': 5, 'message': 'Unknown prolog step: {0}'.format(step)} - resp.body = json.dumps(response) - resp.content_type = 'application/json' - resp.status = falcon.HTTP_200 +class GetProblem(CodeqService): + def process(self, js, session): + language = js.get('language') + problem_group = js.get('problem_group') + problem = js.get('problem') + if language is None: + return {'code': 1, 'message': 'Language identifier not given'} + elif problem_group is None: + return {'code': 2, 'message': 'Problem group identifier not given'} + elif problem is None: + return {'code': 3, 'message': 'Problem identifier not given'} + else: + return {'code': 0, 'message': 'ok', 'data': session.get_problem_data(language, problem_group, problem)} + +problem_list = ProblemList() +api.add_route('/list_problems', problem_list) login = Login() api.add_route('/login', login) @@ -126,3 +160,13 @@ api.add_route('/activity', activity) query = Query() api.add_route('/query', query) + +get_problem = GetProblem() +api.add_route('/get_problem', get_problem) + +if __name__ == '__main__': + import logging + from waitress import serve + logger = logging.getLogger('waitress') + logger.setLevel(logging.DEBUG) + serve(application, host='0.0.0.0', port=8082) -- cgit v1.2.1