diff --git a/bootstrap.py b/bootstrap.py index e064b44..c935428 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -12,6 +12,7 @@ import yaml from flasgger import LazyJSONEncoder, Swagger from flask import Response from flask_restful import Api +import threading import hub_api.helpers.session_helper as sh from hub_api.catalogs.construction_catalog import ConstructionCatalogEntry, ConstructionCatalogEntries, ConstructionCatalogNames @@ -69,4 +70,5 @@ with open("hub_api/docs/openapi-specs.yml", "r") as stream: def home(): return Response(headers={'Access-Control-Allow-Origin': '*'}) -app.run(port=15789, host="0.0.0.0", debug=True) +threading.Thread(target=sh.session_garbage_collector, daemon=True, args="5").start() +app.run(port=15789, host="0.0.0.0", debug=True) \ No newline at end of file diff --git a/hub_api/docs/openapi-specs.yml b/hub_api/docs/openapi-specs.yml index 439eb68..ec1cb92 100644 --- a/hub_api/docs/openapi-specs.yml +++ b/hub_api/docs/openapi-specs.yml @@ -20,7 +20,7 @@ paths: description: Retrieve current API uptime responses: '200': - description: Request sucessful + description: Request successful content: application/json: schema: @@ -172,13 +172,13 @@ components: properties: result: type: string - example: 'OK' + example: 'succeed' login_succeed: type: object properties: result: type: string - example: 'OK' + example: 'succeed' cities: type: array example: [{'name': 'city 1', 'geometric_level_of_detail': '1'}, {'name': 'city 2', 'geometric_level_of_detail': '1'}] \ No newline at end of file diff --git a/hub_api/helpers/session_helper.py b/hub_api/helpers/session_helper.py index 5060971..50e79fc 100644 --- a/hub_api/helpers/session_helper.py +++ b/hub_api/helpers/session_helper.py @@ -5,6 +5,7 @@ Copyright © 2022 Project Author name guillermo.gutierrezmorote@concordia.ca """ import uuid import datetime +import time sessions = {} begin_time = None @@ -55,75 +56,45 @@ class SessionData: return usage_catalog -def clear_old_sessions(): +def session_garbage_collector(session_timeout_duration): #loop through all sessions and remove expired sessions - if bool(sessions): - for session in list(sessions): - _expire = datetime.datetime.strptime(sessions[session]['expire'], '%Y-%m-%d %H:%M:%S.%f') + while(True): + if bool(sessions): + for session in list(sessions): + _expire = datetime.datetime.strptime(sessions[session]['expire'], '%Y-%m-%d %H:%M:%S.%f') + if _expire < datetime.datetime.now(): + print("session with session_id: ", session, "expired.") + del sessions[session] - if _expire < datetime.datetime.now(): - del sessions[session] + time.sleep(60*int(session_timeout_duration)) + +def _validate_session(session_id, token, application_uuid): + try: + if bool(sessions[session_id]) and sessions[session_id]['token'] == token and \ + sessions[session_id]['application_uuid'] == application_uuid: + return True + except: + return False -def _validate_session(session_id, token, application_id): - print(sessions) - print(session_id) - print(token) - print(application_id) - if bool(sessions[session_id]) and sessions[session_id]['token'] == token and \ - sessions[session_id]['application_id'] == application_id: - return True - return False - - -def remove_session(request): +def remove_session(session_id, token, application_uuid): """ Remove a session from the sessions array """ - session = eval(request.headers.get('session')) - session_id = session['session_id'] - token = session['token'] - ip = request.remote_addr - valid, i = _valid_session(session_id, ip, token) - if valid: - del sessions[i] - return valid + if _validate_session(session_id, token, application_uuid): + del sessions[session_id] + return True + return False -def refresh_session(request): +def refresh_session(session_id, token, application_uuid): """ Validate and extend current session - :return: valid, token, city + :return: valid session """ - session_id = request.headers.get('session_id', None) - token = request.headers.get('token', None) - application_id = request.headers.get('application_id', None) - - if _validate_session(session_id, token, application_id): + if _validate_session(session_id, token, application_uuid): sessions[session_id]['expire'] = str(datetime.datetime.now() + datetime.timedelta(minutes=5)) - sessions[session_id]['token'] = uuid.uuid4() + sessions[session_id]['token'] = str(uuid.uuid4()) return sessions[session_id] return None - ''' - session_header = request.headers.get('session') - print(session_header) - if session_header is None: - return None - session = eval(session_header) - session_id = session['session_id'] - token = session['token'] - ip = request.remote_addr - valid, i = _valid_session(session_id, ip, token) - if valid: - if session_id == 'debug': - new_token = 'debug' - else: - new_token = str(uuid.uuid4()) - expire = str(datetime.datetime.now() + datetime.timedelta(minutes=5)) - sessions[i]['token'] = new_token - sessions[i]['expire'] = expire - return SessionData(sessions[i]) - else: - return None - ''' diff --git a/hub_api/session.py b/hub_api/session.py index 71381ac..5846a9a 100644 --- a/hub_api/session.py +++ b/hub_api/session.py @@ -12,7 +12,7 @@ from flask import request, Response from flask_restful import Resource from hub_api.config import Config -from hub_api.helpers.session_helper import remove_session, clear_old_sessions, sessions, refresh_session +from hub_api.helpers.session_helper import remove_session, sessions, refresh_session class SessionStart(Resource, Config): @@ -45,7 +45,6 @@ class SessionStart(Resource, Config): "geometric_level_of_detail": city.level_of_detail }) sessions[session_id] = session - clear_old_sessions() response = Response(json.dumps({'cities': session['cities'], 'result': 'OK'}), status=200) response.headers['session_id'] = session_id response.headers['token'] = token @@ -59,19 +58,28 @@ class SessionEnd(Resource): @staticmethod def put(): - if remove_session(request): - return Response(json.dumps({'result': 'succeed'})) + session_id = request.headers.get('session_id', None) + token = request.headers.get('token', None) + application_uuid = request.headers.get('application_uuid', None) + + if remove_session(session_id, token, application_uuid): + return Response(json.dumps({'result': 'succeed'}), status=200) return Response(json.dumps({'error': 'unauthorized'}), status=403) class KeepSessionAlive(Resource): def __init__(self): pass - # todo : finish implementing KeepSessionAlive and include error handling for missing invalid session_id or empty sessions + @staticmethod def put(): - session = refresh_session(request) + session_id = request.headers.get('session_id', None) + token = request.headers.get('token', None) + application_uuid = request.headers.get('application_uuid', None) + session = refresh_session(session_id, token, application_uuid) + if session is None: return Response(json.dumps({'error': 'unauthorized'}), status=403) - response = {'result': 'succeed'} - return Response(json.dumps(response), headers=headers) + response = Response(json.dumps({'result': 'succeed'}), status=200) + response.headers['token'] = session['token'] + return response diff --git a/requirements.txt b/requirements.txt index 3c4548a..5e1f1e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,4 +26,4 @@ flagger==3.1.0 flasgger cerc-hub python-dotenv - +mapbox_earcut