Browse Source

Merge remote-tracking branch 'origin/master'

Roman Cardenas 5 years ago
parent
commit
36df8aadff
2 changed files with 202 additions and 0 deletions
  1. 74 0
      web_service/manage.py
  2. 128 0
      web_service/web_service.py

+ 74 - 0
web_service/manage.py

@@ -0,0 +1,74 @@
+
+import argparse
+import sqlite3
+import uuid
+
+DB_FILENAME = "db.sqlite"
+
+SQL_CREATE_USERS = \
+"""CREATE TABLE users (
+username TEXT PRIMARY KEY,
+api_key TEXT NOT NULL
+);"""
+
+
+SQL_CREATE_REQUESTS = \
+"""CREATE TABLE requests (
+id TEXT PRIMARY KEY,
+username TEXT NOT NULL,
+depth INTEGER NOT NULL,
+width INTEGER NOT NULL,
+int_cycles INTEGER NOT NULL,
+ext_cycles INTEGER NOT NULL,
+status TEXT NOT NULL,
+FOREIGN KEY(username) REFERENCES users(username)
+);"""
+
+SQL_INSERT_USER = "INSERT INTO users VALUES('{username}', '{api_key}');"
+SQL_DELETE_USER = "DELETE FROM users WHERE username='{username}';"
+
+conn = sqlite3.connect(DB_FILENAME)
+c = conn.cursor()
+
+
+def init_db():
+    c.execute(SQL_CREATE_USERS)
+    c.execute(SQL_CREATE_REQUESTS)
+
+
+def add_user(username):
+    api_key = uuid.uuid4().hex
+    sql = SQL_INSERT_USER.format(username=username, api_key=api_key)
+    c.execute(sql)
+    conn.commit()
+    print("User '%s' added succesfully (api_key: %s)" % (username, api_key))
+
+
+def remove_user(username):
+    sql = SQL_DELETE_USER.format(username=username)
+    c.execute(sql)
+    conn.commit()
+    print("User '%s' removed succesfully from DB" % username)
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(description='Script to manage the DB related to the DEVStone comparative web service.')
+
+    parser.add_argument('-i', '--init', action='store_true', help='Init the DB')
+    parser.add_argument('-a', '--add_user', type=str, help='Add a user to the DB')
+    parser.add_argument('-r', '--remove_user', type=str, help='Remove a user from the DB')
+
+    return parser.parse_args()
+
+
+if __name__ == '__main__':
+    args = parse_args()
+
+    if args.init:
+        init_db()
+
+    if args.add_user:
+        add_user(args.add_user)
+
+    if args.remove_user:
+        remove_user(args.remove_user)

+ 128 - 0
web_service/web_service.py

@@ -0,0 +1,128 @@
+#!/usr/bin/env python3
+import uuid
+from flask import Flask, request, jsonify, Response
+import sqlite3
+import os
+import time
+
+app = Flask(__name__)
+
+DB_FILENAME = "db.sqlite"
+SQL_INSERT_REQUEST = "INSERT INTO requests ('id', 'username', 'depth', 'width', 'int_cycles', 'ext_cycles', 'status') VALUES ('{request_id}', '{username}', '{depth}', '{width}', '{int_cycles}', '{ext_cycles}', '{status}');"
+SQL_SELECT_USERNAME = "SELECT username FROM users WHERE api_key='{api_key}'"
+SQL_SELECT_REQUEST_STATUS = "SELECT status FROM requests WHERE id='{request_id}'"
+SQL_UPDATE_STATUS = "UPDATE requests SET status='{status}' WHERE id='{request_id}'"
+
+
+def get_username_from_api_key(api_key):
+    conn = sqlite3.connect(DB_FILENAME)
+    c = conn.cursor()
+    sql = SQL_SELECT_USERNAME.format(api_key=api_key)
+    res = c.execute(sql).fetchall()
+    conn.close()
+    return res[0][0] if res else None
+
+
+def get_request_status(request_id):
+    conn = sqlite3.connect(DB_FILENAME)
+    c = conn.cursor()
+    sql = SQL_SELECT_REQUEST_STATUS.format(request_id=request_id)
+    res = c.execute(sql).fetchall()
+    conn.close()
+    return res[0][0] if res else None
+
+
+def submit_devstone(request_id, username, depth, width, int_cycles, ext_cycles):
+    conn = sqlite3.connect(DB_FILENAME)
+    c = conn.cursor()
+    sql = SQL_INSERT_REQUEST.format(request_id=request_id, username=username, depth=depth, width=width, int_cycles=int_cycles, ext_cycles=ext_cycles, status="pending")
+    c.execute(sql)
+    conn.commit()
+    conn.close()
+    # TODO: here it would be the devstone comparative script call
+    # time.sleep(5)
+    open("results/%s.csv" % request_id, "w").write(username)
+
+    conn = sqlite3.connect(DB_FILENAME)
+    sql = SQL_UPDATE_STATUS.format(request_id=request_id, status="finished")
+    c = conn.cursor()
+    c.execute(sql)
+    conn.commit()
+    conn.close()
+
+
+@app.route('/')
+def hello():
+    return 'Hey there! Ready to execute some DEVStone models?'
+
+
+@app.route('/run_devstone')
+def run_devstone():
+    try:
+        api_key = request.args["api_key"]
+    except Exception as e:
+        return jsonify({"status": "denied", "reason": "No api_key was specified."})
+    
+    try:
+        depth = int(request.args["depth"])
+        width = int(request.args["width"])
+        int_cycles = int(request.args["int_cycles"]) if "int_cycles" in request.args else 0
+        ext_cycles = int(request.args["ext_cycles"]) if "ext_cycles" in request.args else 0
+    except Exception as e:
+        return jsonify({"status": "denied", "reason": "Invalid params."})
+
+    # Check that api key exists
+    username = get_username_from_api_key(api_key)
+    if username is None:
+        return jsonify({"status": "denied", "reason": "Invalid api key."})
+
+    # Execute task
+    request_id = uuid.uuid4().hex
+    submit_devstone(request_id, username, depth, width, int_cycles, ext_cycles)
+    status_url = request.host_url + "status?request_id=" + request_id
+    return jsonify({"status": "submitted", "request_id": request_id, "status_url": status_url})
+
+
+@app.route('/status')
+def status():
+    try:
+        request_id = request.args["request_id"]
+    except Exception as e:
+        return jsonify({"status": "denied", "reason": "No request_id was specified."})
+    
+    status = get_request_status(request_id)
+    res = {"status": status, "request_id": request_id}
+    if status == "finished":
+        download_url = request.host_url + "download?request_id=" + request_id
+        res["download_link"] = download_url
+    
+    return jsonify(res)
+
+
+@app.route('/download')
+def download():
+    try:
+        request_id = request.args["request_id"]
+    except Exception as e:
+        return jsonify({"status": "denied", "reason": "No request_id was specified."})
+
+    status = get_request_status(request_id)
+    if status != "finished":
+        status_url = request.host_url + "status?request_id=" + request_id
+        return redirect(status_url)
+
+    with open("results/%s.csv" % request_id) as f:
+        csv = f.read()
+
+    return Response(
+        csv,
+        mimetype="text/csv",
+        headers={"Content-disposition":
+                 "attachment; filename=%s.csv" % request_id})
+
+
+if __name__ == '__main__':
+    if not os.path.exists('results'):
+        os.makedirs('results')
+        
+    app.run(debug=True, port=8080)