unitex-webservice/microService.py

243 lines
9.1 KiB
Python

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
__author__ = "Adler Neves"
__email__ = "adlerosn@gmail.com"
__title__ = None
__description__ = None
__license__ = 'MIT'
__copyright__ = 'Copyright 2017 Adler O. S. Neves'
__version__ = '0.0.1'
import sys
import json
from http.server import CGIHTTPRequestHandler, HTTPServer
from unitexActions import UnitexActions
from urllib.parse import urlparse
from urllib.parse import parse_qs
from urllib.parse import parse_qsl
from cgi import parse_multipart
from cgi import parse_header
import threading
APIKEY = None
try:
with open('apikey.txt') as f:
APIKEY = f.read().strip().splitlines()[0].strip()
if APIKEY == '':
APIKEY = None
except:
pass
class BackgroundFunction(threading.Thread):
def __init__(self, call, *args, **kwargs):
self._call = call
self._args = args
self._kwargs = kwargs
threading.Thread.__init__(self)
def run(self):
self._call(*self._args, **self._kwargs)
def urlQuerySplitter(path):
psd = urlparse(path)
ph = psd.path
qs = psd.query
qsl = parse_qsl(qs, keep_blank_values = True)
qsd = dict()
for key, val in qsl:
if key not in qsd:
qsd[key] = list()
qsd[key].append(val)
qsd2 = dict()
for key, val in qsd.values():
if len(val)<2:
qsd2[key]=val[0]
else:
qsd2=val
return ph, qsd2
class unitexMicroService(CGIHTTPRequestHandler):
def doApiKeyValidation(self):
rqp, qd = urlQuerySplitter(self.path)
if APIKEY is not None:
rak = None
if 'X-API-KEY' in self.headers or 'X_API_KEY' in self.headers:
if 'X-API-KEY' in self.headers:
rak = self.headers['X-API-KEY']
else:
rak = self.headers['X_API_KEY']
elif 'api-key' in qd:
if isinstance(qd['api-key'], list):
rak = qd['api-key'][0]
else:
rak = qd['api-key']
return rak == APIKEY
return True
def do_GET(self):
rqp, qd = urlQuerySplitter(self.path)
if not self.doApiKeyValidation():
self.replyJsonError(401)
else:
parts = list(filter(lambda a: len(a)>0,rqp.split('/')))
if len(parts) == 0:
self.send_response(200)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.end_headers()
content = sorted(UnitexActions.reopen_list(), key=int)
message = json.dumps(content)
self.wfile.write(bytes(message, "utf8"))
elif len(parts) == 2 and parts[0] == 'age' and parts[1].isnumeric():
age = 0
try:
age = int(parts[1])
except:
pass
uas = [
{'age':ua.newestAge,'id':ua.id}
for ua in UnitexActions.reopen_all()
if ua.newestAge >= age
]
self.send_response(200)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.end_headers()
content = uas
message = json.dumps(content)
self.wfile.write(bytes(message, "utf8"))
elif not parts[0].isnumeric():
self.replyJsonError(403)
elif len(parts) == 1:
try:
content = UnitexActions.reopen(parts[0])
self.send_response(200)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.end_headers()
message = json.dumps(True)
self.wfile.write(bytes(message, "utf8"))
except:
self.replyJsonError()
elif len(parts) >= 2:
try:
jsonable = None
content = UnitexActions.reopen(parts[0])
try:
jsonable = content._jsonable
except:
pass
if jsonable is None:
self.replyJsonError(500)
else:
okay = False
message = None
if len(parts) == 2 and parts[1] == 'all':
message = json.dumps(jsonable)
okay = True
elif len(parts) == 3 and parts[1] == 'all' and parts[2] == 'delete':
content.delete()
message = json.dumps(True)
okay = True
else:
try:
for i in range(2,len(parts)):
jsonable = jsonable[parts[i]]
message = json.dumps(jsonable)
okay = True
except:
pass
if okay:
self.send_response(200)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.end_headers()
self.wfile.write(bytes(message, "utf8"))
else:
self.replyJsonError(400)
except:
self.replyJsonError()
else:
self.replyJsonError(500)
return
def do_POST(self):
rqp, qd = urlQuerySplitter(self.path)
if not self.doApiKeyValidation():
self.replyJsonError(401)
else:
if 'Content-Type' not in self.headers:
self.replyJsonError(406)
elif 'Content-Length' not in self.headers:
self.replyJsonError(406)
else:
ctype, pdict = parse_header(self.headers['Content-Type'])
postedData = self.rfile.read(int(self.headers['Content-Length']))
postVars = None
if ctype == 'multipart/form-data':
print(pdict, postedData)
postVars = parse_multipart(postedData, pdict)
elif ctype == 'application/x-www-form-urlencoded':
postVars = parse_qs(postedData, keep_blank_values=True)
elif ctype in [
'application/json',
'application/x-javascript',
'text/javascript',
'text/x-javascript',
'text/x-json',
]:
charset = pdict.get('charset','utf-8')
postVars = json.loads(postedData.decode(charset,'ignore'))
else:
postVars = dict()
if len(qd) == 0:
corpus = postVars.get('corpus','')
lang = postVars.get('lang','')
assets = None
if len(corpus)==0 or len(lang)==0:
self.replyJsonError(406)
else:
ua = UnitexActions(corpus, lang, custom_assets=assets)
ua.planAll_shortcut()
self.send_response(200)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.send_header('Connection','close')
self.end_headers()
message = json.dumps(str(ua.id))
self.wfile.write(bytes(message, "utf8"))
self.close_connection = True
BackgroundFunction(ua.executePlanning).start()
else:
self.replyJsonError(500)
return
def replyJsonError(self, num=404, msg='null'):
self.send_response(num)
self.send_header('Access-Control-Allow-Origin','*')
self.send_header('Content-type','application/json; encoding=utf-8')
self.end_headers()
self.wfile.write(bytes(msg, "utf8"))
def main(argc, argv):
print('starting server...')
server_address = ('0.0.0.0', 5423)
httpd = HTTPServer(server_address, unitexMicroService)
print('running server...')
try:
httpd.serve_forever()
except KeyboardInterrupt:
print('Got a KeyboardInterrupt!')
print('stopping server...')
except Exception as e:
print('Got a "%s"!'%(str(e)))
print('stopping server...')
httpd.server_close()
print('server stopped')
if __name__ == '__main__':
main(len(sys.argv),sys.argv)