added media fixes, search, push updates, pwa, metrics. preparing release 1.0
CI / Go (build + vet + test) (push) Canceled after 0s
CI / Web (build + lint) (push) Canceled after 0s

This commit is contained in:
vantablackTea
2026-09-27 23:26:15 +03:00
parent 855a62755c
commit 6fc6d977bf
59 changed files with 6823 additions and 113 deletions
+35 -15
View File
@@ -4,49 +4,66 @@ import (
"log/slog"
"net/http"
"strings"
"time"
"messenger/internal/auth"
"messenger/internal/media"
"messenger/internal/platform/config"
"messenger/internal/platform/ratelimit"
"messenger/internal/realtime"
"messenger/internal/store"
)
type apiHandler struct {
store *store.Store
tokens *auth.TokenManager
hub *realtime.Hub
log *slog.Logger
secure bool
media media.Storage
store *store.Store
tokens *auth.TokenManager
hub *realtime.Hub
log *slog.Logger
secure bool
media media.Storage
notifier *pushNotifier
}
// NewHandler builds the /api/v1 route tree with all middleware applied.
// static, when non-nil, serves the built frontend for non-API paths.
func NewHandler(st *store.Store, tm *auth.TokenManager, hub *realtime.Hub, log *slog.Logger, cfg *config.Config, ms media.Storage, static http.Handler) http.Handler {
h := &apiHandler{
store: st,
tokens: tm,
hub: hub,
log: log,
secure: cfg.Environment == "production",
media: ms,
store: st,
tokens: tm,
hub: hub,
log: log,
secure: cfg.Environment == "production",
media: ms,
notifier: newPushNotifier(st, hub, cfg.VAPIDPublicKey, cfg.VAPIDPrivateKey, cfg.VAPIDSubject),
}
mux := http.NewServeMux()
authHandler := requireAuth(tm, http.HandlerFunc(h.websocket))
authLimiter := ratelimit.New(20, time.Minute)
limited := func(inner http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !authLimiter.Allow(r) {
w.Header().Set("Retry-After", "60")
writeError(w, http.StatusTooManyRequests, "too many requests")
return
}
inner(w, r)
}
}
mux.HandleFunc("GET /api/v1/ping", func(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"message": "pong"})
})
mux.HandleFunc("POST /api/v1/auth/register", h.register)
mux.HandleFunc("POST /api/v1/auth/login", h.login)
mux.HandleFunc("POST /api/v1/auth/refresh", h.refresh)
mux.HandleFunc("POST /api/v1/auth/register", limited(h.register))
mux.HandleFunc("POST /api/v1/auth/login", limited(h.login))
mux.HandleFunc("POST /api/v1/auth/refresh", limited(h.refresh))
mux.HandleFunc("POST /api/v1/auth/logout", h.logout)
mux.Handle("GET /api/v1/users/me", requireAuth(tm, h.me))
mux.Handle("GET /api/v1/users", requireAuth(tm, h.searchUsers))
mux.Handle("GET /api/v1/search/messages", requireAuth(tm, h.searchMessages))
mux.Handle("GET /api/v1/contacts", requireAuth(tm, h.listContacts))
mux.Handle("POST /api/v1/contacts", requireAuth(tm, h.addContact))
@@ -66,6 +83,9 @@ func NewHandler(st *store.Store, tm *auth.TokenManager, hub *realtime.Hub, log *
mux.Handle("GET /api/v1/media/{id}", requireAuth(tm, h.downloadMedia))
mux.Handle("GET /api/v1/media/{id}/thumb", requireAuth(tm, h.downloadThumb))
mux.Handle("POST /api/v1/push/subscribe", requireAuth(tm, h.subscribePush))
mux.Handle("DELETE /api/v1/push/subscribe", requireAuth(tm, h.unsubscribePush))
mux.Handle("GET /ws", authHandler)
if static != nil {