Files
phase-memory/src/phase_memory/service_app.py

78 lines
2.6 KiB
Python

"""Deployable stdlib service entrypoint for phase-memory."""
from __future__ import annotations
import argparse
from dataclasses import dataclass
from typing import Sequence
from wsgiref.simple_server import make_server
from .service import RuntimeConfig
from .service_binding import ServiceBinding, service_binding_from_config
SERVICE_APP_SCHEMA = "phase_memory.service.app.v1"
@dataclass(frozen=True)
class ServiceAppConfig:
host: str = "127.0.0.1"
port: int = 8080
local_store_path: str = ".phase-memory-local"
def runtime_config(self) -> RuntimeConfig:
return RuntimeConfig(local_store_path=self.local_store_path)
def to_dict(self) -> dict:
return {
"host": self.host,
"port": self.port,
"local_store_path": self.local_store_path,
}
def build_service_binding(config: ServiceAppConfig | None = None) -> ServiceBinding:
config = config or ServiceAppConfig()
return service_binding_from_config(config.runtime_config())
def service_app_metadata(config: ServiceAppConfig | None = None) -> dict:
config = config or ServiceAppConfig()
binding = build_service_binding(config)
readiness = binding.readiness()
return {
"schema_version": SERVICE_APP_SCHEMA,
"config": config.to_dict(),
"readiness": readiness,
"routes": {
"health": "/health",
"readiness": "/ready",
"contracts": "/contracts",
"operations": "/operations/{operation}",
},
}
def create_wsgi_app(config: ServiceAppConfig | None = None):
return build_service_binding(config).as_wsgi_app()
def serve(config: ServiceAppConfig | None = None) -> None:
config = config or ServiceAppConfig()
app = create_wsgi_app(config)
with make_server(config.host, config.port, app) as server:
server.serve_forever()
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Run the phase-memory service binding.")
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", type=int, default=8080)
parser.add_argument("--store", default=".phase-memory-local")
parser.add_argument("--check", action="store_true", help="Build the app and return readiness status without listening.")
args = parser.parse_args(list(argv) if argv is not None else None)
config = ServiceAppConfig(host=args.host, port=args.port, local_store_path=args.store)
if args.check:
return 0 if service_app_metadata(config)["readiness"]["ok"] else 1
serve(config)
return 0