Source code for slicops.pkcli.service

"""Start SlicOps services.

:copyright: Copyright (c) 2024 The Board of Trustees of the Leland Stanford Junior University, through SLAC National Accelerator Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy).  All Rights Reserved.
:license: http://github.com/slaclab/slicops/LICENSE
"""

from pykern.pkcollections import PKDict
from pykern.pkdebug import pkdc, pkdlog, pkdp
import slicops.pkcli
import tornado.httpclient
import tornado.web


[docs] class Commands(slicops.pkcli.CommandsBase):
[docs] def ui_api(self, tcp_port=None, prod=False): """Start UI API web server. This web server provides a friendly and secure API for SlicOps apps. Args: prod (bool): run in production mode (serve Vue statically) """ from pykern import pkconfig, pkresource from pykern.api import server from slicops import config, quest, sliclet, ui_api from tornado import web def _dev_uri_map(config): return [ ( # send any non-api call to the proxy rf"^(?!{config.api_uri}).*", _ProxyHandler, PKDict( proxy_url=f"http://localhost:{config.vue_port}", ), ), ] def _prod_uri_map(config): d = PKDict( # TODO(robnagler) package_path path=str(pkresource.file_path("vue")), default_filename="index.html", ) return [ # NOTE: StaticFileHandler requires match returns a group ( # very specific so we control the name space r"^/(assets/[^/.]+\.(?:css|js)|favicon.png|index.html|)$", web.StaticFileHandler, d, ), ( # vue index.html is returned for sliclet URLs rf"^/($|(?:{'|'.join(sliclet.names())})(?:$|/.*))", _VueIndexHandler, d, ), ] def _tcp_port(): return ( PKDict(tcp_port=pkconfig.parse_positive_int(tcp_port)) if tcp_port else PKDict() ) c = config.cfg().ui_api.copy() server.start( attr_classes=quest.attr_classes(), api_classes=ui_api.api_classes(), http_config=c.pkupdate( PKDict( uri_map=_prod_uri_map(c) if prod else _dev_uri_map(c), **_tcp_port(), ) ), )
class _ProxyHandler(tornado.web.RequestHandler): def initialize(self, proxy_url, **kwargs): super().initialize(**kwargs) self.http_client = tornado.httpclient.AsyncHTTPClient() self.proxy_url = proxy_url async def get(self): r = await self.http_client.fetch(f"{self.proxy_url}{self.request.uri}") self.set_status(r.code) self.set_header("Content-Type", r.headers["Content-Type"]) self.write(r.body) class _VueIndexHandler(tornado.web.StaticFileHandler): def get_absolute_path(self, root, path, *args, **kwargs): return super().get_absolute_path(root, self.default_filename)