47 lines
1.4 KiB
Python
47 lines
1.4 KiB
Python
import importlib.util
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from flask import Flask, render_template_string
|
|
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
|
from werkzeug.serving import run_simple
|
|
|
|
root = Flask(__name__)
|
|
|
|
|
|
@root.route("/")
|
|
def index():
|
|
apps = [
|
|
d.name for d in Path(__file__).parent.iterdir()
|
|
if d.is_dir() and (d / "app.py").exists()
|
|
]
|
|
links = "".join(f'<li><a href="/{a}">{a}</a></li>' for a in sorted(apps))
|
|
return render_template_string(f"""
|
|
<!DOCTYPE html><html><head><title>Tools</title></head>
|
|
<body>
|
|
<h1>Tools</h1>
|
|
<ul>{links}</ul>
|
|
</body></html>
|
|
""")
|
|
|
|
|
|
def load_sub_apps():
|
|
mounts = {}
|
|
base = Path(__file__).parent
|
|
for app_dir in sorted(base.iterdir()):
|
|
app_file = app_dir / "app.py"
|
|
if not app_dir.is_dir() or not app_file.exists():
|
|
continue
|
|
spec = importlib.util.spec_from_file_location(app_dir.name, app_file)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
sys.modules[app_dir.name] = mod # must be registered before exec so Flask(__name__) resolves root_path correctly
|
|
spec.loader.exec_module(mod)
|
|
mounts[f"/{app_dir.name}"] = mod.app
|
|
print(f" mounted /{app_dir.name}")
|
|
return mounts
|
|
|
|
|
|
application = DispatcherMiddleware(root, load_sub_apps())
|
|
|
|
if __name__ == "__main__":
|
|
run_simple("0.0.0.0", 8080, application, use_reloader=False)
|