forked from retoor/devplacepy
refactor: split docs_api.py into package (ref.md 3.1)
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from ._shared import SERVICE_ACTIONS, endpoint, field
|
||||
from .negotiation import _classify
|
||||
|
||||
|
||||
def _service_control_endpoints():
|
||||
endpoints = []
|
||||
for action, summary in SERVICE_ACTIONS:
|
||||
endpoints.append(
|
||||
endpoint(
|
||||
id=f"services-{action.replace('-', '')}",
|
||||
method="POST",
|
||||
path=f"/admin/services/{{name}}/{action}",
|
||||
title=f"Service: {action}",
|
||||
summary=summary + ".",
|
||||
auth="admin",
|
||||
interactive=True,
|
||||
destructive=True,
|
||||
params=[
|
||||
field(
|
||||
"name",
|
||||
"path",
|
||||
required=True,
|
||||
example="news",
|
||||
description="Registered service name.",
|
||||
)
|
||||
],
|
||||
sample_response={"ok": True},
|
||||
)
|
||||
)
|
||||
return endpoints
|
||||
|
||||
|
||||
def _field_to_param(spec):
|
||||
description = spec["label"]
|
||||
if spec.get("help"):
|
||||
description = f"{spec['label']} - {spec['help']}"
|
||||
value = "" if spec.get("secret") else str(spec.get("value", ""))
|
||||
if spec.get("secret"):
|
||||
description += " Leave blank to keep the current value."
|
||||
if spec["type"] == "bool":
|
||||
return field(
|
||||
spec["key"], "form", "enum", False, value or "0", description, ["1", "0"]
|
||||
)
|
||||
if spec["type"] == "select":
|
||||
options = [option["value"] for option in spec.get("options") or []]
|
||||
return field(
|
||||
spec["key"],
|
||||
"form",
|
||||
"enum",
|
||||
False,
|
||||
value or (options[0] if options else ""),
|
||||
description,
|
||||
options,
|
||||
)
|
||||
if spec["type"] in ("int", "float"):
|
||||
return field(spec["key"], "form", "int", False, value, description)
|
||||
return field(spec["key"], "form", "string", False, value, description)
|
||||
|
||||
|
||||
def _service_section(service):
|
||||
enabled = "yes" if service.get("enabled") else "no"
|
||||
groups = ", ".join(group["name"] for group in service.get("field_groups", []))
|
||||
lines = [
|
||||
f"## {service.get('title') or service['name']}",
|
||||
"",
|
||||
service.get("description", ""),
|
||||
"",
|
||||
f"- Service name: `{service['name']}`",
|
||||
f"- Enabled: {enabled}",
|
||||
f"- Run interval: {service.get('interval_seconds', 0)}s",
|
||||
]
|
||||
if groups:
|
||||
lines.append(f"- Configuration groups: {groups}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def build_services_group(services, base):
|
||||
intro_parts = [
|
||||
"# Background Services",
|
||||
"",
|
||||
"DevPlace runs background services supervised by a single manager. Each service has its "
|
||||
"own enable flag, run interval, live status, metrics, and a rolling log buffer. Manage "
|
||||
"them from the admin panel at `/admin/services` or with the endpoints below.",
|
||||
"",
|
||||
"Control a service by its `name` (shown per service): start or stop it, trigger a single "
|
||||
"run, clear its logs, or save its configuration. `GET /admin/services/data` returns the "
|
||||
"live status, metrics, and log tail for every service.",
|
||||
"",
|
||||
"See the [Admin API](/docs/admin.html) for the rest of administration; the Devii assistant "
|
||||
"is itself a service, configured in [Configuration and CLI](/docs/devii-config.html).",
|
||||
]
|
||||
config_endpoints = []
|
||||
for service in services:
|
||||
intro_parts.append("")
|
||||
intro_parts.append(_service_section(service))
|
||||
params = [
|
||||
_field_to_param(spec)
|
||||
for spec in service.get("fields", [])
|
||||
if not spec["key"].endswith("_enabled")
|
||||
]
|
||||
config_endpoints.append(
|
||||
endpoint(
|
||||
id=f"services-config-{service['name']}",
|
||||
method="POST",
|
||||
path=f"/admin/services/{service['name']}/config",
|
||||
title=f"Configure {service.get('title') or service['name']}",
|
||||
summary=f"Save configuration for the {service['name']} service. Empty values keep the current setting.",
|
||||
auth="admin",
|
||||
encoding="form",
|
||||
destructive=True,
|
||||
params=params,
|
||||
notes=[
|
||||
"Use start/stop to enable or disable the service; this saves the remaining settings."
|
||||
],
|
||||
)
|
||||
)
|
||||
control_endpoints = [
|
||||
endpoint(
|
||||
id="services-data",
|
||||
method="GET",
|
||||
path="/admin/services/data",
|
||||
title="Service status",
|
||||
summary="Live status, metrics, and log tail for every background service.",
|
||||
auth="admin",
|
||||
sample_response={
|
||||
"services": [{"name": "news", "status": "running", "enabled": True}]
|
||||
},
|
||||
),
|
||||
endpoint(
|
||||
id="services-detail-data",
|
||||
method="GET",
|
||||
path="/admin/services/{name}/data",
|
||||
title="One service status",
|
||||
summary="Live status, metrics, and log tail for a single background service.",
|
||||
auth="admin",
|
||||
params=[field("name", "path", "string", True, "news", "Service name.")],
|
||||
sample_response={
|
||||
"service": {"name": "news", "status": "running", "enabled": True}
|
||||
},
|
||||
),
|
||||
*_service_control_endpoints(),
|
||||
]
|
||||
endpoints = control_endpoints + config_endpoints
|
||||
for ep in endpoints:
|
||||
ep["negotiation"] = _classify(ep)
|
||||
return {
|
||||
"slug": "services",
|
||||
"title": "Background Services",
|
||||
"admin": True,
|
||||
"intro": "\n".join(intro_parts),
|
||||
"endpoints": endpoints,
|
||||
}
|
||||
Reference in New Issue
Block a user