1
0

socket.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package upstream
  2. import (
  3. "net/http"
  4. "sort"
  5. "github.com/0xJacky/Nginx-UI/internal/upstream"
  6. "github.com/0xJacky/Nginx-UI/model"
  7. "github.com/0xJacky/Nginx-UI/query"
  8. "github.com/gin-gonic/gin"
  9. "github.com/uozi-tech/cosy"
  10. "github.com/uozi-tech/cosy/logger"
  11. )
  12. // SocketInfo represents a socket with its configuration and health status
  13. type SocketInfo struct {
  14. Socket string `json:"socket"` // host:port
  15. Host string `json:"host"` // hostname/IP
  16. Port string `json:"port"` // port number
  17. Type string `json:"type"` // proxy_pass, grpc_pass, or upstream
  18. IsConsul bool `json:"is_consul"` // whether this is a consul service
  19. UpstreamName string `json:"upstream_name"` // which upstream this belongs to (if any)
  20. LastCheck string `json:"last_check"` // last time health check was performed
  21. Status *upstream.Status `json:"status"` // health check status
  22. Enabled bool `json:"enabled"` // whether health check is enabled
  23. }
  24. // GetSocketList returns all sockets with their configuration and health status
  25. func GetSocketList(c *gin.Context) {
  26. service := upstream.GetUpstreamService()
  27. // Get all target infos
  28. targets := service.GetTargetInfos()
  29. // Get availability map
  30. availabilityMap := service.GetAvailabilityMap()
  31. // Get all socket configurations from database
  32. u := query.UpstreamConfig
  33. configs, err := u.Find()
  34. if err != nil {
  35. cosy.ErrHandler(c, err)
  36. return
  37. }
  38. // Create a map for quick lookup of enabled status
  39. configMap := make(map[string]bool)
  40. for _, config := range configs {
  41. configMap[config.Socket] = config.Enabled
  42. }
  43. // Build response
  44. result := make([]SocketInfo, 0, len(targets))
  45. for _, target := range targets {
  46. socketAddr := formatSocketAddress(target.Host, target.Port)
  47. // Get enabled status from database, default to true if not found
  48. enabled := true
  49. if val, exists := configMap[socketAddr]; exists {
  50. enabled = val
  51. }
  52. // Get health status
  53. var status *upstream.Status
  54. if s, exists := availabilityMap[socketAddr]; exists {
  55. status = s
  56. }
  57. // Find which upstream this belongs to
  58. upstreamName := findUpstreamForSocket(service, target.ProxyTarget)
  59. info := SocketInfo{
  60. Socket: socketAddr,
  61. Host: target.Host,
  62. Port: target.Port,
  63. Type: target.Type,
  64. IsConsul: target.IsConsul,
  65. UpstreamName: upstreamName,
  66. LastCheck: target.LastSeen.Format("2006-01-02 15:04:05"),
  67. Status: status,
  68. Enabled: enabled,
  69. }
  70. result = append(result, info)
  71. }
  72. // Sort by socket address for stable ordering
  73. sort.Slice(result, func(i, j int) bool {
  74. return result[i].Socket < result[j].Socket
  75. })
  76. c.JSON(http.StatusOK, gin.H{
  77. "data": result,
  78. })
  79. }
  80. // UpdateSocketConfigRequest represents the request body for updating socket config
  81. type UpdateSocketConfigRequest struct {
  82. Enabled bool `json:"enabled"`
  83. }
  84. // UpdateSocketConfig updates the enabled status of a socket
  85. func UpdateSocketConfig(c *gin.Context) {
  86. socket := c.Param("socket")
  87. var req UpdateSocketConfigRequest
  88. if err := c.ShouldBindJSON(&req); err != nil {
  89. cosy.ErrHandler(c, err)
  90. return
  91. }
  92. u := query.UpstreamConfig
  93. // Check if config exists
  94. config, err := u.Where(u.Socket.Eq(socket)).First()
  95. if err != nil {
  96. // Create new config if not found
  97. config = &model.UpstreamConfig{
  98. Socket: socket,
  99. Enabled: req.Enabled,
  100. }
  101. if err := u.Create(config); err != nil {
  102. logger.Error("Failed to create socket config:", err)
  103. cosy.ErrHandler(c, err)
  104. return
  105. }
  106. // Invalidate cache after creating new config
  107. service := upstream.GetUpstreamService()
  108. service.InvalidateDisabledSocketsCache()
  109. } else {
  110. // Update existing config
  111. if _, err := u.Where(u.Socket.Eq(socket)).Update(u.Enabled, req.Enabled); err != nil {
  112. logger.Error("Failed to update socket config:", err)
  113. cosy.ErrHandler(c, err)
  114. return
  115. }
  116. }
  117. // Invalidate the disabled sockets cache to ensure changes take effect immediately
  118. service := upstream.GetUpstreamService()
  119. service.InvalidateDisabledSocketsCache()
  120. c.JSON(http.StatusOK, gin.H{
  121. "message": "Socket config updated successfully",
  122. })
  123. }
  124. // findUpstreamForSocket finds which upstream a socket belongs to
  125. func findUpstreamForSocket(service *upstream.Service, target upstream.ProxyTarget) string {
  126. socketAddr := formatSocketAddress(target.Host, target.Port)
  127. upstreams := service.GetAllUpstreamDefinitions()
  128. for name, upstream := range upstreams {
  129. for _, server := range upstream.Servers {
  130. serverAddr := formatSocketAddress(server.Host, server.Port)
  131. if serverAddr == socketAddr {
  132. return name
  133. }
  134. }
  135. }
  136. return ""
  137. }