Maksim Totmin cc9da3ad7d refactor: common util package, ESL/AMI/security fixes, Prometheus metrics
Backend stability and security improvements:

* internal/util/ — common RandomHex helper, removed 3 duplicates
* ESL: deduplicated readMessage (locked/unlocked), net.JoinHostPort for IPv6
* AMI: synchronous reconnect() in readEventsLoop, net.JoinHostPort for IPv6
* Auth: /api/auth/refresh accepts Authorization header only (no ?token=)
* decodeJSON: http.MaxBytesReader(1<<20) body limit
* Trunks: gatewayParams() uses configured ESL.GatewayPrefix
* Config: jwt_secret_env env-var fallback
* FSCollector: time.After → time.NewTimer with defer Stop
* Monitoring: Prometheus counters (route_requests, nodes_total/healthy, uptime)
* go fmt pass across all internal/ packages
2026-06-25 19:30:36 +07:00

64 lines
1.9 KiB
Go

package api
import (
"net/http"
)
// handleHealth — GET /api/health — возвращает статус всех зависимостей.
func (a *API) handleHealth(w http.ResponseWriter, r *http.Request) {
stats := a.engine.GetHealthStats()
natsStatus := "disconnected"
if a.natsConnected != nil && a.natsConnected() {
natsStatus = "connected"
}
eslInfo := map[string]interface{}{"status": "disabled"}
if a.eslClient != nil {
eslStats := a.eslClient.GetStats()
eslInfo = map[string]interface{}{
"status": eslStats.Status,
"host": eslStats.Host,
"uptime_seconds": eslStats.UptimeSec,
"reconnects": eslStats.Reconnects,
"gateway_ops": eslStats.GatewayOps,
"events_recv": eslStats.EventsRecv,
}
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"status": "ok",
"version": "1.0.0",
"connections": map[string]interface{}{
"nats": natsStatus,
"esl": eslInfo,
},
"stats": stats,
})
}
// handleLiveness — GET /api/health/live — всегда 200, если процесс жив.
func (a *API) handleLiveness(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "alive"})
}
// handleReadiness — GET /api/health/ready — 200 когда NATS подключён, метрики поступают.
// ESL опционален — не требуется для готовности.
func (a *API) handleReadiness(w http.ResponseWriter, r *http.Request) {
if a.natsConnected != nil && !a.natsConnected() {
writeJSON(w, http.StatusServiceUnavailable, map[string]string{
"status": "not_ready",
"reason": "nats_disconnected",
})
return
}
if !a.engine.HasRecentMetrics(60) {
writeJSON(w, http.StatusServiceUnavailable, map[string]string{
"status": "not_ready",
"reason": "no_recent_metrics",
})
return
}
writeJSON(w, http.StatusOK, map[string]string{"status": "ready"})
}