# zot/plugs/api.py
#
#
""" Object Copy API. """
__copyright__ = "Copyright 2015, B.H.J Thate"
## IMPORTS
from zot.utils import run_thr, error, get_exception, list_files, j, get_source
from zot.object import Object
from zot.defaults import cfg_api
from zot.runtime import kernel, cfg
from zot import __version__
import urllib.parse
import urllib
import logging
import select
import socket
import time
import http
import cgi
import sys
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
## DEFINES
port = 10102
server = None
## HANDLERS
handlers = Object()
## APIServer class
[docs]class API(HTTPServer, Object):
""" API server """
allow_reuse_address = True
daemon_thread = True
def __init__(zelf, *args, **kwargs):
""" start the API server. """
HTTPServer.__init__(zelf, *args, **kwargs)
Object.__init__(zelf)
zelf.host = args[0]
zelf._status = "init"
zelf._last = time.time()
zelf._start = time.time()
[docs] def exit(zelf):
""" shutdown API. """
logging.warn("# exit API.")
zelf._status = ""
time.sleep(0.2)
zelf.shutdown()
[docs] def start(zelf, *args, **kwargs):
""" serving requests. """
logging.warn("# start API at http://%s:%s" % zelf.host)
zelf._status = "running"
zelf.ready()
zelf.serve_forever()
[docs] def handle_request(zelf):
zelf._last = time.time()
[docs] def handle_error(zelf, request, addr):
""" log the error """
ex = get_exception()
logging.warn('%s - %s' % (addr, ex))
## RestReqeustHandler class
[docs]class APIHandler(BaseHTTPRequestHandler):
""" timeserver request handler class """
[docs] def setup(zelf):
""" called on each incoming request. """
BaseHTTPRequestHandler.setup(zelf)
zelf._ip = zelf.client_address[0]
zelf._size = 0
[docs] def write_header(zelf, type='text/plain'):
""" write headers to the client. """
zelf.send_response(200)
zelf.send_header('Content-type', '%s; charset=%s ' % (type, "utf-8"))
zelf.send_header('Server', __version__)
zelf.end_headers()
[docs] def handle_request(zelf):
""" handle a REST request. """
zelf.parsed = urllib.parse.urlparse(zelf.path)
path = "/" + zelf.parsed[2].split("/")[1]
try:
for functor in handlers[path]:
result = functor.func(zelf, zelf.request)
except KeyError as ex: logging.info("# missing %s" % str(ex))
except: error()
do_DELETE = do_PUT = do_GET = do_POST = handle_request
[docs] def log_request(zelf, code):
""" log the request """
try: ua = zelf.headers['user-agent']
except: ua = "-"
try: rf = zelf.headers['referer']
except: rf = "-"
logging.warn('# %s %s %s' % (zelf.address_string(), code, zelf.path))
[docs]def api_home(handler, request):
server, port = handler.server.host
handler.write_header()
handler.wfile.write(bytes("ZOTBOT API INTERFACE\n\n", "utf-8"))
for func in handlers.keys():
handler.wfile.write(bytes("http://%s:%s%s\n" % (server, port, func), "utf-8"))
handler.wfile.flush()
[docs]def api_all(handler, request):
o = Object()
nr = 0
server, port = handler.server.host
root = kernel.get_root()
for fn in list_files(root):
o[nr] = "http://%s:%s/get%s" % (server, port, fn.split(root)[-1])
nr += 1
handler.write_header()
handler.wfile.write(bytes(o.json(indent=2), "utf-8"))
handler.wfile.flush()
[docs]def api_get(handler, request):
fn = os.sep.join(handler.path.split("/")[2:])
root = kernel.get_root()
path = os.path.normpath(os.path.expanduser(j(root, fn)))
o = Object()
o.load(path)
txt = o.json(indent=2, ensure_ascii=False, sort_keys=True)
handler.write_header()
handler.wfile.write(bytes(txt, "utf-8"))
handler.wfile.flush()
[docs]def api_show(handler, request):
fn = os.path.join(handler.path.split("/")[2:])
root = kernel.get_root()
path = os.path.normpath(j(root, *fn))
o = Object()
o.load(path)
txt = o.pretty(indent=2, sort_keys=True)
txt = txt.replace("\\n", "\n")
txt = txt.replace("\\t", "\t")
handler.write_header()
handler.wfile.write(bytes(txt, "utf-8"))
handler.wfile.flush()
[docs]def init(*args, **kwargs):
from zot.runtime import kernel
api = API((cfg_api.hostname, int(cfg.port or cfg_api.port)), APIHandler)
handlers.register("/", api_home)
handlers.register("/all", api_all)
handlers.register("/get", api_get)
handlers.register("/show", api_show)
kernel.put(api.start)