more decoupling
This commit is contained in:
@@ -36,11 +36,8 @@ DB_DUMP=test.sql
|
|||||||
BACKEND_PORT=8000
|
BACKEND_PORT=8000
|
||||||
FRONTEND_PORT=3000
|
FRONTEND_PORT=3000
|
||||||
|
|
||||||
# Soleprint ports
|
# Soleprint port
|
||||||
SOLEPRINT_PORT=12000
|
SOLEPRINT_PORT=12000
|
||||||
ARTERY_PORT=12001
|
|
||||||
ATLAS_PORT=12002
|
|
||||||
STATION_PORT=12003
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# BACKEND SERVER (Uvicorn)
|
# BACKEND SERVER (Uvicorn)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
"slug": "artery",
|
"slug": "artery",
|
||||||
"title": "Artery",
|
"title": "Artery",
|
||||||
"tagline": "Todo lo vital",
|
"tagline": "Todo lo vital",
|
||||||
"port": 12001,
|
|
||||||
"icon": "💉"
|
"icon": "💉"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -31,7 +30,6 @@
|
|||||||
"slug": "atlas",
|
"slug": "atlas",
|
||||||
"title": "Atlas",
|
"title": "Atlas",
|
||||||
"tagline": "Documentación accionable",
|
"tagline": "Documentación accionable",
|
||||||
"port": 12002,
|
|
||||||
"icon": "🗺️"
|
"icon": "🗺️"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -40,7 +38,6 @@
|
|||||||
"slug": "station",
|
"slug": "station",
|
||||||
"title": "Station",
|
"title": "Station",
|
||||||
"tagline": "Monitores, Entornos y Herramientas",
|
"tagline": "Monitores, Entornos y Herramientas",
|
||||||
"port": 12003,
|
|
||||||
"icon": "🎛️"
|
"icon": "🎛️"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ SOLEPRINT_BARE_PATH=/home/mariano/wdir/spr/gen
|
|||||||
# PORTS
|
# PORTS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
SOLEPRINT_PORT=12000
|
SOLEPRINT_PORT=12000
|
||||||
ARTERY_PORT=12001
|
|
||||||
ATLAS_PORT=12002
|
|
||||||
STATION_PORT=12003
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# DATABASE (amar's DB for station tools)
|
# DATABASE (amar's DB for station tools)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
"slug": "artery",
|
"slug": "artery",
|
||||||
"title": "Artery",
|
"title": "Artery",
|
||||||
"tagline": "Todo lo vital",
|
"tagline": "Todo lo vital",
|
||||||
"port": 12001,
|
|
||||||
"icon": "💉"
|
"icon": "💉"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -24,7 +23,6 @@
|
|||||||
"slug": "atlas",
|
"slug": "atlas",
|
||||||
"title": "Atlas",
|
"title": "Atlas",
|
||||||
"tagline": "Documentación accionable",
|
"tagline": "Documentación accionable",
|
||||||
"port": 12002,
|
|
||||||
"icon": "🗺️"
|
"icon": "🗺️"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -33,7 +31,6 @@
|
|||||||
"slug": "station",
|
"slug": "station",
|
||||||
"title": "Station",
|
"title": "Station",
|
||||||
"tagline": "Monitores, Entornos y Herramientas",
|
"tagline": "Monitores, Entornos y Herramientas",
|
||||||
"port": 12003,
|
|
||||||
"icon": "🎛️"
|
"icon": "🎛️"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,79 +1,14 @@
|
|||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
{
|
|
||||||
"name": "arch-model",
|
|
||||||
"slug": "arch-model",
|
|
||||||
"title": "Architecture Model",
|
|
||||||
"status": "ready",
|
|
||||||
"template": null,
|
|
||||||
"larder": {
|
|
||||||
"name": "arch-model",
|
|
||||||
"slug": "arch-model",
|
|
||||||
"title": "Architecture Model",
|
|
||||||
"status": "ready",
|
|
||||||
"source_template": null,
|
|
||||||
"data_path": "album/book/arch-model"
|
|
||||||
},
|
|
||||||
"output_larder": null,
|
|
||||||
"system": "album"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "feature-flow",
|
"name": "feature-flow",
|
||||||
"slug": "feature-flow",
|
"slug": "feature-flow",
|
||||||
"title": "Feature Flow Pipeline",
|
"title": "Feature Flow Pipeline",
|
||||||
"status": "ready",
|
"status": "ready",
|
||||||
"template": null,
|
"template": null,
|
||||||
"larder": {
|
"larder": null,
|
||||||
"name": "feature-flow",
|
|
||||||
"slug": "feature-flow",
|
|
||||||
"title": "Feature Flow Pipeline",
|
|
||||||
"status": "ready",
|
|
||||||
"source_template": null,
|
|
||||||
"data_path": "album/book/feature-flow"
|
|
||||||
},
|
|
||||||
"output_larder": null,
|
"output_larder": null,
|
||||||
"system": "album"
|
"system": "atlas"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "gherkin-samples",
|
|
||||||
"slug": "gherkin-samples",
|
|
||||||
"title": "Gherkin Samples",
|
|
||||||
"status": "ready",
|
|
||||||
"template": null,
|
|
||||||
"larder": {
|
|
||||||
"name": "gherkin-samples",
|
|
||||||
"slug": "gherkin-samples",
|
|
||||||
"title": "Gherkin Samples",
|
|
||||||
"status": "ready",
|
|
||||||
"source_template": null,
|
|
||||||
"data_path": "album/book/gherkin-samples"
|
|
||||||
},
|
|
||||||
"output_larder": null,
|
|
||||||
"system": "album"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "feature-form-samples",
|
|
||||||
"slug": "feature-form-samples",
|
|
||||||
"title": "Feature Form Samples",
|
|
||||||
"status": "ready",
|
|
||||||
"template": {
|
|
||||||
"name": "feature-form",
|
|
||||||
"slug": "feature-form",
|
|
||||||
"title": "Feature Form Template",
|
|
||||||
"status": "ready",
|
|
||||||
"template_path": "album/template/feature-form",
|
|
||||||
"system": "album"
|
|
||||||
},
|
|
||||||
"larder": {
|
|
||||||
"name": "feature-form",
|
|
||||||
"slug": "feature-form",
|
|
||||||
"title": "Feature Forms",
|
|
||||||
"status": "ready",
|
|
||||||
"source_template": "feature-form",
|
|
||||||
"data_path": "album/book/feature-form-samples/feature-form"
|
|
||||||
},
|
|
||||||
"output_larder": null,
|
|
||||||
"system": "album"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
<ul class="books">
|
<ul class="books">
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<li>
|
<li>
|
||||||
<a href="/book/{{ book.slug }}/">{{ book.title }}</a>
|
<a href="/atlas/book/{{ book.slug }}/">{{ book.title }}</a>
|
||||||
<span
|
<span
|
||||||
class="status {% if book.status == 'ready' %}ready{% elif book.status == 'building' %}building{% endif %}"
|
class="status {% if book.status == 'ready' %}ready{% elif book.status == 'building' %}building{% endif %}"
|
||||||
>{{ book.status | capitalize }}</span
|
>{{ book.status | capitalize }}</span
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ Album - Documentation system.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import httpx
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import httpx
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
@@ -47,11 +48,14 @@ def health():
|
|||||||
@app.get("/")
|
@app.get("/")
|
||||||
def index(request: Request):
|
def index(request: Request):
|
||||||
data = get_data()
|
data = get_data()
|
||||||
return templates.TemplateResponse("index.html", {
|
return templates.TemplateResponse(
|
||||||
"request": request,
|
"index.html",
|
||||||
"pawprint_url": os.getenv("PAWPRINT_EXTERNAL_URL", PAWPRINT_URL),
|
{
|
||||||
**data,
|
"request": request,
|
||||||
})
|
"pawprint_url": os.getenv("PAWPRINT_EXTERNAL_URL", PAWPRINT_URL),
|
||||||
|
**data,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/data")
|
@app.get("/api/data")
|
||||||
@@ -103,13 +107,18 @@ def feature_flow_es():
|
|||||||
def feature_form_samples_index(request: Request):
|
def feature_form_samples_index(request: Request):
|
||||||
"""Templated book landing page"""
|
"""Templated book landing page"""
|
||||||
data = get_data()
|
data = get_data()
|
||||||
book = next((b for b in data.get("books", []) if b["slug"] == "feature-form-samples"), None)
|
book = next(
|
||||||
|
(b for b in data.get("books", []) if b["slug"] == "feature-form-samples"), None
|
||||||
|
)
|
||||||
if not book:
|
if not book:
|
||||||
return HTMLResponse("<h1>Book not found</h1>", status_code=404)
|
return HTMLResponse("<h1>Book not found</h1>", status_code=404)
|
||||||
return templates.TemplateResponse("book-template.html", {
|
return templates.TemplateResponse(
|
||||||
"request": request,
|
"book-template.html",
|
||||||
"book": book,
|
{
|
||||||
})
|
"request": request,
|
||||||
|
"book": book,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/book/feature-form-samples/template/", response_class=HTMLResponse)
|
@app.get("/book/feature-form-samples/template/", response_class=HTMLResponse)
|
||||||
@@ -297,7 +306,10 @@ def feature_form_samples_larder():
|
|||||||
return HTMLResponse("<h1>Larder index not found</h1>", status_code=404)
|
return HTMLResponse("<h1>Larder index not found</h1>", status_code=404)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/book/feature-form-samples/larder/{user_type}/{filename}", response_class=HTMLResponse)
|
@app.get(
|
||||||
|
"/book/feature-form-samples/larder/{user_type}/{filename}",
|
||||||
|
response_class=HTMLResponse,
|
||||||
|
)
|
||||||
def feature_form_samples_detail(request: Request, user_type: str, filename: str):
|
def feature_form_samples_detail(request: Request, user_type: str, filename: str):
|
||||||
"""View a specific feature form"""
|
"""View a specific feature form"""
|
||||||
# Look in the larder subfolder (feature-form)
|
# Look in the larder subfolder (feature-form)
|
||||||
@@ -308,27 +320,34 @@ def feature_form_samples_detail(request: Request, user_type: str, filename: str)
|
|||||||
|
|
||||||
content = file_path.read_text()
|
content = file_path.read_text()
|
||||||
detail_file = BOOK_DIR / "feature-form-samples" / "detail.html"
|
detail_file = BOOK_DIR / "feature-form-samples" / "detail.html"
|
||||||
return templates.TemplateResponse(str(detail_file.relative_to(BASE_DIR)), {
|
return templates.TemplateResponse(
|
||||||
"request": request,
|
str(detail_file.relative_to(BASE_DIR)),
|
||||||
"user_type": user_type,
|
{
|
||||||
"filename": filename,
|
"request": request,
|
||||||
"content": content,
|
"user_type": user_type,
|
||||||
})
|
"filename": filename,
|
||||||
|
"content": content,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Book: Gherkin Samples ---
|
# --- Book: Gherkin Samples ---
|
||||||
@app.get("/book/gherkin-samples/", response_class=HTMLResponse)
|
@app.get("/book/gherkin-samples/", response_class=HTMLResponse)
|
||||||
@app.get("/book/gherkin-samples", response_class=HTMLResponse)
|
@app.get("/book/gherkin-samples", response_class=HTMLResponse)
|
||||||
@app.get("/book/gherkin/", response_class=HTMLResponse) # Alias
|
@app.get("/book/gherkin/", response_class=HTMLResponse) # Alias
|
||||||
@app.get("/book/gherkin", response_class=HTMLResponse) # Alias
|
@app.get("/book/gherkin", response_class=HTMLResponse) # Alias
|
||||||
def gherkin_samples_index():
|
def gherkin_samples_index():
|
||||||
"""Browse gherkin samples"""
|
"""Browse gherkin samples"""
|
||||||
html_file = BOOK_DIR / "gherkin-samples" / "index.html"
|
html_file = BOOK_DIR / "gherkin-samples" / "index.html"
|
||||||
return HTMLResponse(html_file.read_text())
|
return HTMLResponse(html_file.read_text())
|
||||||
|
|
||||||
|
|
||||||
@app.get("/book/gherkin-samples/{lang}/{user_type}/{filename}", response_class=HTMLResponse)
|
@app.get(
|
||||||
@app.get("/book/gherkin/{lang}/{user_type}/{filename}", response_class=HTMLResponse) # Alias
|
"/book/gherkin-samples/{lang}/{user_type}/{filename}", response_class=HTMLResponse
|
||||||
|
)
|
||||||
|
@app.get(
|
||||||
|
"/book/gherkin/{lang}/{user_type}/{filename}", response_class=HTMLResponse
|
||||||
|
) # Alias
|
||||||
def gherkin_samples_detail(request: Request, lang: str, user_type: str, filename: str):
|
def gherkin_samples_detail(request: Request, lang: str, user_type: str, filename: str):
|
||||||
"""View a specific gherkin file"""
|
"""View a specific gherkin file"""
|
||||||
file_path = BOOK_DIR / "gherkin-samples" / lang / user_type / filename
|
file_path = BOOK_DIR / "gherkin-samples" / lang / user_type / filename
|
||||||
@@ -337,17 +356,24 @@ def gherkin_samples_detail(request: Request, lang: str, user_type: str, filename
|
|||||||
|
|
||||||
content = file_path.read_text()
|
content = file_path.read_text()
|
||||||
detail_file = BOOK_DIR / "gherkin-samples" / "detail.html"
|
detail_file = BOOK_DIR / "gherkin-samples" / "detail.html"
|
||||||
return templates.TemplateResponse(str(detail_file.relative_to(BASE_DIR)), {
|
return templates.TemplateResponse(
|
||||||
"request": request,
|
str(detail_file.relative_to(BASE_DIR)),
|
||||||
"lang": lang,
|
{
|
||||||
"user_type": user_type,
|
"request": request,
|
||||||
"filename": filename,
|
"lang": lang,
|
||||||
"content": content,
|
"user_type": user_type,
|
||||||
})
|
"filename": filename,
|
||||||
|
"content": content,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Book: Architecture Model (static site) ---
|
# --- Book: Architecture Model (static site) ---
|
||||||
app.mount("/book/arch-model", StaticFiles(directory=str(BOOK_DIR / "arch-model"), html=True), name="arch-model")
|
app.mount(
|
||||||
|
"/book/arch-model",
|
||||||
|
StaticFiles(directory=str(BOOK_DIR / "arch-model"), html=True),
|
||||||
|
name="arch-model",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Book: Drive Index ---
|
# --- Book: Drive Index ---
|
||||||
@@ -361,9 +387,10 @@ def drive_index():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"main:app",
|
"main:app",
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
port=int(os.getenv("PORT", "12002")),
|
port=int(os.getenv("PORT", "12000")),
|
||||||
reload=os.getenv("DEV", "").lower() in ("1", "true"),
|
reload=os.getenv("DEV", "").lower() in ("1", "true"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -68,22 +68,8 @@ CONFIG = {}
|
|||||||
if CONFIG_PATH.exists():
|
if CONFIG_PATH.exists():
|
||||||
CONFIG = json.loads(CONFIG_PATH.read_text())
|
CONFIG = json.loads(CONFIG_PATH.read_text())
|
||||||
|
|
||||||
# Get ports from config or use defaults
|
# Get hub port from config
|
||||||
HUB_PORT = CONFIG.get("framework", {}).get("hub_port", 12000)
|
HUB_PORT = CONFIG.get("framework", {}).get("hub_port", 12000)
|
||||||
SYSTEM_PORTS = {s["key"]: s["port"] for s in CONFIG.get("systems", [])}
|
|
||||||
ARTERY_PORT = SYSTEM_PORTS.get("data_flow", 12001)
|
|
||||||
ATLAS_PORT = SYSTEM_PORTS.get("documentation", 12002)
|
|
||||||
STATION_PORT = SYSTEM_PORTS.get("execution", 12003)
|
|
||||||
|
|
||||||
# Service URLs (internal for API calls)
|
|
||||||
ARTERY_URL = os.getenv("ARTERY_URL", f"http://localhost:{ARTERY_PORT}")
|
|
||||||
ATLAS_URL = os.getenv("ATLAS_URL", f"http://localhost:{ATLAS_PORT}")
|
|
||||||
STATION_URL = os.getenv("STATION_URL", f"http://localhost:{STATION_PORT}")
|
|
||||||
|
|
||||||
# External URLs (for frontend links, falls back to internal)
|
|
||||||
ARTERY_EXTERNAL_URL = os.getenv("ARTERY_EXTERNAL_URL", ARTERY_URL)
|
|
||||||
ATLAS_EXTERNAL_URL = os.getenv("ATLAS_EXTERNAL_URL", ATLAS_URL)
|
|
||||||
STATION_EXTERNAL_URL = os.getenv("STATION_EXTERNAL_URL", STATION_URL)
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
@@ -149,7 +135,6 @@ def generate_config(req: GenerationRequest):
|
|||||||
"slug": req.systems.artery.lower(),
|
"slug": req.systems.artery.lower(),
|
||||||
"title": req.systems.artery.title(),
|
"title": req.systems.artery.title(),
|
||||||
"tagline": "Todo lo vital",
|
"tagline": "Todo lo vital",
|
||||||
"port": ARTERY_PORT,
|
|
||||||
"icon": "",
|
"icon": "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -158,7 +143,6 @@ def generate_config(req: GenerationRequest):
|
|||||||
"slug": req.systems.atlas.lower(),
|
"slug": req.systems.atlas.lower(),
|
||||||
"title": req.systems.atlas.title(),
|
"title": req.systems.atlas.title(),
|
||||||
"tagline": "Documentacion accionable",
|
"tagline": "Documentacion accionable",
|
||||||
"port": ATLAS_PORT,
|
|
||||||
"icon": "",
|
"icon": "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -167,7 +151,6 @@ def generate_config(req: GenerationRequest):
|
|||||||
"slug": req.systems.station.lower(),
|
"slug": req.systems.station.lower(),
|
||||||
"title": req.systems.station.title(),
|
"title": req.systems.station.title(),
|
||||||
"tagline": "Monitores, Entornos y Herramientas",
|
"tagline": "Monitores, Entornos y Herramientas",
|
||||||
"port": STATION_PORT,
|
|
||||||
"icon": "",
|
"icon": "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Add parent directory to path for imports
|
# Add current directory to path for imports (artery, atlas, station)
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse
|
from fastapi.responses import HTMLResponse, JSONResponse
|
||||||
@@ -163,7 +163,7 @@ def artery_index(request: Request):
|
|||||||
@app.get("/artery/{path:path}")
|
@app.get("/artery/{path:path}")
|
||||||
def artery_route(path: str):
|
def artery_route(path: str):
|
||||||
"""Artery sub-routes."""
|
"""Artery sub-routes."""
|
||||||
return {"system": "artery", "path": path, "message": "Artery route placeholder"}
|
return {"system": "artery", "path": path}
|
||||||
|
|
||||||
|
|
||||||
# === Atlas ===
|
# === Atlas ===
|
||||||
@@ -208,10 +208,32 @@ def atlas_index(request: Request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/atlas/book/{book_name:path}")
|
||||||
|
def atlas_book(book_name: str):
|
||||||
|
"""Serve atlas books."""
|
||||||
|
book_name = book_name.rstrip("/")
|
||||||
|
book_path = SPR_ROOT / "atlas" / "books" / book_name
|
||||||
|
|
||||||
|
if not book_path.exists():
|
||||||
|
return JSONResponse({"detail": "Book not found"}, status_code=404)
|
||||||
|
|
||||||
|
index_html = book_path / "index.html"
|
||||||
|
if index_html.exists():
|
||||||
|
return HTMLResponse(index_html.read_text())
|
||||||
|
|
||||||
|
readme = book_path / "README.md"
|
||||||
|
if readme.exists():
|
||||||
|
return HTMLResponse(f"<pre>{readme.read_text()}</pre>")
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
{"book": book_name, "files": [f.name for f in book_path.iterdir()]}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/atlas/{path:path}")
|
@app.get("/atlas/{path:path}")
|
||||||
def atlas_route(path: str):
|
def atlas_route(path: str):
|
||||||
"""Atlas sub-routes."""
|
"""Atlas sub-routes."""
|
||||||
return {"system": "atlas", "path": path, "message": "Atlas route placeholder"}
|
return {"system": "atlas", "path": path}
|
||||||
|
|
||||||
|
|
||||||
# === Station ===
|
# === Station ===
|
||||||
@@ -271,7 +293,7 @@ def station_index(request: Request):
|
|||||||
@app.get("/station/{path:path}")
|
@app.get("/station/{path:path}")
|
||||||
def station_route(path: str):
|
def station_route(path: str):
|
||||||
"""Station sub-routes."""
|
"""Station sub-routes."""
|
||||||
return {"system": "station", "path": path, "message": "Station route placeholder"}
|
return {"system": "station", "path": path}
|
||||||
|
|
||||||
|
|
||||||
# === Generate ===
|
# === Generate ===
|
||||||
@@ -290,7 +312,6 @@ def generate_config(req: dict):
|
|||||||
"""Generate a config.json for a new room."""
|
"""Generate a config.json for a new room."""
|
||||||
config = load_config()
|
config = load_config()
|
||||||
hub_port = config.get("framework", {}).get("hub_port", 12000)
|
hub_port = config.get("framework", {}).get("hub_port", 12000)
|
||||||
system_ports = {s["key"]: s["port"] for s in config.get("systems", [])}
|
|
||||||
|
|
||||||
framework = req.get("framework", {})
|
framework = req.get("framework", {})
|
||||||
systems = req.get("systems", {})
|
systems = req.get("systems", {})
|
||||||
@@ -307,17 +328,14 @@ def generate_config(req: dict):
|
|||||||
{
|
{
|
||||||
"key": "data_flow",
|
"key": "data_flow",
|
||||||
"name": systems.get("artery", "artery"),
|
"name": systems.get("artery", "artery"),
|
||||||
"port": system_ports.get("data_flow", 12001),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "documentation",
|
"key": "documentation",
|
||||||
"name": systems.get("atlas", "atlas"),
|
"name": systems.get("atlas", "atlas"),
|
||||||
"port": system_ports.get("documentation", 12002),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "execution",
|
"key": "execution",
|
||||||
"name": systems.get("station", "station"),
|
"name": systems.get("station", "station"),
|
||||||
"port": system_ports.get("execution", 12003),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ Loads and validates framework configuration files.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
|
||||||
from typing import Dict, Any, List, Optional
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FrameworkConfig:
|
class FrameworkConfig:
|
||||||
"""Framework metadata"""
|
"""Framework metadata"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
slug: str
|
slug: str
|
||||||
version: str
|
version: str
|
||||||
@@ -25,18 +26,19 @@ class FrameworkConfig:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class SystemConfig:
|
class SystemConfig:
|
||||||
"""System configuration"""
|
"""System configuration"""
|
||||||
|
|
||||||
key: str
|
key: str
|
||||||
name: str
|
name: str
|
||||||
slug: str
|
slug: str = ""
|
||||||
title: str
|
title: str = ""
|
||||||
tagline: str
|
tagline: str = ""
|
||||||
port: int
|
icon: str = ""
|
||||||
icon: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ComponentConfig:
|
class ComponentConfig:
|
||||||
"""Component configuration"""
|
"""Component configuration"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
title: str
|
title: str
|
||||||
description: str
|
description: str
|
||||||
@@ -54,7 +56,7 @@ class ConfigLoader:
|
|||||||
self.systems: List[SystemConfig] = []
|
self.systems: List[SystemConfig] = []
|
||||||
self.components: Dict[str, Dict[str, ComponentConfig]] = {}
|
self.components: Dict[str, Dict[str, ComponentConfig]] = {}
|
||||||
|
|
||||||
def load(self) -> 'ConfigLoader':
|
def load(self) -> "ConfigLoader":
|
||||||
"""Load configuration from file"""
|
"""Load configuration from file"""
|
||||||
with open(self.config_path) as f:
|
with open(self.config_path) as f:
|
||||||
self.raw_config = json.load(f)
|
self.raw_config = json.load(f)
|
||||||
@@ -67,25 +69,25 @@ class ConfigLoader:
|
|||||||
|
|
||||||
def _parse_framework(self):
|
def _parse_framework(self):
|
||||||
"""Parse framework metadata"""
|
"""Parse framework metadata"""
|
||||||
fw = self.raw_config['framework']
|
fw = self.raw_config["framework"]
|
||||||
self.framework = FrameworkConfig(**fw)
|
self.framework = FrameworkConfig(**fw)
|
||||||
|
|
||||||
def _parse_systems(self):
|
def _parse_systems(self):
|
||||||
"""Parse system configurations"""
|
"""Parse system configurations"""
|
||||||
for sys in self.raw_config['systems']:
|
for sys in self.raw_config["systems"]:
|
||||||
self.systems.append(SystemConfig(**sys))
|
self.systems.append(SystemConfig(**sys))
|
||||||
|
|
||||||
def _parse_components(self):
|
def _parse_components(self):
|
||||||
"""Parse component configurations"""
|
"""Parse component configurations"""
|
||||||
comps = self.raw_config['components']
|
comps = self.raw_config["components"]
|
||||||
|
|
||||||
# Shared components
|
# Shared components
|
||||||
self.components['shared'] = {}
|
self.components["shared"] = {}
|
||||||
for key, value in comps.get('shared', {}).items():
|
for key, value in comps.get("shared", {}).items():
|
||||||
self.components['shared'][key] = ComponentConfig(**value)
|
self.components["shared"][key] = ComponentConfig(**value)
|
||||||
|
|
||||||
# System-specific components
|
# System-specific components
|
||||||
for system_key in ['data_flow', 'documentation', 'execution']:
|
for system_key in ["data_flow", "documentation", "execution"]:
|
||||||
self.components[system_key] = {}
|
self.components[system_key] = {}
|
||||||
for comp_key, comp_value in comps.get(system_key, {}).items():
|
for comp_key, comp_value in comps.get(system_key, {}).items():
|
||||||
self.components[system_key][comp_key] = ComponentConfig(**comp_value)
|
self.components[system_key][comp_key] = ComponentConfig(**comp_value)
|
||||||
@@ -97,13 +99,15 @@ class ConfigLoader:
|
|||||||
return sys
|
return sys
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_component(self, system_key: str, component_key: str) -> Optional[ComponentConfig]:
|
def get_component(
|
||||||
|
self, system_key: str, component_key: str
|
||||||
|
) -> Optional[ComponentConfig]:
|
||||||
"""Get component config"""
|
"""Get component config"""
|
||||||
return self.components.get(system_key, {}).get(component_key)
|
return self.components.get(system_key, {}).get(component_key)
|
||||||
|
|
||||||
def get_shared_component(self, key: str) -> Optional[ComponentConfig]:
|
def get_shared_component(self, key: str) -> Optional[ComponentConfig]:
|
||||||
"""Get shared component config"""
|
"""Get shared component config"""
|
||||||
return self.components.get('shared', {}).get(key)
|
return self.components.get("shared", {}).get(key)
|
||||||
|
|
||||||
|
|
||||||
def load_config(config_path: str | Path) -> ConfigLoader:
|
def load_config(config_path: str | Path) -> ConfigLoader:
|
||||||
@@ -115,6 +119,7 @@ def load_config(config_path: str | Path) -> ConfigLoader:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Test with pawprint config
|
# Test with pawprint config
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
config_path = Path(__file__).parent.parent / "pawprint.config.json"
|
config_path = Path(__file__).parent.parent / "pawprint.config.json"
|
||||||
|
|
||||||
loader = load_config(config_path)
|
loader = load_config(config_path)
|
||||||
@@ -126,5 +131,5 @@ if __name__ == "__main__":
|
|||||||
print(f" {sys.icon} {sys.title} ({sys.name}) - {sys.tagline}")
|
print(f" {sys.icon} {sys.title} ({sys.name}) - {sys.tagline}")
|
||||||
|
|
||||||
print(f"\nShared Components:")
|
print(f"\nShared Components:")
|
||||||
for key, comp in loader.components['shared'].items():
|
for key, comp in loader.components["shared"].items():
|
||||||
print(f" {comp.name} - {comp.description}")
|
print(f" {comp.name} - {comp.description}")
|
||||||
|
|||||||
Reference in New Issue
Block a user