feat: add public.agents table and its set_updated_at trigger.

This commit is contained in:
Haitao Pan 2026-02-05 13:10:56 +08:00
parent e48c23fab5
commit 3ffd39cc8b
3 changed files with 41 additions and 14 deletions

View File

@ -2,6 +2,7 @@ package api
import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
@ -81,8 +82,17 @@ func (h *handler) listAgentNodes(c *gin.Context) {
return
}
// Add panic recovery for this handler
defer func() {
if r := recover(); r != nil {
fmt.Printf("PANIC in listAgentNodes: %v\n", r)
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal_error", "message": fmt.Sprintf("%v", r)})
}
}()
registeredHosts, registeredNames := registeredNodeMetadata(h.agentStatusReader)
hosts := parseProxyNodeHosts(h.publicURL, registeredHosts)
if len(hosts) == 0 {
c.JSON(http.StatusOK, []vlessNode{})
return

View File

@ -722,10 +722,26 @@ func runServer(ctx context.Context, cfg *config.Config, logger *slog.Logger) err
} else {
agents := agentRegistry.Agents()
logger.Info("loaded agents from store", "count", len(agents))
for _, agent := range agents {
logger.Info("loaded agent", "id", agent.ID, "name", agent.Name, "groups", agent.Groups)
}
}
// Start background sync task to keep in-memory registry updated from DB
go func() {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
if err := agentRegistry.Load(ctx); err != nil {
logger.Warn("failed to reload agents from store", "err", err)
} else {
// logger.Debug("reloaded agents from store", "count", len(agentRegistry.Agents()))
}
}
}
}()
// Start background cleanup task for stale agents (e.g., those that haven't heartbeated for 10 minutes)
go runAgentCleanup(ctx, st, logger)
}

View File

@ -54,8 +54,19 @@ const (
// AuthMiddleware is a middleware that validates JWT access tokens
func (s *TokenService) AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
var token string
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
if authHeader != "" && strings.HasPrefix(authHeader, bearerPrefix) {
token = strings.TrimPrefix(authHeader, bearerPrefix)
} else {
// Fallback to session cookie
if cookie, err := c.Cookie("xc_session"); err == nil {
token = cookie
}
}
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "missing authorization header",
})
@ -63,16 +74,6 @@ func (s *TokenService) AuthMiddleware() gin.HandlerFunc {
return
}
if !strings.HasPrefix(authHeader, bearerPrefix) {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "invalid authorization header format",
})
c.Abort()
return
}
token := strings.TrimPrefix(authHeader, bearerPrefix)
claims, err := s.ValidateAccessToken(token)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{