Initial commit: ifconfig.me clone on the kaya framework
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# pyfconfig
|
||||
|
||||
A clone of [ifconfig.me](https://ifconfig.me/) built on the
|
||||
[kaya](https://gitea.woggioni.net/woggioni/kaya) framework
|
||||
(`kaya-core` + `kaya-rsgi`), served by [Granian](https://github.com/emmett-framework/granian)
|
||||
over the RSGI protocol.
|
||||
|
||||
## Stack
|
||||
|
||||
- **kaya-core** — routing and HTTP request/response handling
|
||||
- **kaya-rsgi** — Granian (RSGI) adapter
|
||||
- **granian** — application server
|
||||
- **httpx + pwo** — test client over kaya's ASGI transport
|
||||
|
||||
No database, sessions, or authentication — the app is stateless.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Response |
|
||||
|---|---|---|
|
||||
| GET | `/` | HTML page for browsers (`Accept: text/html`), plain-text IP otherwise |
|
||||
| GET | `/ip` | Client IP address |
|
||||
| GET | `/ua` | `User-Agent` header |
|
||||
| GET | `/lang` | `Accept-Language` header |
|
||||
| GET | `/encoding` | `Accept-Encoding` header |
|
||||
| GET | `/mime` | `Accept` header |
|
||||
| GET | `/charset` | `Accept-Charset` header |
|
||||
| GET | `/forwarded` | `X-Forwarded-For` header |
|
||||
| GET | `/all` | All connection fields as `key: value` lines (empty fields included; `remote_host` shown as `unavailable`) |
|
||||
| GET | `/all.json` | Same fields as a JSON object, empty fields omitted |
|
||||
| GET | `/api/health` | Liveness probe (`{"status":"ok"}`) |
|
||||
|
||||
The `/all` field order mirrors the reference site: `ip_addr`,
|
||||
`remote_host`, `user_agent`, `port`, `language`, `referer`, `connection`,
|
||||
`keep_alive`, `method`, `encoding`, `mime`, `charset`, `via`, `forwarded`.
|
||||
|
||||
Example:
|
||||
|
||||
```console
|
||||
$ curl http://localhost:8080/
|
||||
203.0.113.7
|
||||
$ curl http://localhost:8080/all.json
|
||||
{"ip_addr":"203.0.113.7","user_agent":"curl/8.21.0","port":"51342","method":"GET","mime":"*/*"}
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
### With Docker Compose (recommended)
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
# App published at http://localhost:8080
|
||||
```
|
||||
|
||||
### On the host
|
||||
|
||||
```bash
|
||||
cp .env.example .env # optional; all settings have defaults
|
||||
python -m venv .venv && . .venv/bin/activate
|
||||
pip install --index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple \
|
||||
--extra-index-url https://pypi.org/simple \
|
||||
-e .
|
||||
granian --interface rsgi --host 0.0.0.0 --port 8000 pyfconfig.app:app
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Environment variables (see `.env.example`):
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `APP_HOST` | `0.0.0.0` | Bind host (informational; granian is configured via `GRANIAN_*`) |
|
||||
| `APP_PORT` | `8000` | Bind port (informational) |
|
||||
| `SITE_NAME` | `pyfconfig` | Public name used in the HTML page title and the curl examples (set to your domain, e.g. `ifconfig.example.com`) |
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
. .venv/bin/activate
|
||||
python -m unittest discover -s tests -t .
|
||||
```
|
||||
|
||||
The tests drive the app in-process through kaya's ASGI interface using
|
||||
`httpx.ASGITransport`; no external services are needed.
|
||||
|
||||
## Project layout
|
||||
|
||||
```
|
||||
src/pyfconfig/
|
||||
├── app.py # KayaApp assembly; imports route modules
|
||||
├── config.py # env-driven Settings dataclass
|
||||
├── page.py # HTML landing page builder (kaya has no templating)
|
||||
└── routes/
|
||||
├── health.py # GET /api/health
|
||||
├── root.py # GET / with content negotiation
|
||||
└── connection.py # /ip /ua /lang /encoding /mime /charset /forwarded /all /all.json
|
||||
tests/
|
||||
└── test_routes.py # unittest + httpx.ASGITransport
|
||||
```
|
||||
|
||||
Route modules import the module-level `app` from `pyfconfig.app` and
|
||||
register handlers with `@app.GET(...)` decorators at import time —
|
||||
`pyfconfig.app` imports them last to complete the wiring.
|
||||
|
||||
## Deployment
|
||||
|
||||
The `Dockerfile` is a multi-stage alpine build producing a minimal,
|
||||
non-root runtime image; pushing a `release/*` tag triggers the Gitea
|
||||
Actions workflow in `.gitea/workflows/build.yaml`, which builds and
|
||||
publishes the image to `gitea.woggioni.net/woggioni-opencode-agent/pyfconfig`.
|
||||
Reference in New Issue
Block a user