diff options
| author | Terry Truong <terry06890@gmail.com> | 2022-07-09 03:20:53 +1000 |
|---|---|---|
| committer | Terry Truong <terry06890@gmail.com> | 2022-07-09 04:36:52 +1000 |
| commit | 5569c8191ae02f109254282b5943e3ed40032018 (patch) | |
| tree | 0ec5c2f6176c470aaeaa41be9bfbb0825554b764 | |
| parent | 347f5127929b17671c75734af5a374ec4f39b5ae (diff) | |
Replace CGI script with WSGI script and dev server
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | backend/README.md | 9 | ||||
| -rwxr-xr-x | backend/server.py | 18 | ||||
| -rwxr-xr-x | backend/tilo.py (renamed from backend/cgi-bin/data.py) | 67 | ||||
| -rw-r--r-- | src/App.vue | 2 | ||||
| -rw-r--r-- | src/lib.ts | 2 | ||||
| -rw-r--r-- | vite.config.js | 2 |
7 files changed, 57 insertions, 44 deletions
@@ -30,3 +30,4 @@ /backend/data/pickedEnwikiLabels.txt /backend/data/pickedNodes.txt /backend/data/pickedNames.txt +/backend/__pycache__ diff --git a/backend/README.md b/backend/README.md index 3a56f76..358ed72 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,8 +1,9 @@ # Files -- cgi-bin/data.py: CGI script for providing tree-of-life data to client +- server.py: Basic dev server that serves a WSGI script +- tilo.py: WSGI script that serves tree-of-life data - data: Contains scripts for generating the tree-of-life database # During development -Having generated the database as data/data.db, running `python3 -m http.server --cgi 8000`, -in this directory, allows the client to access the CGI script, and hence the database, -via `localhost:8000/cgi-bin/data.py`. +Having generated the database as data/data.db, running `server.py`, +in this directory, allows the client to access data from `tilo.py`, +via `localhost:8000`. diff --git a/backend/server.py b/backend/server.py new file mode 100755 index 0000000..a00ab7f --- /dev/null +++ b/backend/server.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys +from wsgiref.simple_server import make_server +from tilo import application + +usageInfo = f""" +Usage: {sys.argv[0]} + +Runs a basic dev server that serves a WSGI script +""" +if len(sys.argv) > 1: + print(usageInfo, file=sys.stderr) + sys.exit(1) + +with make_server('', 8000, application) as httpd: + print("Serving HTTP on port 8000...") + httpd.serve_forever() diff --git a/backend/cgi-bin/data.py b/backend/tilo.py index c1ea181..2f49baa 100755 --- a/backend/cgi-bin/data.py +++ b/backend/tilo.py @@ -13,9 +13,9 @@ ROOT_NAME = "cellular organisms" usageInfo = f""" Usage: {sys.argv[0]} -CGI script that provides tree-of-life data, in JSON form. +WSGI script that serves tree-of-life data, in JSON form. -Query parameters: +Expected HTTP query parameters: - name: Provides a name, or partial name, of a tree-of-life node. If absent, the root node is used. - type: Specifies what data to reply with. If 'node', reply with a name-to-TolNode map, describing the named node and it's children. @@ -219,22 +219,12 @@ def lookupInfo(name, tree, dbCur): ) if n != None else None for n in [name] + subNames ] return InfoResponse(nodeInfoObjs[0], nodeInfoObjs[1:]) +def getTableSuffix(tree): + return "t" if tree == "trimmed" else "i" if tree == "images" else "p" -# For handling request -def respondJson(val): - content = jsonpickle.encode(val, unpicklable=False).encode("utf-8") - print("Content-type: application/json") - if "HTTP_ACCEPT_ENCODING" in os.environ and "gzip" in os.environ["HTTP_ACCEPT_ENCODING"]: - if len(content) > 100: - content = gzip.compress(content, compresslevel=5) - print(f"Content-length: {len(content)}") - print(f"Content-encoding: gzip") - print() - sys.stdout.flush() - sys.stdout.buffer.write(content) -def handleReq(dbCur): +def handleReq(dbCur, environ): # Get query params - queryStr = os.environ["QUERY_STRING"] if "QUERY_STRING" in os.environ else "" + queryStr = environ["QUERY_STRING"] if "QUERY_STRING" in environ else "" queryDict = urllib.parse.parse_qs(queryStr) # Set vars from params name = queryDict["name"][0] if "name" in queryDict else None @@ -246,8 +236,7 @@ def handleReq(dbCur): tree = queryDict["tree"][0] if "tree" in queryDict else "images" # Check for valid 'tree' if tree != None and re.fullmatch(r"trimmed|images|picked", tree) == None: - respondJson(None) - return + return None # Get data of requested type if reqType == "node": toroot = queryDict["toroot"][0] if "toroot" in queryDict else None @@ -257,8 +246,7 @@ def handleReq(dbCur): tolNode = tolNodes[name] childNodeObjs = lookupNodes(tolNode.children, tree, dbCur) childNodeObjs[name] = tolNode - respondJson(childNodeObjs) - return + return childNodeObjs else: # Get ancestors to skip inclusion of nodesToSkip = set() @@ -279,8 +267,7 @@ def handleReq(dbCur): tolNodes = lookupNodes([name], tree, dbCur) if len(tolNodes) == 0: if not ranOnce: - respondJson(results) - return + return results print(f"ERROR: Parent-chain node {name} not found", file=sys.stderr) break tolNode = tolNodes[name] @@ -297,8 +284,7 @@ def handleReq(dbCur): results.update(childNodeObjs) # Check if root if tolNode.parent == None or tolNode.parent in nodesToSkip: - respondJson(results) - return + return results else: name = tolNode.parent elif reqType == "sugg": @@ -314,20 +300,27 @@ def handleReq(dbCur): print(f"INFO: Invalid limit {suggLimit}", file=sys.stderr) # Get search suggestions if not invalidLimit: - respondJson(lookupSuggs(name, suggLimit, tree, dbCur)) - return + return lookupSuggs(name, suggLimit, tree, dbCur) elif reqType == "info": infoResponse = lookupInfo(name, tree, dbCur) if infoResponse != None: - respondJson(infoResponse) - return + return infoResponse # On failure, provide empty response - respondJson(None) -def getTableSuffix(tree): - return "t" if tree == "trimmed" else "i" if tree == "images" else "p" - -# Open db -dbCon = sqlite3.connect(dbFile) -dbCur = dbCon.cursor() -# Handle request -handleReq(dbCur) + return None +def application(environ, start_response): + global dbFile + # Open db + dbCon = sqlite3.connect(dbFile) + dbCur = dbCon.cursor() + # Get response object + val = handleReq(dbCur, environ) + # Construct response + data = jsonpickle.encode(val, unpicklable=False).encode() + headers = [("Content-type", "application/json")] + if "HTTP_ACCEPT_ENCODING" in environ and "gzip" in environ["HTTP_ACCEPT_ENCODING"]: + if len(data) > 100: + data = gzip.compress(data, compresslevel=5) + headers.append(("Content-encoding", "gzip")) + headers.append(('Content-Length', str(len(data)))) + start_response('200 OK', headers) + return [data] diff --git a/src/App.vue b/src/App.vue index e379a1d..77de7ca 100644 --- a/src/App.vue +++ b/src/App.vue @@ -780,7 +780,7 @@ export default defineComponent({ primeLoadInd(msg: string){ this.pendingLoadingRevealHdlr = setTimeout(() => { this.loadingMsg = msg; - }, 300); + }, 500); }, endLoadInd(){ clearTimeout(this.pendingLoadingRevealHdlr); @@ -7,7 +7,7 @@ import {LayoutOptions} from './layout'; import {getBreakpoint, Breakpoint, getScrollBarWidth, onTouchDevice} from './util'; // For server requests -const SERVER_URL = window.location.href + 'cgi-bin/data.py' +const SERVER_URL = window.location.href + 'data' export async function queryServer(params: URLSearchParams){ // Construct URL let url = new URL(SERVER_URL); diff --git a/vite.config.js b/vite.config.js index ebcdcd3..900daa2 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,7 +6,7 @@ export default defineConfig({ plugins: [vue()], server: { proxy: { - '/cgi-bin/data.py': 'http://localhost:8000' + '/data': 'http://localhost:8000' }, watch: { ignored: ['**/backend', '**/public'] |
