mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
8a44410e37
* feat(gateway): support hot reload and empty startup - extract gateway runtime into pkg/gateway - add gateway.hot_reload config with default and example values - allow starting the gateway without a default model via --allow-empty - stop treating missing enabled channels as a startup error - update related tests * feat: replace gateway SSE updates with polling-based state sync - remove gateway SSE broadcasting and event endpoint - add polling-based gateway status refresh with stopping state handling - detect when gateway restart is required after default model changes - resolve gateway health and websocket proxy targets from configured host - update gateway UI labels and add backend/frontend test coverage
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package middleware
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"runtime/debug"
|
|
"time"
|
|
)
|
|
|
|
// JSONContentType sets the Content-Type header to application/json for
|
|
// API requests handled by the wrapped handler.
|
|
func JSONContentType(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/api/" {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// responseRecorder wraps http.ResponseWriter to capture the status code.
|
|
type responseRecorder struct {
|
|
http.ResponseWriter
|
|
statusCode int
|
|
}
|
|
|
|
func (rr *responseRecorder) WriteHeader(code int) {
|
|
rr.statusCode = code
|
|
rr.ResponseWriter.WriteHeader(code)
|
|
}
|
|
|
|
// Flush delegates to the underlying ResponseWriter if it implements http.Flusher.
|
|
func (rr *responseRecorder) Flush() {
|
|
if f, ok := rr.ResponseWriter.(http.Flusher); ok {
|
|
f.Flush()
|
|
}
|
|
}
|
|
|
|
// Unwrap returns the underlying ResponseWriter so that http.ResponseController
|
|
// and interface checks (like http.Flusher) can see through the wrapper.
|
|
func (rr *responseRecorder) Unwrap() http.ResponseWriter {
|
|
return rr.ResponseWriter
|
|
}
|
|
|
|
// Logger logs each HTTP request with method, path, status code, and duration.
|
|
func Logger(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
start := time.Now()
|
|
rec := &responseRecorder{ResponseWriter: w, statusCode: http.StatusOK}
|
|
next.ServeHTTP(rec, r)
|
|
log.Printf("%s %s %d %s", r.Method, r.URL.Path, rec.statusCode, time.Since(start))
|
|
})
|
|
}
|
|
|
|
// Recoverer recovers from panics in downstream handlers and returns a 500
|
|
// Internal Server Error response.
|
|
func Recoverer(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
log.Printf("panic recovered: %v\n%s", err, debug.Stack())
|
|
http.Error(w, `{"error":"internal server error"}`, http.StatusInternalServerError)
|
|
}
|
|
}()
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|