extract middlewares to lightmux-contrib

Removes pkg/middleware. The Logger, Recoverer, and RealIP middlewares
now live in the sibling lightmux-contrib module as the realip,
requestlog, and recoverer packages, each exposing a single New(...)
constructor.

The Middleware type alias moves to pkg/router. The splinter dependency
is dropped from go.mod; only errx remains.

BREAKING CHANGE: consumers must replace pkg/middleware imports with
the corresponding lightmux-contrib sub-packages. See README for the
new usage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
juancwu 2026-04-26 14:02:54 +00:00
commit 22277186ae
15 changed files with 44 additions and 612 deletions

View file

@ -22,12 +22,10 @@ import (
"strconv"
"git.juancwu.dev/juancwu/lightmux"
"git.juancwu.dev/juancwu/lightmux/pkg/middleware"
)
func main() {
mux := lightmux.New()
mux.Use(middleware.Recoverer, middleware.Logger)
mux.Get("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello from lightmux")
@ -71,34 +69,29 @@ There are two ways to attach middleware: chain-style with `Use`, or per-route as
```go
mux := lightmux.New()
mux.Use(middleware.Recoverer, middleware.Logger) // applies to every route registered after
mux.Use(authMiddleware) // applies to every route registered after
mux.Get("/admin", adminHandler, requireAdmin) // requireAdmin only on this route
mux.Get("/admin", adminHandler, requireAdmin) // requireAdmin only on this route
```
Order is outer → inner: `Use`-order first, then per-route mws. The outermost middleware runs first on the request and last on the response.
Middleware values are plain `func(http.Handler) http.Handler`, so any stdlib-compatible middleware works without an adapter.
## Built-in middleware
An opinionated set of middlewares (request logging, panic recovery, real-IP resolution) lives in a sibling module — see [lightmux-contrib](https://git.juancwu.dev/juancwu/lightmux-contrib):
The `pkg/middleware` package ships:
- **`Logger`** — emits a structured `http.request` record (method, path, status, duration, client) via [splinter](https://git.juancwu.dev/juancwu/splinter)'s default logger. The `client` field is `r.RemoteAddr`, so pairing with `RealIP` makes it the resolved client IP.
- **`LoggerWith(*splinter.Logger)`** — same, but routes records through the supplied splinter logger instead of the default.
- **`Recoverer`** — catches panics inside handlers, wraps the value with [errx](https://git.juancwu.dev/juancwu/errx) under op `middleware.Recoverer`, logs it with the stack, and writes a 500 response.
- **`RealIP`** — replaces `r.RemoteAddr` with the originating client IP from `CF-Connecting-IP`, `True-Client-IP`, `X-Real-IP`, or `X-Forwarded-For` (in that order). Always trusts these headers — only register it when the service sits behind a trusted proxy.
- **`RealIPWith(trusted ...netip.Prefix)`** — same, but only honors the headers when the immediate peer's IP falls within one of the trusted prefixes. Requests from outside the allowlist pass through untouched.
```go
custom := splinter.New(splinter.WithStream(...))
mux.Use(middleware.Recoverer, middleware.LoggerWith(custom))
```sh
go get git.juancwu.dev/juancwu/lightmux-contrib
```
When using `RealIP` together with `Logger`, register `RealIP` first so the logged `client` field is the resolved client IP rather than the proxy's peer address:
```go
mux.Use(middleware.RealIP, middleware.Logger)
import (
"git.juancwu.dev/juancwu/lightmux-contrib/realip"
"git.juancwu.dev/juancwu/lightmux-contrib/recoverer"
"git.juancwu.dev/juancwu/lightmux-contrib/requestlog"
)
mux.Use(recoverer.New(), realip.New(), requestlog.New(nil))
```
## Path parameters
@ -114,5 +107,5 @@ mux.Get("/items/{name}", func(w http.ResponseWriter, r *http.Request) {
## Notes
- `mux.Get("/", h)` registers `"GET /"`, which is a stdlib **subtree** pattern — it matches every unmatched path. Use `"/{$}"` to match only the literal root.
- Bad route registrations (invalid prefix, conflicting wildcards) panic at startup, matching stdlib `http.ServeMux` behavior. `Recoverer` handles panics that occur *inside* request handlers.
- Bad route registrations (invalid prefix, conflicting wildcards) panic at startup, matching stdlib `http.ServeMux` behavior. The `recoverer` middleware in [lightmux-contrib](https://git.juancwu.dev/juancwu/lightmux-contrib) handles panics that occur *inside* request handlers.
- Group prefixes apply to the path only — they never inject a host. Routes can still carry an explicit host via `Handle("GET host.com/path", h)`.