spaceapi-server/spaceapi_server/server/__init__.py

100 lines
2.8 KiB
Python
Raw Normal View History

2019-11-25 02:48:12 +01:00
import os
import sys
import json
import signal
import importlib
import bottle
from spaceapi_server import template, config
# The SpaceAPI response template instance
__TEMPLATE = None
def render_traverse(obj):
2019-11-25 03:14:14 +01:00
"""
2019-11-25 02:48:12 +01:00
Walk through a complex, JSON-serializable data structure, and pass
string objects through the Jinja2 templating engine.
2019-11-25 04:10:20 +01:00
:param obj: The object to traverse.
2019-11-25 03:14:14 +01:00
"""
2019-11-25 02:48:12 +01:00
if isinstance(obj, list):
# list -> recurse into each item
for i in range(len(obj)):
obj[i] = render_traverse(obj[i])
return obj
elif isinstance(obj, dict):
# dict -> recurse into the value of each (key, value)
for k, v in obj.items():
obj[k] = render_traverse(obj[k])
return obj
elif isinstance(obj, str):
# str -> template
return template.render(obj)
else:
# anything else -> return as-is
return obj
@bottle.route('/')
def serve():
global __TEMPLATE
# Render the response template
rendered = render_traverse(__TEMPLATE)
# Set the response Content-Type
bottle.response.content_type = 'application/json; charset=utf-8'
# CORS "whitelist"
# https://spaceapi.io/getting-started/#common-issues
bottle.response.headers['Access-Control-Allow-Origin'] = '*'
# Return the JSON-serialized rendered data as response body,
# indented with two spaces
return json.dumps(rendered, indent=2)
def load(*args, **kwargs):
global __TEMPLATE
# If a config file path was passed, load it
if len(sys.argv) > 1:
config.load(sys.argv[1])
# Get the current config
conf = config.get()
# Get the absoulute plugins dir path
plugin_dir = os.path.abspath(conf.get('plugins_dir', 'plugins'))
# Iterate the plugins dir and take all python files
for f in os.listdir(plugin_dir):
if f.endswith('.py'):
# Get the full name to the plugin file
plugin_fname = os.path.join(plugin_dir, f)
# Load the file as module and import it
# https://stackoverflow.com/a/67692
m_spec = importlib.util.spec_from_file_location(f[:-3], plugin_fname)
module = importlib.util.module_from_spec(m_spec)
m_spec.loader.exec_module(module)
# Get the template path
template_path = conf.get('template', 'template.json')
# Load and parse the JSON template
with open(template_path, 'r') as f:
__TEMPLATE = json.load(f)
def init():
# Register SIGHUP config reload handler
signal.signal(signal.SIGHUP, load)
# Prepare everything
load()
def start():
init()
# Start the HTTP server
conf = config.get()
bottle.run(
server=conf.get('server', 'wsgiref'),
host=conf.get('address', '::'),
port=int(conf.get('port', 8080))
)