56 lines
2.1 KiB
Python
56 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
"""프레임워크 중립 최소 스타터 — Python 표준 라이브러리만(의존성 0).
|
|
|
|
배포 계약만 보여준다:
|
|
· PORT 환경변수로 리슨(기본 8080)
|
|
· GET /healthz → 200 {"ok": true} (매니페스트 health 경로)
|
|
· GET / → 앱 정보 + 바인딩된 소스의 <PREFIX>_URL '키'만(값은 노출 안 함)
|
|
새 프로젝트는 이 파일을 원하는 스택으로 교체하되, 위 3가지 계약만 지키면 된다.
|
|
"""
|
|
import http.server
|
|
import json
|
|
import os
|
|
import socketserver
|
|
|
|
PORT = int(os.environ.get("PORT", "8080"))
|
|
|
|
|
|
def bound_source_keys() -> list[str]:
|
|
"""바인딩된 데이터 소스가 주입한 <PREFIX>_URL 키만(값 미노출) — 무엇이 연결됐는지 확인용."""
|
|
return sorted(
|
|
k for k, v in os.environ.items()
|
|
if k.endswith("_URL") and isinstance(v, str) and "://" in v
|
|
)
|
|
|
|
|
|
class Handler(http.server.BaseHTTPRequestHandler):
|
|
def _send(self, code: int, obj: dict) -> None:
|
|
body = json.dumps(obj, ensure_ascii=False).encode()
|
|
self.send_response(code)
|
|
self.send_header("content-type", "application/json; charset=utf-8")
|
|
self.send_header("content-length", str(len(body)))
|
|
self.end_headers()
|
|
self.wfile.write(body)
|
|
|
|
def do_GET(self) -> None: # noqa: N802
|
|
path = self.path.split("?", 1)[0].rstrip("/") or "/"
|
|
if path in ("/healthz", "/health"):
|
|
self._send(200, {"ok": True})
|
|
return
|
|
self._send(200, {
|
|
"app": os.environ.get("APP_NAME", "yakcloud-starter"),
|
|
"host": os.environ.get("HOSTNAME", "?"),
|
|
"bound_sources": bound_source_keys(), # 연결된 소스 <PREFIX>_URL 키(값 미노출)
|
|
"path": self.path,
|
|
})
|
|
|
|
def log_message(self, *_args) -> None: # 로그 조용히
|
|
return
|
|
|
|
|
|
if __name__ == "__main__":
|
|
socketserver.ThreadingTCPServer.allow_reuse_address = True
|
|
with socketserver.ThreadingTCPServer(("", PORT), Handler) as httpd:
|
|
print(f"yakcloud-starter listening on :{PORT}", flush=True)
|
|
httpd.serve_forever()
|