#!/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)