def build_app(): if os.getuid() != 0: raise RuntimeError("need to be root, sorry about that") known_env_vars = ( "MESHPING_DATABASE_PATH", "MESHPING_PING_TIMEOUT", "MESHPING_PING_INTERVAL", "MESHPING_HISTOGRAM_DAYS", "MESHPING_PEERS", "MESHPING_PEERING_INTERVAL", "MESHPING_PROMETHEUS_URL", "MESHPING_PROMETHEUS_QUERY", "MESHPING_REDIS_HOST", ) deprecated_env_vars = ( "MESHPING_PROMETHEUS_URL", "MESHPING_PROMETHEUS_QUERY", "MESHPING_REDIS_HOST", ) for key in os.environ: if key.startswith("MESHPING_") and key not in known_env_vars: print("env var %s is unknown" % key, file=sys.stderr) sys.exit(1) if key.startswith("MESHPING_") and key in deprecated_env_vars: print("env var %s is deprecated, ignored" % key, file=sys.stderr) app = QuartTrio(__name__, static_url_path="") #app.config["TEMPLATES_AUTO_RELOAD"] = True app.secret_key = str(uuid4()) app.jinja_options = dict(variable_start_string='{[', variable_end_string=']}') @app.context_processor def _inject_icons(): # I'm not happy about hardcoding this path here, but I'm also not sure what else to do icons_dir = "/opt/meshping/ui/node_modules/bootstrap-icons/icons/" return dict( icons={ filename: Markup( open(os.path.join(icons_dir, filename), "r").read()) for filename in os.listdir(icons_dir) }) mp = MeshPing(int(os.environ.get("MESHPING_PING_TIMEOUT", 5)), int(os.environ.get("MESHPING_PING_INTERVAL", 30)), int(os.environ.get("MESHPING_HISTOGRAM_DAYS", 3))) add_api_views(app, mp) @app.before_serving async def _(): app.nursery.start_soon(mp.run) app.nursery.start_soon(run_peers, mp) return app
def register_blueprints(app: QuartTrio) -> None: """Register Flask blueprints / LNbits extensions.""" app.register_blueprint(core_app) for ext in get_valid_extensions(): try: ext_module = importlib.import_module(f"lnbits.extensions.{ext.code}") bp = getattr(ext_module, f"{ext.code}_ext") app.register_blueprint(bp, url_prefix=f"/{ext.code}") except Exception: raise ImportError( f"Please make sure that the extension `{ext.code}` follows conventions." )
def __init__(self, cfg: dict, worker: Worker, debug:bool=False): cfg = combine_dict(cfg, CFG, cls=attrdict) self.cfg = cfg self.main = None # Nursery self.clients = WeakValueDictionary() self.worker = worker self.sub_worker = WeakValueDictionary() self._sw_id = 0 self.version = worker.version or deframed.__version__ self.debug=debug or cfg.debug self.app = Quart(cfg.server.name, # no, we do not want any of those default folders and whatnot static_folder=None,template_folder=None,root_path="/nonexistent", ) #@self.app.route("/<path:p>", methods=['GET']) @self.app.route("/", defaults={"p":None}, methods=['GET']) async def index(p): # "path" is unused, the app will get it via Javascript mainpage = os.path.join(os.path.dirname(deframed.__file__), cfg.mainpage) with open(mainpage, 'r') as f: data = cfg.data.copy() data['debug'] = self.debug data['version'] = self.version if data['title'] == CFG.data.title: data['title'] = self.worker.title return Response(chevron.render(f, data), headers={"Access-Control-Allow-Origin": "*"}) @self.app.websocket('/ws') async def ws(): """Main websocket""" w = self.worker(self) await w.run(websocket._get_current_object()) @self.app.route("/sub/<int:sid>", methods=['GET']) async def index_sub(sid): """SubWorker main page""" w = self.sub_worker[sid] return await w.index() @self.app.websocket('/ws/<int:sid>') async def ws_sub(sid): """SubWorker websocket""" try: w = self.sub_worker[sid] except KeyError: raise NotFound else: await w.run(websocket._get_current_object()) static = os.path.join(os.path.dirname(deframed.__file__), cfg.data.static) @self.app.route("/static/<path:filename>", methods=['GET']) async def send_static(filename): print("GET",filename) return await send_from_directory(static, filename)
def create_app(config_object="lnbits.settings") -> QuartTrio: """Create application factory. :param config_object: The configuration object to use. """ app = QuartTrio(__name__, static_folder="static") app.config.from_object(config_object) app.asgi_http_class = ASGIProxyFix cors(app) Compress(app) check_funding_source(app) register_assets(app) register_blueprints(app) register_filters(app) register_commands(app) register_async_tasks(app) register_exception_handlers(app) return app
def mk_app(challenges): app = QuartTrio(__name__) @app.route("/.well-known/acme-challenge/<ch_code>") async def get_challenge(ch_code): log.debug(f"Got challenge request for {ch_code}") return challenges.get(ch_code) or ("Not Found", 404) @app.route("/ping") async def ping(): return "pong" return app
def register_blueprints(app: QuartTrio) -> None: """Register Flask blueprints / LNbits extensions.""" app.register_blueprint(core_app) for ext in get_valid_extensions(): try: ext_module = importlib.import_module( f"lnbits.extensions.{ext.code}") bp = getattr(ext_module, f"{ext.code}_ext") @bp.before_request async def before_request(): g.ext_db = open_ext_db(ext.code) @bp.teardown_request async def after_request(exc): g.ext_db.close() app.register_blueprint(bp, url_prefix=f"/{ext.code}") except Exception: raise ImportError( f"Please make sure that the extension `{ext.code}` follows conventions." )
def _make_app_marathon(marathon): from quart import jsonify, make_response, request app = QuartTrio(__name__) backend = marathon._backend @app.route("/v2/apps", methods=["GET"]) async def get_apps(): marathon._called_get_apps = True return jsonify({"apps": backend.get_apps()}) @app.route("/v2/apps", methods=["POST"]) async def post_apps(): app = await request.json await backend.add_app(app) return jsonify(app) @app.route("/v2/events", methods=["GET"]) async def get_events(): assert request.headers["Accept"] == "text/event-stream" remote_addr = request.remote_addr event_types = request.args.getlist("event_type") # Ideally we'd use a zero-size buffer, but we need to send the attach # event before we return the response. send, recv = trio.open_memory_channel(1) await backend.attach_event_stream(send, event_types, remote_addr) async def forward_events(): try: async for event in recv: event_type = event["eventType"] msg = f"event: {event_type}\ndata: {json.dumps(event)}\n\n" yield msg.encode("utf-8") except trio.Cancelled: # FIXME: We don't seem to get cancelled on disconnection here, # see https://gitlab.com/pgjones/hypercorn/-/issues/124 for # details. raise finally: await backend.detach_event_stream(send, remote_addr) headers = {"Content-Type": "text/event-stream"} return await make_response(forward_events(), headers) return app
async def web_server(command_input): app = QuartTrio(__name__) @app.route("/") async def index(): return await render_template("index.html") @app.route("/api/<path:mode>") async def api(mode): await command_input.send(Command.factory(request)) return "", 200 config = hypercorn.Config.from_mapping(bind="0.0.0.0:5000", worker_class="trio", accesslog="-", errorlog="-") await hypercorn.trio.serve(app, config)
def _make_app_mlb(mlb): from quart import make_response app = QuartTrio(__name__) async def plain_resp(body): resp = await make_response(body) resp.content_type = "text/plain" return resp @app.route("/_mlb_signal/hup", methods=["POST"]) async def signal_hup(): mlb._signalled_hup = True return await plain_resp("Sent SIGHUP signal to marathon-lb") @app.route("/_mlb_signal/usr1", methods=["POST"]) async def signal_usr1(): mlb._signalled_usr1 = True return await plain_resp("Sent SIGUSR1 signal to marathon-lb") return app
def main(): if os.getuid() != 0: raise RuntimeError("need to be root, sorry about that") known_env_vars = ( "MESHPING_REDIS_HOST", "MESHPING_PING_TIMEOUT", "MESHPING_PING_INTERVAL", "MESHPING_PEERS", "MESHPING_PROMETHEUS_URL", "MESHPING_PROMETHEUS_QUERY", ) for key in os.environ.keys(): if key.startswith("MESHPING_") and key not in known_env_vars: print("env var %s is unknown" % key, file=sys.stderr) sys.exit(1) app = QuartTrio(__name__, static_url_path="") app.config["TEMPLATES_AUTO_RELOAD"] = True app.secret_key = str(uuid4()) app.debug = False redis = StrictRedis( host=os.environ.get("MESHPING_REDIS_HOST", "127.0.0.1")) mp = MeshPing(redis, int(os.environ.get("MESHPING_PING_TIMEOUT", 5)), int(os.environ.get("MESHPING_PING_INTERVAL", 30))) add_api_views(app, mp) @app.before_serving async def startup(): app.nursery.start_soon(mp.run) app.nursery.start_soon(run_peers, mp) app.run(host="::", port=9922)
async def serve(self, title, host, port, *, task_status=anyio.TASK_STATUS_IGNORED): """Web view server task.""" # (quart and hypercorn should have a common API for asyncio and trio...) async_lib = sniffio.current_async_library() if async_lib == 'trio': from quart_trio import QuartTrio # pylint: disable=import-outside-toplevel,import-error web_app = QuartTrio('pura') web_app.register_blueprint(self.get_blueprint(title)) async with anyio.create_task_group() as tg: urls = await tg.start( hypercorn.trio.serve, web_app, hypercorn.Config.from_mapping( bind=[f'{host}:{port}'], loglevel='WARNING', )) _logger.info(f'listening on {urls[0]}') task_status.started() elif async_lib == 'asyncio': web_app = quart.Quart('pura') web_app.register_blueprint(self.get_blueprint(title)) task_status.started() await hypercorn.asyncio.serve( web_app, hypercorn.Config.from_mapping( bind=[f'{host}:{port}'], loglevel='INFO', graceful_timeout=.2, )) raise CancelledError else: raise RuntimeError('unsupported async library:', async_lib)
import json import trio from quart import render_template, websocket from quart_trio import QuartTrio connections = set() app = QuartTrio(__name__) @app.route("/") async def index(): return await render_template("index.html") @app.websocket("/ws") async def chat(): try: connections.add(websocket._get_current_object()) async with trio.open_nursery() as nursery: nursery.start_soon(heartbeat) while True: message = await websocket.receive() await broadcast(message) finally: connections.remove(websocket._get_current_object()) async def broadcast(message): for connection in connections:
def create_app(stream_changes=True, allow_remote_class_registration=True, allow_import_from_main=False, max_queue_size=MAX_QUEUE_SIZE) -> QuartTrio: """Creates the quart app. """ # todo prevent server crashing from any user exceptions or from # connections closing etc. Same for multiprocessing global MAX_QUEUE_SIZE MAX_QUEUE_SIZE = max_queue_size app = QuartTrio(__name__) thread_executor = ThreadExecutor() stream_clients = defaultdict(dict) rest_executor = app.rest_executor = QuartRestServer( quart_app=app, executor=thread_executor, stream_clients=stream_clients) rest_executor.stream_changes = stream_changes rest_executor.allow_remote_class_registration = \ allow_remote_class_registration rest_executor.allow_import_from_main = allow_import_from_main # the objects are shared between the two executors socket_executor = app.socket_executor = QuartSocketServer( quart_app=app, registry=rest_executor.registry, executor=thread_executor, stream_clients=stream_clients) socket_executor.stream_changes = stream_changes socket_executor.allow_remote_class_registration = \ allow_remote_class_registration socket_executor.allow_import_from_main = allow_import_from_main app.add_url_rule('/api/v1/objects/import', view_func=rest_executor.remote_import, methods=['POST']) app.add_url_rule('/api/v1/objects/register_class', view_func=rest_executor.register_remote_class, methods=['POST']) app.add_url_rule('/api/v1/objects/create_open', view_func=rest_executor.ensure_instance, methods=['POST']) app.add_url_rule('/api/v1/objects/delete', view_func=rest_executor.delete_instance, methods=['POST']) app.add_url_rule('/api/v1/objects/execute', view_func=rest_executor.execute, methods=['POST']) app.add_url_rule('/api/v1/objects/execute_generator/stream', view_func=rest_executor.rest_execute_generator, methods=['POST']) app.add_url_rule('/api/v1/objects/list', view_func=rest_executor.get_objects, methods=['GET']) app.add_url_rule('/api/v1/objects/config', view_func=rest_executor.get_object_config, methods=['GET']) app.add_url_rule('/api/v1/objects/properties', view_func=rest_executor.get_object_data, methods=['GET']) app.add_url_rule('/api/v1/echo_clock', view_func=rest_executor.get_echo_clock, methods=['GET']) app.add_url_rule('/api/v1/sleep', view_func=rest_executor.sleep, methods=['GET']) app.add_url_rule('/api/v1/stream/data', view_func=rest_executor.sse_data, methods=['GET']) app.add_url_rule('/api/v1/stream/create', view_func=rest_executor.sse_channel_create, methods=['GET']) app.add_url_rule('/api/v1/stream/delete', view_func=rest_executor.sse_channel_delete, methods=['GET']) app.add_url_rule('/api/v1/stream/execute', view_func=rest_executor.sse_channel_execute, methods=['GET']) app.add_url_rule('/api/v1/stream/all', view_func=rest_executor.sse_channel_all, methods=['GET']) app.add_websocket('/api/v1/ws', view_func=socket_executor.ws) # app.register_error_handler(Exception, handle_unexpected_error) return app
from quart import render_template, websocket from quart_trio import QuartTrio import json from resources.web_connections import ConnectionManager from app.mock_objs import mock_stages class MovementException(Exception): def to_json(self): return json.dumps({"error": f'{self.args[0]}'}) app = QuartTrio(__name__) stages = mock_stages @app.route('/') async def index(): return await render_template('stage.html', stages=list(stages.values())) app.xps_connections = ConnectionManager() @app.websocket('/ws') @app.xps_connections.collect_websocket # decorator handles opening and closing async def ws(): # on page load function starts then heads into a loop try: while True: msg: str = await websocket.receive()
def serve(): app = QuartTrio(__name__) store = Store(str(ingest_dir)) gstore = GraphStore(ingest_dir) async def full(package, version, sub, ref): return await _route(ref, store, version, gstore=gstore) async def full_gallery(module, version): return await gallery(module, store, version, gstore=gstore) async def g(module): return await gallery(module, store, gstore=gstore) async def gr(): return await gallery("*", store, gstore=gstore) async def index(): import papyri v = str(papyri.__version__) return redirect(f"/p/papyri/{v}/api/papyri") async def ex(module, version, subpath): return await examples(module=module, store=store, version=version, subpath=subpath) # return await _route(ref, GHStore(Path('.'))) app.route("/logo.png")(logo) app.route("/favicon.ico")(static("favicon.ico")) # sub here is likely incorrect app.route("/p/<package>/<version>/img/<path:subpath>")(img) app.route("/p/<module>/<version>/examples/<path:subpath>")(ex) app.route("/p/<module>/<version>/gallery")(full_gallery) app.route("/p/<package>/<version>/<sub>/<ref>")(full) app.route("/gallery/")(gr) app.route("/gallery/<module>")(g) app.route("/")(index) port = os.environ.get("PORT", 5000) print("Seen config port ", port) prod = os.environ.get("PROD", None) if prod: app.run(port=port, host="0.0.0.0") else: app.run(port=port)
import quart.flask_patch from quart_trio import QuartTrio from config import Config from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager from flask_bootstrap import Bootstrap app = QuartTrio(__name__) app.config.from_object(Config) db = SQLAlchemy(app) bootstrap = Bootstrap(app) login = LoginManager(app) login.login_view = 'login' # hardware support from app import mock_objs xps1 = mock_objs.fake_xps all_insts = mock_objs.all_insts from app import scans scan = scans.Scan(all_insts) # routing from app import routes, models, websockets # todo: print vals to file # todo: connect to instruments # todo: display results
from quart import render_template, websocket from quart_trio import QuartTrio import trio from functools import wraps app = QuartTrio(__name__) app.connected = set() def collect_websocket(func): @wraps(func) async def wrapper(*args, **kwargs): print("wrapping: adding connection") app.connected.add(websocket._get_current_object()) try: return await func(*args, **kwargs) finally: print("wrapper: removing connection") app.connected.remove(websocket._get_current_object()) return wrapper async def broadcast(message: str): active = len(app.connected) for websock in app.connected: await websock.send(f"Broadcast: {message.upper()} : to {active}") @app.route('/') async def index():
from quart import request from quart_trio import QuartTrio app = QuartTrio(__name__) @app.route('/<int:number>') async def index(number=1): return "{}-fib({})={}".format(__file__, number, _fib(int(number))) @app.route('/', methods=['POST']) async def post(): data = await request.form number = data['fib'] return "{}-fib({})={}".format(__file__, number, _fib(int(number))) def _fib(n): if n == 0: return 0 elif n == 1: return 1 else: return _fib(n - 1) + _fib(n - 2) if __name__ == '__main__': app.run(host='127.0.0.1', port=5000)
OAUTH_DISCORD_CLIENT_SECRET, OAUTH_REDIRECT_PATH, OAUTH_REDIRECT_HOST, ) from .config_classes import GuildConfig from .i18n import _, ngettext, CurrentLocale from .models import User, GuildConfigJson, HighscoreCron from .utils import run_sync logger = logging.getLogger(__name__) serializer = URLSafeTimedSerializer(SIGNING_SECRET) TOKEN_MAX_AGE = 1800 if not DEVELOPMENT else 3600000 app = QuartTrio(__name__) # HACK: these three are set by Orisa in orisa.py. send_ch = None client = None orisa = None app.debug = DEVELOPMENT async def render_message(message, is_error=False): return await render_template( "message.html", message=message, close_msg=_("You can close this window."), classes="bg-danger text-white"
""" Demo codes for https://stackoverflow.com/questions/71417266 """ import trio from quart import request, jsonify from quart_trio import QuartTrio app = QuartTrio("Very named Much app") @app.get("/json") async def send_json(): """ Sleeps 5 + n seconds before returning response. Returns: json response """ key = int(request.args["key"]) await trio.sleep(5 + key) return jsonify({"key": key}) trio.run(app.run_task)
# this defines the root folder containing our DASH dataset dash_content_path = '/var/www/html/' # define the config setup for our testbed config = Config() config.quic_bind = ["10.0.0.1:4444"] # port number to use for HTTP config.bind = ["10.0.0.1:443"] # port number to use for HTTPS config.insecure_bind = ["10.0.0.1:80"] # port number to use for QUIC # locations for the cert and key config.certfile = "../goDASH/godash/http/certs/cert.pem" config.keyfile = "../goDASH/godash/http/certs/key.pem" # this 'root_path' is needed by QuartTrio to point to the DASH video content folder app = QuartTrio(__name__, root_path=dash_content_path) # return 404, if file not found @app.errorhandler(404) # @app.route('/') async def page_not_found(error): return ' File not found', 404 # this return index.html if nothing is added to the url and port @app.route('/') async def root(): print("returning index.html", ) return await send_from_directory(dash_content_path, 'index.html'), 200
from trio import sleep from textflip import flip from .slack import slack from .grafana import views as grafana_views from .storage import Store, Log from .utils import timestamp, elo as _elo from .krank import views as krank_views from .auth import simple_token, github_hmac from .chords import views as chord_views logging.basicConfig(filename="api.log", level=logging.INFO, format="%(asctime)s\t%(message)s") app = QuartTrio(__name__) def debug_route(*args, **kwargs): def decorator(fn): if os.environ.get("DEBUG_STUFF") == "yep": return app.route(*args, **kwargs)(fn) return decorator @app.route("/") async def hello(): return "Hello"
import trio from power_simulator.redis_util import redis__queue_push, redis__wait_for_key REDIS_HOSTNAME = os.environ.get('REDIS_HOSTNAME', 'localhost') REDIS_PORT = int(os.environ.get('REDIS_PORT', 6379)) WORKER_QUEUE = 'gs_worker_queue' WS_NOTIFY_KEY = 'gs_ws_notify_key' SIMULATION_RESULT_KEY = 'simulation-result' redis_cli = redis.StrictRedis(host=REDIS_HOSTNAME, port=REDIS_PORT) hypercorn_config = HyperConfig.from_mapping(worker_class='trio', bind='0.0.0.0:5000') app = QuartTrio(__name__) app.SUBSCRIBER_CHANNELS = set( ) # local queues for each subscribing websocket client async def _do_background_task(redis_cli, task_uid, task_type, task_kwargs): # push task to worker queue wait_key = 'wait-' + task_uid + uuid.uuid4().hex[:6] msg = json.dumps({ 'task_type': task_type, 'task_kwargs': task_kwargs, 'redis_resultkey': task_uid, 'redis_waitkey': wait_key }) await trio.to_thread.run_sync(redis__queue_push, redis_cli, WORKER_QUEUE,
async def run(self): # Serve static files from ./static static_folder = os.path.join(os.path.dirname(__file__), 'static') app = QuartTrio(__name__, static_folder=static_folder) app.add_url_rule('/', 'static', app.send_static_file, defaults={'filename': 'index.html'}) app.add_url_rule('/<path:filename>', 'static', app.send_static_file) app.add_url_rule('/tasks.json', 'task_tree', self.dispatch_task_tree, ['GET']) app.add_url_rule('/task/<int:task_id>/stacktrace.json', 'task_stacktrace', self.dispatch_task_stacktrace, ['GET']) app.add_url_rule('/nursery/<int:nursery_id>/cancel', 'nursery_cancel', self.dispatch_nursery_cancel, ['GET']) app.add_url_rule('/stats.json', 'stats', self.dispatch_stats, ['GET']) config = HyperConfig() #config.access_log_format = '%(h)s %(r)s %(s)s %(b)s %(D)s' #config.access_logger = create_serving_logger() # type: ignore config.bind = [f'{self._host}:{self._port}'] config.error_logger = config.access_logger # type: ignore #trio.hazmat.add_instrument(self) await serve(cors(app), config)
class App: """ This is deframed's main code. You probably don't need to subclass this. """ def __init__(self, cfg: dict, worker: Worker, debug:bool=False): cfg = combine_dict(cfg, CFG, cls=attrdict) self.cfg = cfg self.main = None # Nursery self.clients = WeakValueDictionary() self.worker = worker self.sub_worker = WeakValueDictionary() self._sw_id = 0 self.version = worker.version or deframed.__version__ self.debug=debug or cfg.debug self.app = Quart(cfg.server.name, # no, we do not want any of those default folders and whatnot static_folder=None,template_folder=None,root_path="/nonexistent", ) #@self.app.route("/<path:p>", methods=['GET']) @self.app.route("/", defaults={"p":None}, methods=['GET']) async def index(p): # "path" is unused, the app will get it via Javascript mainpage = os.path.join(os.path.dirname(deframed.__file__), cfg.mainpage) with open(mainpage, 'r') as f: data = cfg.data.copy() data['debug'] = self.debug data['version'] = self.version if data['title'] == CFG.data.title: data['title'] = self.worker.title return Response(chevron.render(f, data), headers={"Access-Control-Allow-Origin": "*"}) @self.app.websocket('/ws') async def ws(): """Main websocket""" w = self.worker(self) await w.run(websocket._get_current_object()) @self.app.route("/sub/<int:sid>", methods=['GET']) async def index_sub(sid): """SubWorker main page""" w = self.sub_worker[sid] return await w.index() @self.app.websocket('/ws/<int:sid>') async def ws_sub(sid): """SubWorker websocket""" try: w = self.sub_worker[sid] except KeyError: raise NotFound else: await w.run(websocket._get_current_object()) static = os.path.join(os.path.dirname(deframed.__file__), cfg.data.static) @self.app.route("/static/<path:filename>", methods=['GET']) async def send_static(filename): print("GET",filename) return await send_from_directory(static, filename) def route(self,*a,**k): return self.app.route(*a,**k) async def run (self) -> None: """ Run this application. This is a simple Hypercorn runner. You should probably use something more elaborate in a production setting. """ config = HyperConfig() cfg = self.cfg.server config.access_log_format = "%(h)s %(r)s %(s)s %(b)s %(D)s" config.access_logger = create_serving_logger() # type: ignore config.bind = [f"{cfg.host}:{cfg.port}"] config.ca_certs = cfg.ca_certs config.certfile = cfg.certfile # if debug is not None: # config.debug = debug config.error_logger = config.access_logger # type: ignore config.keyfile = cfg.keyfile config.use_reloader = cfg.use_reloader scheme = "http" if config.ssl_enabled is None else "https" async with trio.open_nursery() as n: self.main = n await hyper_serve(self.app, config) def attach_sub(self, subworker): """ Attach a sub-worker, typically displayed in an iframe. There is no "detach", as the worker is weakly referenced. There is no "get", as the ID only shows up in the path. """ self._sw_id += 1 sw_id = self._sw_id self.sub_worker[sw_id] = subworker return sw_id
import os import asks from asks import Session from quart import request, Response from quart_trio import QuartTrio ENABLE_DEBUG = bool(os.environ.get('ROCKETCHAT_WEBHOOK_PROXY_DEBUG', False)) TARGET_URL = os.environ.get("ROCKETCHAT_WEBHOOK_PROXY_TARGET") if not TARGET_URL: raise RuntimeError( "Required env variable ROCKETCHAT_WEBHOOK_PROXY_TARGET is missing.") asks.init("trio") session = Session(connections=8) app = QuartTrio(__name__) @app.route("/<token_a>/<token_b>", methods=["POST"]) async def webhook(token_a, token_b): request_data = await request.get_json(force=True) if ENABLE_DEBUG: print(f"Request data:\n{json.dumps(request_data, indent=2)}") target_url = f"{TARGET_URL}/{token_a}/{token_b}" response = await session.post(target_url, json=request_data) return Response(response.text, content_type=response.headers["content-type"]) if __name__ == "__main__": app.run("localhost", port=5000, debug=True)
def main(): if os.getuid() != 0: raise RuntimeError("need to be root, sorry about that") known_env_vars = ( "MESHPING_DATABASE_PATH", "MESHPING_REDIS_HOST", "MESHPING_PING_TIMEOUT", "MESHPING_PING_INTERVAL", "MESHPING_HISTOGRAM_DAYS", "MESHPING_PEERS", "MESHPING_PEERING_INTERVAL", "MESHPING_PROMETHEUS_URL", "MESHPING_PROMETHEUS_QUERY", ) deprecated_env_vars = ( "MESHPING_PROMETHEUS_URL", "MESHPING_PROMETHEUS_QUERY", ) for key in os.environ: if key.startswith("MESHPING_") and key not in known_env_vars: print("env var %s is unknown" % key, file=sys.stderr) sys.exit(1) if key.startswith("MESHPING_") and key in deprecated_env_vars: print("env var %s is deprecated, ignored" % key, file=sys.stderr) app = QuartTrio(__name__, static_url_path="") #app.config["TEMPLATES_AUTO_RELOAD"] = True app.secret_key = str(uuid4()) app.jinja_options = dict(variable_start_string='{[', variable_end_string=']}') @app.context_processor def _inject_icons(): # I'm not happy about hardcoding this path here, but I'm also not sure what else to do icons_dir = "/opt/meshping/ui/node_modules/bootstrap-icons/icons/" return dict( icons={ filename: Markup( open(os.path.join(icons_dir, filename), "r").read()) for filename in os.listdir(icons_dir) }) # Transition period: Read all targets from redis and add them to our DB try: redis = StrictRedis( host=os.environ.get("MESHPING_REDIS_HOST", "127.0.0.1")) for target in redis.smembers("meshping:targets"): target = target.decode("utf-8") name, addr = target.split("@", 1) Target.db.add(addr, name) for target in redis.smembers("meshping:foreign_targets"): target = target.decode("utf-8") name, addr = target.split("@", 1) Target.db.get(addr).set_is_foreign(True) except: # Probably no redis here, ignore pass mp = MeshPing(int(os.environ.get("MESHPING_PING_TIMEOUT", 5)), int(os.environ.get("MESHPING_PING_INTERVAL", 30)), int(os.environ.get("MESHPING_HISTOGRAM_DAYS", 3))) add_api_views(app, mp) @app.before_serving async def _(): app.nursery.start_soon(mp.run) app.nursery.start_soon(run_peers, mp) app.run(host="::", port=9922, debug=False, use_reloader=False)