# standard import import json import os import logging import argparse import sys from http.server import ( HTTPServer, BaseHTTPRequestHandler, ) # external imports import confini from jsonrpc_std.parse import jsonrpc_from_str from jsonrpc_std.interface import jsonrpc_response # local imports from eth_stat_syncer.store import RunStore logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() default_config_dir = os.environ.get('CONFINI_DIR', './config') argparser = argparse.ArgumentParser() argparser.add_argument('-c', '--config', dest='c', default=default_config_dir, type=str, help='rpc provider') argparser.add_argument('--host', type=str, help='httpd host') argparser.add_argument('--port', type=str, help='httpd port') argparser.add_argument('--store-dir', dest='store_dir', type=str, help='syncerd data store base directory') argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') argparser.add_argument('-v', action='store_true', help='be verbose') argparser.add_argument('-vv', action='store_true', help='be more verbose') args = argparser.parse_args() if args.vv: logging.getLogger().setLevel(logging.DEBUG) elif args.v: logging.getLogger().setLevel(logging.INFO) config = confini.Config(args.c, args.env_prefix) config.process() # override args args_override = { 'HTTPD_HOST': getattr(args, 'host'), 'HTTPD_PORT': getattr(args, 'port'), 'STORE_BASE_DIR': getattr(args, 'store_dir'), } config.dict_override(args_override, 'cli flag') logg.debug('loaded config: {}\n'.format(config)) class StatRequestHandler(BaseHTTPRequestHandler): runstore = None server_version = 'eth_stat_syncer/0.0.1' def do_POST(self): if self.headers.get('Content-Type') != 'application/json': self.send_response(400, 'me read json only') self.end_headers() return if 'application/json' not in self.headers.get('Accept').split(','): self.send_response(400, 'me json only speak') self.end_headers() return l = self.headers.get('Content-Length') try: l = int(l) except ValueError: self.send_response(400, 'content length must be integer') self.end_headers() return if l > 4096: self.send_response(400, 'too much information') self.end_headers() return if l < 0: self.send_response(400, 'you are too negative') self.end_headers() return b = b'' c = 0 while c < l: d = self.rfile.read(l-c) if d == None: break b += d c += len(d) if c > 4096: self.send_response(413, 'i should slap you around for lying about your size') self.end_headers() return o = None err = None try: o = jsonrpc_from_str(b.decode('utf-8')) except JSONRPCException as e: err = e if err != None: res = e self.send_response(200, 'alas with jsonrpc error') else: r = self.runstore.get('high', 'minute') r = int(r) if r == 0: r = 1 res = jsonrpc_response(o['id'], r) logg.debug('returning {} for req {} {}'.format(r, o, self.requestline)) self.send_response(200, 'It\'s a gas') b = json.dumps(res).encode('utf-8') l = len(b) self.send_header('Content-Length', str(l)) self.send_header('Cache-Control', 'no-cache') self.send_header('Content-Type', 'application/json') self.end_headers() c = 0 while c < l: n = self.wfile.write(b[c:]) c += n def run(store, host=None, port=None): if host == None: host = '' if port == None: port = 8000 StatRequestHandler.runstore = store server_address = (host, port) httpd = HTTPServer(server_address, StatRequestHandler) httpd.serve_forever() if __name__ == '__main__': store = RunStore(basedir=config.get('STORE_BASE_DIR')) run(store, host=config.get('HTTPD_HOST'), port=config.get('HTTPD_PORT'))