sitecheck.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package sites
  2. import (
  3. "context"
  4. "net/http"
  5. "time"
  6. "github.com/0xJacky/Nginx-UI/internal/sitecheck"
  7. "github.com/0xJacky/Nginx-UI/model"
  8. "github.com/0xJacky/Nginx-UI/query"
  9. "github.com/gin-gonic/gin"
  10. "github.com/spf13/cast"
  11. "github.com/uozi-tech/cosy"
  12. "github.com/uozi-tech/cosy/logger"
  13. )
  14. // GetSiteNavigation returns all sites for navigation dashboard
  15. func GetSiteNavigation(c *gin.Context) {
  16. service := sitecheck.GetService()
  17. sites := service.GetSites()
  18. c.JSON(http.StatusOK, gin.H{
  19. "data": sites,
  20. })
  21. }
  22. // GetSiteNavigationStatus returns the status of site checking service
  23. func GetSiteNavigationStatus(c *gin.Context) {
  24. service := sitecheck.GetService()
  25. c.JSON(http.StatusOK, gin.H{
  26. "running": service.IsRunning(),
  27. })
  28. }
  29. // UpdateSiteOrder updates the custom order of sites
  30. func UpdateSiteOrder(c *gin.Context) {
  31. var req struct {
  32. OrderedIds []uint64 `json:"ordered_ids" binding:"required"`
  33. }
  34. if !cosy.BindAndValid(c, &req) {
  35. return
  36. }
  37. if err := updateSiteOrderBatchByIds(req.OrderedIds); err != nil {
  38. cosy.ErrHandler(c, err)
  39. return
  40. }
  41. c.JSON(http.StatusOK, gin.H{
  42. "message": "Order updated successfully",
  43. })
  44. }
  45. // updateSiteOrderBatchByIds updates site order in batch using IDs
  46. func updateSiteOrderBatchByIds(orderedIds []uint64) error {
  47. sc := query.SiteConfig
  48. for i, id := range orderedIds {
  49. if _, err := sc.Where(sc.ID.Eq(id)).Update(sc.CustomOrder, i); err != nil {
  50. return err
  51. }
  52. }
  53. return nil
  54. }
  55. // GetHealthCheck gets health check configuration for a site
  56. func GetHealthCheck(c *gin.Context) {
  57. id := cast.ToUint64(c.Param("id"))
  58. sc := query.SiteConfig
  59. siteConfig, err := sc.Where(sc.ID.Eq(id)).First()
  60. if err != nil {
  61. cosy.ErrHandler(c, err)
  62. return
  63. }
  64. ensureHealthCheckConfig(siteConfig)
  65. c.JSON(http.StatusOK, siteConfig)
  66. }
  67. // createDefaultHealthCheckConfig creates default health check configuration
  68. func createDefaultHealthCheckConfig() *model.HealthCheckConfig {
  69. return &model.HealthCheckConfig{
  70. Protocol: "http",
  71. Method: "GET",
  72. Path: "/",
  73. ExpectedStatus: []int{200},
  74. GRPCMethod: "Check",
  75. }
  76. }
  77. // ensureHealthCheckConfig ensures health check config is not nil
  78. func ensureHealthCheckConfig(siteConfig *model.SiteConfig) {
  79. if siteConfig.HealthCheckConfig == nil {
  80. siteConfig.HealthCheckConfig = createDefaultHealthCheckConfig()
  81. }
  82. }
  83. // UpdateHealthCheck updates health check configuration for a site
  84. func UpdateHealthCheck(c *gin.Context) {
  85. id := cast.ToUint64(c.Param("id"))
  86. var req model.SiteConfig
  87. if !cosy.BindAndValid(c, &req) {
  88. return
  89. }
  90. sc := query.SiteConfig
  91. siteConfig, err := sc.Where(sc.ID.Eq(id)).First()
  92. if err != nil {
  93. cosy.ErrHandler(c, err)
  94. return
  95. }
  96. siteConfig.HealthCheckEnabled = req.HealthCheckEnabled
  97. siteConfig.CheckInterval = req.CheckInterval
  98. siteConfig.Timeout = req.Timeout
  99. siteConfig.UserAgent = req.UserAgent
  100. siteConfig.MaxRedirects = req.MaxRedirects
  101. siteConfig.FollowRedirects = req.FollowRedirects
  102. siteConfig.CheckFavicon = req.CheckFavicon
  103. if req.HealthCheckConfig != nil {
  104. siteConfig.HealthCheckConfig = req.HealthCheckConfig
  105. }
  106. if err = query.SiteConfig.Save(siteConfig); err != nil {
  107. cosy.ErrHandler(c, err)
  108. return
  109. }
  110. c.JSON(http.StatusOK, gin.H{
  111. "message": "Health check configuration updated successfully",
  112. })
  113. }
  114. // TestHealthCheck tests a health check configuration without saving it
  115. func TestHealthCheck(c *gin.Context) {
  116. id := cast.ToUint64(c.Param("id"))
  117. var req struct {
  118. Config *model.HealthCheckConfig `json:"config" binding:"required"`
  119. }
  120. if !cosy.BindAndValid(c, &req) {
  121. return
  122. }
  123. // Get site config to determine the host for testing
  124. sc := query.SiteConfig
  125. siteConfig, err := sc.Where(sc.ID.Eq(id)).First()
  126. if err != nil {
  127. cosy.ErrHandler(c, err)
  128. return
  129. }
  130. // Create enhanced checker and test the configuration
  131. enhancedChecker := sitecheck.NewEnhancedSiteChecker()
  132. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  133. defer cancel()
  134. // Convert host to URL for testing
  135. testURL := siteConfig.Scheme + "://" + siteConfig.Host
  136. result, err := enhancedChecker.CheckSiteWithConfig(ctx, testURL, req.Config)
  137. if err != nil {
  138. logger.Errorf("Health check test failed for %s: %v", siteConfig.Host, err)
  139. c.JSON(http.StatusOK, gin.H{
  140. "success": false,
  141. "error": err.Error(),
  142. "response_time": 0,
  143. })
  144. return
  145. }
  146. success := result.Status == "online"
  147. errorMsg := ""
  148. if !success && result.Error != "" {
  149. errorMsg = result.Error
  150. }
  151. c.JSON(http.StatusOK, gin.H{
  152. "success": success,
  153. "response_time": result.ResponseTime,
  154. "status": result.Status,
  155. "status_code": result.StatusCode,
  156. "error": errorMsg,
  157. })
  158. }