feat: 实现管理后台 A3 注册群消息概览与 metrics 门禁

This commit is contained in:
Nixevol
2026-09-30 08:08:08 +08:00
parent 0efcfbb8b6
commit 68e790be60
13 changed files with 1591 additions and 81 deletions
+60 -41
View File
@@ -7,7 +7,9 @@ import (
"sync"
"time"
"git.asio.asia/nixevol/NixMsg/internal/app/group"
"git.asio.asia/nixevol/NixMsg/internal/auth"
"git.asio.asia/nixevol/NixMsg/internal/config"
"git.asio.asia/nixevol/NixMsg/internal/store"
)
@@ -38,19 +40,30 @@ type Deps struct {
SecureCookies bool
// KickEndpoint 踢下线钩子(只断开连接);nil 时踢线为 no-op。
KickEndpoint EndpointKickFunc
// Groups 群服务;nil 时群写操作返回 busy。列表/详情可只读库。
Groups group.Service
// Config 只读运行参数来源;零值用 config.Default()。
Config config.Config
// Version 概览里的版本号;空则 "dev"。
Version string
}
// Handler 是可挂载的管理接口(路由前缀 /api/admin/)。
type Handler struct {
db *store.DB
hash auth.HashPool
tokens auth.APITokens
locks auth.LoginLocks
log *slog.Logger
trusted []*net.IPNet
ttl time.Duration
forceSec bool
kick EndpointKickFunc
db *store.DB
hash auth.HashPool
tokens auth.APITokens
locks auth.LoginLocks
log *slog.Logger
trusted []*net.IPNet
ttl time.Duration
forceSec bool
kick EndpointKickFunc
groups group.Service
cfg config.Config
version string
startedAt time.Time
mux *http.ServeMux
@@ -70,18 +83,30 @@ func New(d Deps) *Handler {
if ttl <= 0 {
ttl = defaultSessionTTL
}
cfg := d.Config
if cfg.Listen == "" {
cfg = config.Default()
}
ver := d.Version
if ver == "" {
ver = "dev"
}
h := &Handler{
db: d.DB,
hash: d.Hash,
tokens: d.Tokens,
locks: d.Locks,
log: d.Logger,
trusted: d.TrustedProxies,
ttl: ttl,
forceSec: d.SecureCookies,
kick: d.KickEndpoint,
mux: http.NewServeMux(),
lastUsed: make(map[string]time.Time),
db: d.DB,
hash: d.Hash,
tokens: d.Tokens,
locks: d.Locks,
log: d.Logger,
trusted: d.TrustedProxies,
ttl: ttl,
forceSec: d.SecureCookies,
kick: d.KickEndpoint,
groups: d.Groups,
cfg: cfg,
version: ver,
startedAt: time.Now(),
mux: http.NewServeMux(),
lastUsed: make(map[string]time.Time),
}
h.routes()
return h
@@ -120,25 +145,19 @@ func (h *Handler) routes() {
h.mux.Handle("PUT /api/admin/endpoints/{id}/talk-password", h.auth(h.handleEndpointTalkPassword))
h.mux.Handle("POST /api/admin/endpoints/{id}/unlock", h.auth(h.handleEndpointUnlock))
// 其余管理路由:鉴权生效,业务暂 501(A3)
for _, p := range stubRoutes {
h.mux.Handle(p, h.auth(h.handleNotImplemented))
}
}
var stubRoutes = []string{
"GET /api/admin/overview",
"GET /api/admin/registration",
"PUT /api/admin/registration",
"GET /api/admin/groups",
"POST /api/admin/groups",
"GET /api/admin/groups/{id}",
"PATCH /api/admin/groups/{id}",
"DELETE /api/admin/groups/{id}",
"POST /api/admin/groups/{id}/members",
"DELETE /api/admin/groups/{id}/members/{endpointId}",
"POST /api/admin/groups/{id}/transfer",
"GET /api/admin/messages",
"GET /api/admin/messages/{seq}",
"GET /api/admin/settings",
// A3
h.mux.Handle("GET /api/admin/overview", h.auth(h.handleOverview))
h.mux.Handle("GET /api/admin/registration", h.auth(h.handleRegistrationGet))
h.mux.Handle("PUT /api/admin/registration", h.auth(h.handleRegistrationPut))
h.mux.Handle("GET /api/admin/groups", h.auth(h.handleGroupList))
h.mux.Handle("POST /api/admin/groups", h.auth(h.handleGroupCreate))
h.mux.Handle("GET /api/admin/groups/{id}", h.auth(h.handleGroupGet))
h.mux.Handle("PATCH /api/admin/groups/{id}", h.auth(h.handleGroupRename))
h.mux.Handle("DELETE /api/admin/groups/{id}", h.auth(h.handleGroupDissolve))
h.mux.Handle("POST /api/admin/groups/{id}/members", h.auth(h.handleGroupAddMembers))
h.mux.Handle("DELETE /api/admin/groups/{id}/members/{endpointId}", h.auth(h.handleGroupRemoveMember))
h.mux.Handle("POST /api/admin/groups/{id}/transfer", h.auth(h.handleGroupTransfer))
h.mux.Handle("GET /api/admin/messages", h.auth(h.handleMessageList))
h.mux.Handle("GET /api/admin/messages/{seq}", h.auth(h.handleMessageGet))
h.mux.Handle("GET /api/admin/settings", h.auth(h.handleSettingsGet))
}