environment.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package cluster
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "encoding/json"
  6. "io"
  7. "net/http"
  8. "time"
  9. "github.com/0xJacky/Nginx-UI/api"
  10. "github.com/0xJacky/Nginx-UI/internal/analytic"
  11. "github.com/0xJacky/Nginx-UI/internal/cluster"
  12. "github.com/0xJacky/Nginx-UI/model"
  13. "github.com/0xJacky/Nginx-UI/query"
  14. "github.com/0xJacky/Nginx-UI/settings"
  15. "github.com/gin-gonic/gin"
  16. "github.com/spf13/cast"
  17. "github.com/uozi-tech/cosy"
  18. "gorm.io/gorm"
  19. )
  20. func GetEnvironment(c *gin.Context) {
  21. id := cast.ToUint64(c.Param("id"))
  22. envQuery := query.Environment
  23. env, err := envQuery.FirstByID(id)
  24. if err != nil {
  25. cosy.ErrHandler(c, err)
  26. return
  27. }
  28. c.JSON(http.StatusOK, analytic.GetNode(env))
  29. }
  30. func GetEnvironmentList(c *gin.Context) {
  31. core := cosy.Core[model.Environment](c).
  32. SetFussy("name")
  33. // fix for sqlite
  34. if c.Query("enabled") != "" {
  35. core.GormScope(func(tx *gorm.DB) *gorm.DB {
  36. return tx.Where("enabled = ?", cast.ToInt(cast.ToBool(c.Query("enabled"))))
  37. })
  38. }
  39. core.SetTransformer(func(m *model.Environment) any {
  40. return analytic.GetNode(m)
  41. }).PagingList()
  42. }
  43. func GetAllEnabledEnvironment(c *gin.Context) {
  44. api.SetSSEHeaders(c)
  45. notify := c.Writer.CloseNotify()
  46. interval := 10
  47. type respEnvironment struct {
  48. *model.Environment
  49. Status bool `json:"status"`
  50. }
  51. f := func() (any, bool) {
  52. return cosy.Core[model.Environment](c).
  53. SetFussy("name").
  54. SetTransformer(func(m *model.Environment) any {
  55. resp := respEnvironment{
  56. Environment: m,
  57. Status: analytic.GetNode(m).Status,
  58. }
  59. return resp
  60. }).ListAllData()
  61. }
  62. getHash := func(data any) string {
  63. bytes, _ := json.Marshal(data)
  64. hash := sha256.New()
  65. hash.Write(bytes)
  66. hashSum := hash.Sum(nil)
  67. return hex.EncodeToString(hashSum)
  68. }
  69. dataHash := ""
  70. {
  71. data, ok := f()
  72. if !ok {
  73. return
  74. }
  75. c.Stream(func(w io.Writer) bool {
  76. c.SSEvent("message", data)
  77. dataHash = getHash(data)
  78. return false
  79. })
  80. }
  81. for {
  82. select {
  83. case <-time.After(time.Duration(interval) * time.Second):
  84. data, ok := f()
  85. if !ok {
  86. return
  87. }
  88. // if data is not changed, send heartbeat
  89. if dataHash == getHash(data) {
  90. c.Stream(func(w io.Writer) bool {
  91. c.SSEvent("heartbeat", "")
  92. return false
  93. })
  94. return
  95. }
  96. dataHash = getHash(data)
  97. c.Stream(func(w io.Writer) bool {
  98. c.SSEvent("message", data)
  99. return false
  100. })
  101. case <-time.After(30 * time.Second):
  102. c.Stream(func(w io.Writer) bool {
  103. c.SSEvent("heartbeat", "")
  104. return false
  105. })
  106. case <-notify:
  107. return
  108. }
  109. }
  110. }
  111. func AddEnvironment(c *gin.Context) {
  112. cosy.Core[model.Environment](c).SetValidRules(gin.H{
  113. "name": "required",
  114. "url": "required,url",
  115. "token": "required",
  116. "enabled": "omitempty,boolean",
  117. }).ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
  118. go analytic.RestartRetrieveNodesStatus()
  119. }).Create()
  120. }
  121. func EditEnvironment(c *gin.Context) {
  122. cosy.Core[model.Environment](c).SetValidRules(gin.H{
  123. "name": "required",
  124. "url": "required,url",
  125. "token": "required",
  126. "enabled": "omitempty,boolean",
  127. }).ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
  128. go analytic.RestartRetrieveNodesStatus()
  129. }).Modify()
  130. }
  131. func DeleteEnvironment(c *gin.Context) {
  132. cosy.Core[model.Environment](c).
  133. ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
  134. go analytic.RestartRetrieveNodesStatus()
  135. }).Destroy()
  136. }
  137. func LoadEnvironmentFromSettings(c *gin.Context) {
  138. err := settings.ReloadCluster()
  139. if err != nil {
  140. cosy.ErrHandler(c, err)
  141. return
  142. }
  143. cluster.RegisterPredefinedNodes()
  144. go analytic.RestartRetrieveNodesStatus()
  145. c.JSON(http.StatusOK, gin.H{
  146. "message": "ok",
  147. })
  148. }