Spaces:
Sleeping
Sleeping
| import base64 | |
| import os | |
| import secrets | |
| import sys | |
| import logging | |
| import traceback | |
| from dataclasses import dataclass, field | |
| from datetime import datetime, timedelta | |
| from typing import Any, Callable | |
| from absl import flags | |
| from flask import Flask | |
| from flask import request | |
| from mesop.cli.execute_module import execute_module | |
| from mesop.runtime import enable_debug_mode | |
| from mesop.runtime import reset_runtime | |
| from mesop.runtime import hot_reload_finished | |
| from mesop.server.constants import PROD_PACKAGE_PATH | |
| from mesop.server.flags import port | |
| from mesop.server.logging import log_startup | |
| from mesop.server.server import configure_flask_app | |
| from mesop.server.static_file_serving import configure_static_file_serving | |
| PAGE_EXPIRATION_MINUTES = 10 | |
| MAIN_MODULE = "main" | |
| RUNNER_TOKEN = os.getenv("MESOP_APP_RUNNER_TOKEN") | |
| if not RUNNER_TOKEN: | |
| logging.fatal("`MESOP_APP_RUNNER_TOKEN` environment variable neeeds to be specified.") | |
| sys.exit() | |
| class RegisteredModule: | |
| name: str = "" | |
| created_at: datetime = field(default_factory=lambda: datetime.now()) | |
| registered_modules = set([RegisteredModule(MAIN_MODULE)]) | |
| class App: | |
| _flask_app: Flask | |
| def __init__(self, flask_app: Flask): | |
| self._flask_app = flask_app | |
| def run(self): | |
| log_startup(port=port()) | |
| self._flask_app.run(host="::", port=port(), use_reloader=False) | |
| def create_app(prod_mode: bool, run_block: Callable[..., None] | None = None) -> App: | |
| flask_app = configure_flask_app(prod_mode=prod_mode) | |
| # Enable debug mode so we can see errors with the code we're running. | |
| enable_debug_mode() | |
| if run_block is not None: | |
| run_block() | |
| configure_static_file_serving(flask_app, static_file_runfiles_base=PROD_PACKAGE_PATH) | |
| def exec_route(): | |
| global registered_modules | |
| if request.form.get("token", "") != RUNNER_TOKEN: | |
| return "Tokens do not match.", 400 | |
| param = request.form.get("code") | |
| new_module = RegisteredModule() | |
| if param is None: | |
| raise Exception("Missing request parameter") | |
| try: | |
| new_module = RegisteredModule(f"page_{secrets.token_urlsafe(8)}") | |
| # Create a new page with the code to run | |
| # We expect `@me.page()` here for this to work. | |
| code = base64.urlsafe_b64decode(param) | |
| code = code.decode("utf-8").replace( | |
| "@me.page()", | |
| f'@me.page(path="/{new_module.name}", security_policy=me.SecurityPolicy(allowed_iframe_parents=["localhost:*", "https://richard-to-mesop-app-maker.hf.space", "https://huggingface.co"]))', | |
| ) | |
| # Write to tmp since Hugging Face does not allow writing to the repo directory. | |
| with open(f"/tmp/{new_module.name}.py", "w") as file: | |
| file.write(code) | |
| # Add new registered path | |
| registered_modules.add(new_module) | |
| # Clean up old registered paths (except main) | |
| registered_modules_to_delete = set() | |
| for registered_module in registered_modules: | |
| if ( | |
| registered_module.name != MAIN_MODULE | |
| and registered_module.created_at | |
| < datetime.now() - timedelta(minutes=PAGE_EXPIRATION_MINUTES) | |
| ): | |
| registered_modules_to_delete.add(registered_module) | |
| registered_modules -= registered_modules_to_delete | |
| # Manually hot reload | |
| reset_runtime() | |
| for module in registered_modules: | |
| if module.name != "main": | |
| execute_module(module_path=f"/tmp/{module.name}.py", module_name=module.name) | |
| else: | |
| execute_module( | |
| module_path=make_path_absolute(f"{module.name}.py"), | |
| module_name=module.name, | |
| ) | |
| hot_reload_finished() | |
| except Exception: | |
| # If there was an error, it's likely that the code failed during hot reload, so | |
| # we need to trigger another hot reload without the bad code. | |
| # For simplicity, we just remove all the generated files | |
| reset_runtime() | |
| execute_module( | |
| module_path=make_path_absolute("main.py"), | |
| module_name="main", | |
| ) | |
| registered_modules = set([RegisteredModule(MAIN_MODULE)]) | |
| hot_reload_finished() | |
| # Get the current exception information | |
| exc_type, exc_value, exc_traceback = sys.exc_info() | |
| # Format the traceback as a string | |
| tb_string = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback)) | |
| return tb_string, 500 | |
| # Return the page path that's running the new code, so we can update the iframe with | |
| # the right path. | |
| return f"/{new_module.name}" | |
| return App(flask_app=flask_app) | |
| _app = None | |
| def wsgi_app(environ: dict[Any, Any], start_response: Callable[..., Any]): | |
| global _app | |
| if not _app: | |
| flags.FLAGS(sys.argv[:1]) | |
| _app = create_app(prod_mode=True) | |
| return _app._flask_app.wsgi_app(environ, start_response) | |
| def make_path_absolute(file_path: str): | |
| if os.path.isabs(file_path): | |
| return file_path | |
| absolute_path = os.path.join(os.getcwd(), file_path) | |
| return absolute_path | |