114 lines
3.4 KiB
Go
114 lines
3.4 KiB
Go
package admin
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.asio.asia/nixevol/NixMsg/internal/httpx"
|
|
)
|
|
|
|
func (h *Handler) handleOverview(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
var total, selfCount, disabled, online int
|
|
err := h.db.Read.QueryRowContext(ctx, `
|
|
SELECT
|
|
COUNT(*),
|
|
COALESCE(SUM(CASE WHEN source = 'self' THEN 1 ELSE 0 END), 0),
|
|
COALESCE(SUM(CASE WHEN enabled = 0 THEN 1 ELSE 0 END), 0),
|
|
COALESCE(SUM(CASE
|
|
WHEN online_since IS NOT NULL
|
|
AND (offline_since IS NULL OR online_since > offline_since) THEN 1
|
|
ELSE 0 END), 0)
|
|
FROM endpoints`).Scan(&total, &selfCount, &disabled, &online)
|
|
if err != nil {
|
|
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
|
return
|
|
}
|
|
|
|
var groupsTotal int
|
|
if err := h.db.Read.QueryRowContext(ctx, `SELECT COUNT(*) FROM groups`).Scan(&groupsTotal); err != nil {
|
|
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
|
return
|
|
}
|
|
|
|
var pending int
|
|
if err := h.db.Read.QueryRowContext(ctx,
|
|
`SELECT COUNT(*) FROM deliveries WHERE state = 'pending'`).Scan(&pending); err != nil {
|
|
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
|
return
|
|
}
|
|
|
|
var scheduled int
|
|
if err := h.db.Read.QueryRowContext(ctx,
|
|
`SELECT COUNT(*) FROM messages WHERE state = 'scheduled'`).Scan(&scheduled); err != nil {
|
|
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
|
return
|
|
}
|
|
|
|
httpx.WriteOK(w, map[string]any{
|
|
"version": h.version,
|
|
"endpoints_total": total,
|
|
"endpoints_self": selfCount,
|
|
"endpoints_online": online,
|
|
"endpoints_disabled": disabled,
|
|
"groups_total": groupsTotal,
|
|
"messages_pending": pending,
|
|
"messages_scheduled": scheduled,
|
|
"uptime_ms": time.Since(h.startedAt).Milliseconds(),
|
|
})
|
|
}
|
|
|
|
func (h *Handler) handleSettingsGet(w http.ResponseWriter, _ *http.Request) {
|
|
cfg := h.cfg
|
|
httpx.WriteOK(w, map[string]any{
|
|
"listen": cfg.Listen,
|
|
"admin_listen": cfg.AdminListen,
|
|
"session_idle_days": cfg.SessionIdleDays,
|
|
"record_retention_days": cfg.RecordRetentionDays,
|
|
"idempotency_hours": cfg.IdempotencyHours,
|
|
"receipt_retention_days": cfg.ReceiptRetentionDays,
|
|
"sqlite_synchronous": cfg.SQLiteSynchronous,
|
|
"limits": map[string]any{
|
|
"max_body_bytes": cfg.Limits.MaxBodyBytes,
|
|
"max_meta_bytes": cfg.Limits.MaxMetaBytes,
|
|
"max_frame_bytes": cfg.Limits.MaxFrameBytes,
|
|
"max_ttl_seconds": cfg.Limits.MaxTTLSeconds,
|
|
"max_schedule_seconds": cfg.Limits.MaxScheduleSeconds,
|
|
"max_group_members": cfg.Limits.MaxGroupMembers,
|
|
"grace_seconds": cfg.Limits.GraceSeconds,
|
|
"ack_timeout_seconds": cfg.Limits.AckTimeoutSeconds,
|
|
"delivery_window": cfg.Limits.DeliveryWindow,
|
|
"receipt_window": cfg.Limits.ReceiptWindow,
|
|
"requests_per_second": cfg.Limits.RequestsPerSecond,
|
|
"max_pending_per_sender": cfg.Limits.MaxPendingPerSender,
|
|
"max_pending_per_receiver": cfg.Limits.MaxPendingPerReceiver,
|
|
},
|
|
})
|
|
}
|
|
|
|
func nullInt64API(v sql.NullInt64) any {
|
|
if !v.Valid {
|
|
return nil
|
|
}
|
|
return v.Int64
|
|
}
|
|
|
|
func parseInt64Query(s string) (int64, bool) {
|
|
if s == "" {
|
|
return 0, false
|
|
}
|
|
n, err := strconv.ParseInt(s, 10, 64)
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
return n, true
|
|
}
|
|
|
|
func isNoRows(err error) bool {
|
|
return errors.Is(err, sql.ErrNoRows)
|
|
}
|