refactor: modularize chat backend, update docs for .m4s segments

This commit is contained in:
zwitschi committed 2026-08-07 13:16:44 +02:00
1 parent 46e878bef6
commit b3a10ba3ef
24 files changed
+3771 -2781

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
package metrics
import (
"context"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"gorm.io/gorm"
"chat/src/auth"
"chat/src/db"
"chat/src/ws"
)
// HandleMetrics returns Prometheus-format metrics for the chat service.
func HandleMetrics(gormDB *gorm.DB, redis db.RedisClient, hub *ws.Hub, sessionStore *auth.SessionStore, dbDriver, instanceID string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
var storedMessages int64
if gormDB != nil {
_ = gormDB.Model(&db.Message{}).Count(&storedMessages).Error
}
var moderationActions int64
if gormDB != nil {
_ = gormDB.Model(&db.ModerationLog{}).Count(&moderationActions).Error
}
redisEnabled := 0
redisUp := 0
redisClients := 0
if redis != nil {
redisEnabled = 1
if err := redis.Ping(context.Background()); err == nil {
redisUp = 1
if info, err := redis.Info(context.Background(), "clients"); err == nil {
for _, line := range strings.Split(info, "\n") {
if strings.HasPrefix(line, "connected_clients:") {
if value, err := strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(line, "connected_clients:"))); err == nil {
redisClients = value
}
break
}
}
}
}
}
connectedClients := 0
dmsSent := int64(0)
if hub != nil {
connectedClients = hub.ConnectedClients()
dmsSent = hub.DMsSent
}
activeSessions := 0
if sessionStore != nil {
activeSessions = sessionStore.CountActive()
}
w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
writeLine := func(name string, value any) {
fmt.Fprintf(w, "%s %v\n", name, value)
}
fmt.Fprintln(w, "# HELP linearvoid_chat_connected_clients Current connected WebSocket clients.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_connected_clients gauge")
writeLine("linearvoid_chat_connected_clients", connectedClients)
fmt.Fprintln(w, "# HELP linearvoid_chat_messages_total Total stored chat messages.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_messages_total gauge")
writeLine("linearvoid_chat_messages_total", storedMessages)
fmt.Fprintln(w, "# HELP linearvoid_chat_dms_total Total private messages sent.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_dms_total counter")
writeLine("linearvoid_chat_dms_total", dmsSent)
fmt.Fprintln(w, "# HELP linearvoid_chat_moderation_actions_total Total moderation log entries.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_moderation_actions_total gauge")
writeLine("linearvoid_chat_moderation_actions_total", moderationActions)
fmt.Fprintln(w, "# HELP linearvoid_chat_redis_enabled Redis configured for chat service.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_redis_enabled gauge")
writeLine("linearvoid_chat_redis_enabled", redisEnabled)
fmt.Fprintln(w, "# HELP linearvoid_chat_redis_up Redis reachable from chat service.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_redis_up gauge")
writeLine("linearvoid_chat_redis_up", redisUp)
fmt.Fprintln(w, "# HELP linearvoid_chat_redis_connected_clients Redis connected client count seen by chat service.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_redis_connected_clients gauge")
writeLine("linearvoid_chat_redis_connected_clients", redisClients)
fmt.Fprintln(w, "# HELP linearvoid_chat_admin_sessions_active Active unexpired admin sessions.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_admin_sessions_active gauge")
writeLine("linearvoid_chat_admin_sessions_active", activeSessions)
fmt.Fprintln(w, "# HELP linearvoid_chat_build_info Static build info for chat service.")
fmt.Fprintln(w, "# TYPE linearvoid_chat_build_info gauge")
fmt.Fprintf(w, "linearvoid_chat_build_info{service=\"chat\",database_driver=\"%s\",instance_id=\"%s\"} 1\n", dbDriver, instanceID)
}
}
// HandleHealth returns a simple health check endpoint.
func HandleHealth() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{"status":"healthy","service":"chat","timestamp":"`+time.Now().UTC().Format(time.RFC3339)+`"}`)
}
}
// HandleNotFound returns a 404 JSON response for all unhandled paths.
func HandleNotFound() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w, `{"error":"not found"}`)
}
}