Source code for point.plugs.api

# point/plugs/api.py
#
#

""" Object Copy API. """

## IMPORTS

from point.utils import run_thr, error, get_exception, list_files, j
from point import Object, kernel, __version__

# imports

import urllib.parse
import urllib
import logging
import select
import socket
import time
import http
import sys
import os

# http imports

from http.server import HTTPServer, BaseHTTPRequestHandler

## hostname

try: hostname = socket.getfqdn()
except: hostname = "localhost"

port = 10102

## APIServer class

[docs]class APIServer(HTTPServer, Object): """ API server """ allow_reuse_address = True daemon_thread = True def __init__(p, *args, **kwargs): """ start the API server. """ HTTPServer.__init__(p, *args, **kwargs) Object.__init__(p) logging.warn("running on http://%s:%s/" % args[0]) p.time_start = time.time() p.time_in = time.time() p.stop = False p.running = False p.handlers = {} p.webmods = {} p.state = Object() p.state.register('whitelistenable', 0) p.state.register('whitelist', []) p.state.register('blacklist', []) p.state.register('disable', []) p.poll = select.poll() p.poll.register(p)
[docs] def start(p, *args, **kwargs): p.serve()
[docs] def exit(p): """ shutdown the API server. """ try: p.stop = True ; time.sleep(0.2) ; p.server_close() except Exception as ex: error()
[docs] def serve(p): """ serving loop. """ time.sleep(1) while not p.stop: p.running = True try: got = p.poll.poll(100) except Exception as ex: error() if got and not p.stop: try: p.handle_request() except Exception as ex: error() time.sleep(0.01) p.running = False
[docs] def entrypoint(p, request): """ check lists whether request should be allowed. """ ip = request.ip if not p.whitelistenable() and ip in p.blacklist(): logging.warn('api - denied %s' % ip) request.send_error(401) return False if p.whitelistenable() and ip not in p.whitelist(): logging.warn('api - denied %s' % ip) request.send_error(401) return False return True
[docs] def whitelistenable(p): """ enable whitelist? """ return p.state['whitelistenable']
[docs] def whitelist(p): """ return the whitelist. """ return p.state['whitelist']
[docs] def blacklist(p): """ return the black list. """ return p.state['blacklist']
[docs] def register(p, path, handler): """ add a web handler """ logging.warn('api - %s handler added' % path) path = urllib.parse.unquote_plus(path) p.handlers[path] = handler
[docs] def enable(p, what): """ enable an path. """ try: p.state['disable'].remove(what) logging.info('api - enabled %s' % str(what)) except ValueError: pass
[docs] def disable(p, what): """ disable an path. """ p.state['disable'].append(what) logging.info('api - disabled %s' % str(what))
[docs] def do(p, request): """ do a request """ path = urllib.parse.unquote_plus(request.path.strip()) try: path, query = path.split('?') except ValueError: query = "" for i in p.state['disable']: if i in path: logging.warn('api - %s - denied disabled %s' % (request.ip, i)) request.send_error(404) return try: splitted = path.split("/") try: target = splitted[1] except: target = path if len(splitted) == 1: target = splitted[1] else: target = splitted[1] func = p.handlers[target] result = func(p, request) p.time_in = time.time() return result except KeyError: logging.info("api - missing handler %s" % str(target)) except: error()
[docs] def handle_error(p, request, addr): """ log the error """ ex = get_exception() logging.warn('api error %s - %s' % (addr, ex)) ## RestReqeustHandler class
[docs]class APIHandler(BaseHTTPRequestHandler): """ timeserver request handler class """
[docs] def setup(p): """ called on each incoming request. """ BaseHTTPRequestHandler.setup(p) p.ip = p.client_address[0] p.name = p.ip p.size = 0
[docs] def write_header(p, type='text/plain'): """ write headers to the client. """ p.send_response(200) p.send_header('Content-type', '%s; charset=%s ' % (type,sys.getdefaultencoding())) p.send_header('Server', __version__) p.end_headers()
[docs] def handle_request(p): """ handle a REST request. """ try: result = p.server.do(p) if not result: return p.size = len(result) except Exception as ex: error() p.send_error(501) return p.wfile.close()
do_DELETE = do_PUT = do_GET = do_POST = handle_request
[docs] def log_request(p, code): """ log the request """ try: ua = p.headers['user-agent'] except: ua = "-" try: rf = p.headers['referer'] except: rf = "-" logging.info('api - %s %s' % (p.address_string(), code))
server = None
[docs]def api_home(server, handler): handler.wfile.write(bytes(""" POINT is a program that will allow you to register events that take place in life, so you can reconstruct things that happen to you if memory is lost. It is essential to be able to place the past in a proper context, so that you can be free to live a real life, instead of moving away from what is left behind. """, "utf-8")) handler.wfile.write(bytes("\n\nAPI INTERFACE\n\n", "UTF-8")) for func in server.handlers: handler.wfile.write(bytes("http://%s:%s/%s\n" % (hostname, port, str(func)), "utf-8"))
[docs]def api_all(server, handler): handler.write_header() o = Object() nr = 0 for fn in list_files(kernel.cfg.workdir): o.register(nr, "http://%s:%s/get/%s" % (hostname, port, fn.split(os.sep)[-1])) nr += 1 handler.wfile.write(bytes(o.to_json(indent=2), "utf-8"))
[docs]def api_get(server, handler): handler.write_header() fn = handler.path.split("/")[2] o = Object() o.load_file(j(kernel.cfg.workdir, fn)) handler.wfile.write(bytes(o.to_json(indent=2), "utf-8"))
[docs]def api_favicon(server, handler): ico = open("favicon.ico", "br").read() handler.wfile.write(ico)
[docs]def init(): server = APIServer((hostname, port), APIHandler) server.register("", api_home) server.register("all", api_all) server.register("get", api_get) server.register("favicon.ico", api_favicon) kernel.run["API"] = server run_thr(server.start, ())