feat: add public.agents table and its set_updated_at trigger.
This commit is contained in:
parent
e48c23fab5
commit
3ffd39cc8b
@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -81,8 +82,17 @@ func (h *handler) listAgentNodes(c *gin.Context) {
|
|||||||
return
|
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)
|
registeredHosts, registeredNames := registeredNodeMetadata(h.agentStatusReader)
|
||||||
hosts := parseProxyNodeHosts(h.publicURL, registeredHosts)
|
hosts := parseProxyNodeHosts(h.publicURL, registeredHosts)
|
||||||
|
|
||||||
if len(hosts) == 0 {
|
if len(hosts) == 0 {
|
||||||
c.JSON(http.StatusOK, []vlessNode{})
|
c.JSON(http.StatusOK, []vlessNode{})
|
||||||
return
|
return
|
||||||
|
|||||||
@ -722,10 +722,26 @@ func runServer(ctx context.Context, cfg *config.Config, logger *slog.Logger) err
|
|||||||
} else {
|
} else {
|
||||||
agents := agentRegistry.Agents()
|
agents := agentRegistry.Agents()
|
||||||
logger.Info("loaded agents from store", "count", len(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)
|
// Start background cleanup task for stale agents (e.g., those that haven't heartbeated for 10 minutes)
|
||||||
go runAgentCleanup(ctx, st, logger)
|
go runAgentCleanup(ctx, st, logger)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,8 +54,19 @@ const (
|
|||||||
// AuthMiddleware is a middleware that validates JWT access tokens
|
// AuthMiddleware is a middleware that validates JWT access tokens
|
||||||
func (s *TokenService) AuthMiddleware() gin.HandlerFunc {
|
func (s *TokenService) AuthMiddleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
var token string
|
||||||
authHeader := c.GetHeader("Authorization")
|
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{
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
"error": "missing authorization header",
|
"error": "missing authorization header",
|
||||||
})
|
})
|
||||||
@ -63,16 +74,6 @@ func (s *TokenService) AuthMiddleware() gin.HandlerFunc {
|
|||||||
return
|
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)
|
claims, err := s.ValidateAccessToken(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user