- Rust 96.4%
- Shell 2%
- Dockerfile 1.6%
AGENTS.md requires forwarding to be abstracted behind a trait so handlers never call a raw HTTP client. The trait lives in src/proxy/mod.rs and ReqwestForwarder implements it; proxy_handler now calls forward(). |
||
|---|---|---|
| goals | ||
| scripts | ||
| src | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
deepseek-peak-proxy
A high-performance, time-gated reverse proxy for the DeepSeek API. It sits in front of the upstream endpoint, evaluates the current time against configured peak-hour windows, and rejects/throttles requests during those windows — without ever opening an outbound connection. Outside peak hours, requests are forwarded to upstream with streaming support.
Current status: MVP complete (Goals 1–2). The proxy is fully runnable and deployable via Docker. Subsequent milestones are reserved for hardening and optional features.
Features
- Peak-hour gating engine — 24-hour range parser (
HH:MM-HH:MM) supporting multiple comma-separated windows and overnight ranges spanning midnight (e.g.23:00-02:00). - HTTP server — Axum-based router with a peak-gate middleware, a
/healthzliveness endpoint, and a catch-all streaming proxy route. - Streaming upstream forwarder —
reqwestclient pipes request/response bodies chunk by chunk (minimal buffering, SSE-friendly) and strips RFC 7230 hop-by-hop headers (Connection,Keep-Alive,Proxy-Authenticate, …) while preservingAuthorization: Bearer …. - Configurable rejection status — blocked requests get a structured JSON error with
429(default) or503, honoringBLOCKED_STATUS_CODE. - Deterministic time abstraction —
TimeProvidertrait with a wall-clockSystemTimeProviderand a thread-safeMockTimeProvider(zero-flake tests, no network I/O). - Strict configuration validation — environment-driven config with descriptive startup errors.
- Quality gates —
rustfmt, Clippy (-D warnings), and a full unit/integration/e2e test suite wired into a pre-commit hook. - Containerization — multi-stage, non-root Docker image with a
/healthzhealth check;docker composefor local deployment.
Architecture
Hexagonal / clean architecture. Domain logic is fully decoupled from infrastructure behind traits:
src/
├── config/
│ ├── mod.rs # Env config loading & validation
│ └── peak_range.rs # HH:MM-HH:MM parsing & interval math
├── domain/
│ ├── mod.rs
│ ├── time_provider.rs # TimeProvider trait + System/Mock providers
│ └── gatekeeper.rs # Block/allow decision engine
├── proxy/
│ ├── mod.rs
│ └── client.rs # ReqwestForwarder (streaming, header sanitization)
├── server/
│ ├── mod.rs # Router assembly + AppState
│ ├── handlers.rs # /healthz + catch-all proxy route
│ └── middleware.rs # Peak-hour gate middleware
├── error.rs # thiserror AppError enum
├── lib.rs # Library facade
└── main.rs # Entry point (telemetry, config, server lifecycle)
The HTTP layer plugs into the Goal 1 domain core without touching domain logic.
Configuration
All configuration is read from environment variables at boot:
| Variable | Required | Default | Description |
|---|---|---|---|
API_URL |
Yes | — | Base upstream URL (e.g. https://api.deepseek.com). Must be a valid http(s) URL. |
PEEK_HOURS |
Yes | — | Comma-separated peak windows, e.g. 10:00-14:00,18:00-19:00. Ranges are start-inclusive, end-exclusive. |
PEAK_HOURS |
No | — | Alias for PEEK_HOURS (used only when PEEK_HOURS is unset). |
TIMEZONE |
No | UTC |
IANA timezone for window evaluation (e.g. America/New_York). |
LISTEN_ADDR |
No | 0.0.0.0:8080 |
Socket address the server binds to. |
BLOCKED_STATUS_CODE |
No | 429 |
Status code returned for blocked requests (429 or 503). |
Usage
Build & run locally
export API_URL="https://api.deepseek.com"
export PEEK_HOURS="10:00-14:00,18:00-19:00"
# optional: TIMEZONE, LISTEN_ADDR, BLOCKED_STATUS_CODE
cargo run
Verify the proxy is up:
curl http://127.0.0.1:8080/healthz # -> {"status":"healthy"}
During peak hours, proxied requests are rejected:
curl -i -X POST http://127.0.0.1:8080/v1/chat/completions -d '{}'
# HTTP/1.1 429 Too Many Requests
# {"error":{"code":429,"message":"Peak hours active. ...","type":"peak_hour_restriction"}}
Off-peak, requests (and streaming SSE bodies) pass straight through.
Docker
docker compose up -d --build
curl http://127.0.0.1:8080/healthz # -> HTTP 200 {"status":"healthy"}
The image is a two-stage build (rust:1.97-alpine builder → alpine:3.20 runtime), runs as non-root UID 10001, and embeds a /healthz health check.
Test
cargo test --all-targets
Covers unit tests (parsing, gatekeeper, config), plus an end-to-end test (tests/proxy_e2e_test.rs) that drives the real router through a loopback HTTP server against a wiremock upstream, asserting peak blocking (429) vs. off-peak forwarding (200) and /healthz availability.
Quality gates (before committing)
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets
Or install them as a mandatory pre-commit hook:
./scripts/install-hooks.sh
Installs .git/hooks/pre-commit and runs the full gate suite.
Roadmap
- Goal 1 — Core domain: config parser,
PeakHourSchedule/TimeRange,TimeProvidertrait,Gatekeeper, test suite, git hooks. - Goal 2 — MVP: Axum server bootstrap, peak-gate middleware,
/healthz, streaming Reqwest forwarder with hop-by-hop stripping, wiremock e2e test, Docker image + compose. - Hardening / optional: metric exporters, dynamic config reload, graceful-shutdown polish, performance tuning.