ソースを参照

refactor: migrate to new cosy

Jacky 6 ヶ月 前
コミット
33a996e777
100 ファイル変更612 行追加1558 行削除
  1. 1 0
      .gitignore
  2. 1 1
      api/analytic/analytic.go
  3. 1 1
      api/analytic/nodes.go
  4. 1 1
      api/api.go
  5. 3 3
      api/certificate/acme_user.go
  6. 1 1
      api/certificate/certificate.go
  7. 1 1
      api/certificate/dns_credential.go
  8. 1 1
      api/certificate/issue.go
  9. 1 1
      api/cluster/environment.go
  10. 1 1
      api/cluster/node.go
  11. 1 1
      api/config/list.go
  12. 1 1
      api/config/rename.go
  13. 1 1
      api/nginx/nginx_log.go
  14. 1 1
      api/notification/notification.go
  15. 9 8
      api/settings/settings.go
  16. 41 0
      api/sites/category.go
  17. 1 62
      api/sites/domain.go
  18. 70 0
      api/sites/list.go
  19. 9 0
      api/sites/router.go
  20. 6 5
      api/system/install.go
  21. 2 2
      api/system/upgrade.go
  22. 1 1
      api/terminal/pty.go
  23. 1 1
      api/upstream/upstream.go
  24. 1 1
      api/user/auth.go
  25. 2 2
      api/user/otp.go
  26. 2 2
      api/user/passkey.go
  27. 2 2
      api/user/user.go
  28. 0 1
      app/src/components/StdDesign/types.d.ts
  29. 5 5
      app/src/views/certificate/ACMEUser.vue
  30. 4 4
      app/src/views/certificate/CertificateList/certColumns.tsx
  31. 3 3
      app/src/views/certificate/DNSCredential.vue
  32. 6 6
      app/src/views/environment/envColumns.tsx
  33. 2 2
      app/src/views/notification/notificationColumns.tsx
  34. 3 3
      app/src/views/site/SiteList.vue
  35. 3 3
      app/src/views/stream/StreamList.vue
  36. 5 5
      app/src/views/user/userColumns.tsx
  37. 15 5
      go.mod
  38. 137 130
      go.sum
  39. BIN
      img.png
  40. 5 2
      install.sh
  41. 1 1
      internal/analytic/analytic.go
  42. 1 1
      internal/analytic/node.go
  43. 1 1
      internal/analytic/node_record.go
  44. 1 1
      internal/analytic/node_stat.go
  45. 1 1
      internal/analytic/record.go
  46. 1 1
      internal/cache/cache.go
  47. 3 3
      internal/cert/auto_cert.go
  48. 4 4
      internal/cert/cert.go
  49. 1 1
      internal/cert/logger.go
  50. 1 1
      internal/cert/payload.go
  51. 10 8
      internal/cert/register.go
  52. 1 1
      internal/cert/sync.go
  53. 1 1
      internal/chatbot/context.go
  54. 1 1
      internal/cluster/cluster.go
  55. 2 2
      internal/config/sync.go
  56. 0 117
      internal/cosy/cosy.go
  57. 0 81
      internal/cosy/create.go
  58. 0 39
      internal/cosy/custom.go
  59. 0 113
      internal/cosy/delete.go
  60. 0 23
      internal/cosy/error.go
  61. 0 212
      internal/cosy/filter.go
  62. 0 39
      internal/cosy/hook.go
  63. 0 172
      internal/cosy/list.go
  64. 0 96
      internal/cosy/map2struct/hook.go
  65. 0 25
      internal/cosy/map2struct/map2struct.go
  66. 0 46
      internal/cosy/order.go
  67. 0 41
      internal/cosy/sort.go
  68. 0 101
      internal/cosy/update.go
  69. 1 1
      internal/cron/cron.go
  70. 1 1
      internal/helper/directory.go
  71. 1 1
      internal/helper/hash.go
  72. 17 10
      internal/kernal/boot.go
  73. 1 1
      internal/kernal/register_acme_user.go
  74. 8 7
      internal/kernal/skip_install.go
  75. 1 1
      internal/logrotate/logrotate.go
  76. 3 22
      internal/middleware/middleware.go
  77. 1 1
      internal/middleware/proxy.go
  78. 1 1
      internal/middleware/proxy_ws.go
  79. 1 1
      internal/nginx/config_args.go
  80. 3 3
      internal/passkey/webauthn.go
  81. 2 2
      internal/pty/pipeline.go
  82. 4 3
      internal/template/template.go
  83. 1 1
      internal/transport/transport.go
  84. 6 5
      internal/upgrader/upgrade.go
  85. 4 4
      internal/user/user.go
  86. 1 1
      internal/validation/validation.go
  87. 20 18
      main.go
  88. 1 1
      model/config_backup.go
  89. 3 39
      model/model.go
  90. 7 0
      model/site_category.go
  91. 3 6
      router/routers.go
  92. 82 0
      settings/app.testing.ini
  93. 1 1
      settings/auth.go
  94. 1 1
      settings/casdoor.go
  95. 36 0
      settings/cert.go
  96. 5 3
      settings/cluster.go
  97. 0 16
      settings/cluster_test.go
  98. 1 1
      settings/crypto.go
  99. 3 3
      settings/crypto_test.go
  100. 11 0
      settings/http.go

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@ tmp
 node_modules
 .pnpm-store
 app.ini
+app.testing.ini
 dist
 *.exe
 *.po~

+ 1 - 1
api/analytic/analytic.go

@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/shirou/gopsutil/v3/cpu"
 	"github.com/shirou/gopsutil/v3/host"
 	"github.com/shirou/gopsutil/v3/load"

+ 1 - 1
api/analytic/nodes.go

@@ -3,7 +3,7 @@ package analytic
 import (
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"
 	"net/http"

+ 1 - 1
api/api.go

@@ -2,7 +2,7 @@ package api
 
 import (
 	"errors"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/gin-gonic/gin"
 	"github.com/go-playground/validator/v10"

+ 3 - 3
api/certificate/acme_user.go

@@ -2,12 +2,12 @@ package certificate
 
 import (
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"net/http"
 )
 
@@ -31,7 +31,7 @@ func CreateAcmeUser(c *gin.Context) {
 		"register_on_startup": "omitempty",
 	}).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) {
 		if ctx.Model.CADir == "" {
-			ctx.Model.CADir = settings.ServerSettings.GetCADir()
+			ctx.Model.CADir = settings.CertSettings.GetCADir()
 		}
 		err := ctx.Model.Register()
 		if err != nil {
@@ -50,7 +50,7 @@ func ModifyAcmeUser(c *gin.Context) {
 		"register_on_startup": "omitempty",
 	}).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) {
 		if ctx.Model.CADir == "" {
-			ctx.Model.CADir = settings.ServerSettings.GetCADir()
+			ctx.Model.CADir = settings.CertSettings.GetCADir()
 		}
 
 		if ctx.OriginModel.Email != ctx.Model.Email ||

+ 1 - 1
api/certificate/certificate.go

@@ -3,7 +3,6 @@ package certificate
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
@@ -12,6 +11,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/go-acme/lego/v4/certcrypto"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"net/http"
 	"os"
 )

+ 1 - 1
api/certificate/dns_credential.go

@@ -3,11 +3,11 @@ package certificate
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/cert/dns"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"net/http"
 )
 

+ 1 - 1
api/certificate/issue.go

@@ -2,7 +2,7 @@ package certificate
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/cert"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/gin-gonic/gin"
 	"github.com/go-acme/lego/v4/certcrypto"

+ 1 - 1
api/cluster/environment.go

@@ -4,12 +4,12 @@ import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/cluster"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"gorm.io/gorm"
 	"net/http"
 )

+ 1 - 1
api/cluster/node.go

@@ -12,7 +12,7 @@ import (
 )
 
 func GetCurrentNode(c *gin.Context) {
-	if _, ok := c.Get("NodeSecret"); !ok {
+	if _, ok := c.Get("Secret"); !ok {
 		c.JSON(http.StatusNotAcceptable, gin.H{
 			"message": "node secret not exist",
 		})

+ 1 - 1
api/config/list.go

@@ -3,7 +3,7 @@ package config
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/config"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/gin-gonic/gin"
 	"net/http"

+ 1 - 1
api/config/rename.go

@@ -4,7 +4,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/config"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"

+ 1 - 1
api/nginx/nginx_log.go

@@ -6,7 +6,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/cache"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"

+ 1 - 1
api/notification/notification.go

@@ -2,11 +2,11 @@ package notification
 
 import (
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"net/http"
 )
 

+ 9 - 8
api/settings/settings.go

@@ -6,12 +6,13 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"net/http"
 )
 
 func GetServerName(c *gin.Context) {
 	c.JSON(http.StatusOK, gin.H{
-		"name": settings.ServerSettings.Name,
+		"name": settings.NodeSettings.Name,
 	})
 }
 
@@ -19,7 +20,7 @@ func GetSettings(c *gin.Context) {
 	settings.NginxSettings.AccessLogPath = nginx.GetAccessLogPath()
 	settings.NginxSettings.ErrorLogPath = nginx.GetErrorLogPath()
 	c.JSON(http.StatusOK, gin.H{
-		"server":    settings.ServerSettings,
+		"server":    cSettings.ServerSettings,
 		"nginx":     settings.NginxSettings,
 		"openai":    settings.OpenAISettings,
 		"logrotate": settings.LogrotateSettings,
@@ -29,7 +30,7 @@ func GetSettings(c *gin.Context) {
 
 func SaveSettings(c *gin.Context) {
 	var json struct {
-		Server    settings.Server    `json:"server"`
+		Server    cSettings.Server   `json:"server"`
 		Nginx     settings.Nginx     `json:"nginx"`
 		Openai    settings.OpenAI    `json:"openai"`
 		Logrotate settings.Logrotate `json:"logrotate"`
@@ -45,11 +46,11 @@ func SaveSettings(c *gin.Context) {
 		go cron.RestartLogrotate()
 	}
 
-	settings.ProtectedFill(&settings.ServerSettings, &json.Server)
-	settings.ProtectedFill(&settings.NginxSettings, &json.Nginx)
-	settings.ProtectedFill(&settings.OpenAISettings, &json.Openai)
-	settings.ProtectedFill(&settings.LogrotateSettings, &json.Logrotate)
-	settings.ProtectedFill(&settings.AuthSettings, &json.Auth)
+	cSettings.ProtectedFill(cSettings.ServerSettings, &json.Server)
+	cSettings.ProtectedFill(settings.NginxSettings, &json.Nginx)
+	cSettings.ProtectedFill(settings.OpenAISettings, &json.Openai)
+	cSettings.ProtectedFill(settings.LogrotateSettings, &json.Logrotate)
+	cSettings.ProtectedFill(settings.AuthSettings, &json.Auth)
 
 	err := settings.Save()
 	if err != nil {

+ 41 - 0
api/sites/category.go

@@ -0,0 +1,41 @@
+package sites
+
+import (
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
+)
+
+func GetCategory(c *gin.Context) {
+
+}
+
+func GetCategoryList(c *gin.Context) {
+	cosy.Core[model.SiteCategory](c).PagingList()
+}
+
+func AddCategory(c *gin.Context) {
+	cosy.Core[model.SiteCategory](c).
+		SetValidRules(gin.H{
+			"name":          "required",
+			"sync_node_ids": "omitempty",
+		}).
+		Create()
+}
+
+func ModifyCategory(c *gin.Context) {
+	cosy.Core[model.SiteCategory](c).
+		SetValidRules(gin.H{
+			"name":          "required",
+			"sync_node_ids": "omitempty",
+		}).
+		Modify()
+}
+
+func DeleteCategory(c *gin.Context) {
+	cosy.Core[model.SiteCategory](c).Destroy()
+}
+
+func RecoverCategory(c *gin.Context) {
+	cosy.Core[model.SiteCategory](c).Recover()
+}

+ 1 - 62
api/sites/domain.go

@@ -3,9 +3,8 @@ package sites
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
-	"github.com/0xJacky/Nginx-UI/internal/config"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
@@ -13,68 +12,8 @@ import (
 	"github.com/sashabaranov/go-openai"
 	"net/http"
 	"os"
-	"strings"
 )
 
-func GetSiteList(c *gin.Context) {
-	name := c.Query("name")
-	enabled := c.Query("enabled")
-	orderBy := c.Query("order_by")
-	sort := c.DefaultQuery("sort", "desc")
-
-	configFiles, err := os.ReadDir(nginx.GetConfPath("sites-available"))
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-
-	enabledConfig, err := os.ReadDir(nginx.GetConfPath("sites-enabled"))
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-
-	enabledConfigMap := make(map[string]bool)
-	for i := range enabledConfig {
-		enabledConfigMap[enabledConfig[i].Name()] = true
-	}
-
-	var configs []config.Config
-
-	for i := range configFiles {
-		file := configFiles[i]
-		fileInfo, _ := file.Info()
-		if !file.IsDir() {
-			// name filter
-			if name != "" && !strings.Contains(file.Name(), name) {
-				continue
-			}
-			// status filter
-			if enabled != "" {
-				if enabled == "true" && !enabledConfigMap[file.Name()] {
-					continue
-				}
-				if enabled == "false" && enabledConfigMap[file.Name()] {
-					continue
-				}
-			}
-			configs = append(configs, config.Config{
-				Name:       file.Name(),
-				ModifiedAt: fileInfo.ModTime(),
-				Size:       fileInfo.Size(),
-				IsDir:      fileInfo.IsDir(),
-				Enabled:    enabledConfigMap[file.Name()],
-			})
-		}
-	}
-
-	configs = config.Sort(orderBy, sort, configs)
-
-	c.JSON(http.StatusOK, gin.H{
-		"data": configs,
-	})
-}
-
 func GetSite(c *gin.Context) {
 	rewriteName, ok := c.Get("rewriteConfigFileName")
 	name := c.Param("name")

+ 70 - 0
api/sites/list.go

@@ -0,0 +1,70 @@
+package sites
+
+import (
+	"github.com/0xJacky/Nginx-UI/api"
+	"github.com/0xJacky/Nginx-UI/internal/config"
+	"github.com/0xJacky/Nginx-UI/internal/nginx"
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"os"
+	"strings"
+)
+
+func GetSiteList(c *gin.Context) {
+	name := c.Query("name")
+	enabled := c.Query("enabled")
+	orderBy := c.Query("order_by")
+	sort := c.DefaultQuery("sort", "desc")
+
+	configFiles, err := os.ReadDir(nginx.GetConfPath("sites-available"))
+	if err != nil {
+		api.ErrHandler(c, err)
+		return
+	}
+
+	enabledConfig, err := os.ReadDir(nginx.GetConfPath("sites-enabled"))
+	if err != nil {
+		api.ErrHandler(c, err)
+		return
+	}
+
+	enabledConfigMap := make(map[string]bool)
+	for i := range enabledConfig {
+		enabledConfigMap[enabledConfig[i].Name()] = true
+	}
+
+	var configs []config.Config
+
+	for i := range configFiles {
+		file := configFiles[i]
+		fileInfo, _ := file.Info()
+		if !file.IsDir() {
+			// name filter
+			if name != "" && !strings.Contains(file.Name(), name) {
+				continue
+			}
+			// status filter
+			if enabled != "" {
+				if enabled == "true" && !enabledConfigMap[file.Name()] {
+					continue
+				}
+				if enabled == "false" && enabledConfigMap[file.Name()] {
+					continue
+				}
+			}
+			configs = append(configs, config.Config{
+				Name:       file.Name(),
+				ModifiedAt: fileInfo.ModTime(),
+				Size:       fileInfo.Size(),
+				IsDir:      fileInfo.IsDir(),
+				Enabled:    enabledConfigMap[file.Name()],
+			})
+		}
+	}
+
+	configs = config.Sort(orderBy, sort, configs)
+
+	c.JSON(http.StatusOK, gin.H{
+		"data": configs,
+	})
+}

+ 9 - 0
api/sites/router.go

@@ -14,3 +14,12 @@ func InitRouter(r *gin.RouterGroup) {
 	r.POST("auto_cert/:name", AddDomainToAutoCert)
 	r.DELETE("auto_cert/:name", RemoveDomainFromAutoCert)
 }
+
+func InitCategoryRouter(r *gin.RouterGroup) {
+	r.GET("site_categories", GetCategoryList)
+	r.GET("site_category/:id", GetCategory)
+	r.POST("site_category", AddCategory)
+	r.PUT("site_category/:id", ModifyCategory)
+	r.DELETE("site_category/:id", DeleteCategory)
+	r.POST("site_category/:id/recover", RecoverCategory)
+}

+ 6 - 5
api/system/install.go

@@ -8,12 +8,13 @@ import (
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/google/uuid"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"golang.org/x/crypto/bcrypt"
 	"net/http"
 )
 
 func installLockStatus() bool {
-	return settings.ServerSettings.SkipInstallation || "" != settings.ServerSettings.JwtSecret
+	return settings.NodeSettings.SkipInstallation || "" != cSettings.AppSettings.JwtSecret
 }
 
 func InstallLockCheck(c *gin.Context) {
@@ -43,11 +44,11 @@ func InstallNginxUI(c *gin.Context) {
 		return
 	}
 
-	settings.ServerSettings.JwtSecret = uuid.New().String()
-	settings.ServerSettings.NodeSecret = uuid.New().String()
-	settings.ServerSettings.Email = json.Email
+	cSettings.AppSettings.JwtSecret = uuid.New().String()
+	settings.NodeSettings.Secret = uuid.New().String()
+	settings.CertSettings.Email = json.Email
 	if "" != json.Database {
-		settings.ServerSettings.Database = json.Database
+		cSettings.DataBaseSettings.Name = json.Database
 	}
 
 	err := settings.Save()

+ 2 - 2
api/system/upgrade.go

@@ -2,11 +2,11 @@ package system
 
 import (
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/upgrader"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"
+	"github.com/uozi-tech/cosy/logger"
 	"net/http"
 	"os"
 )
@@ -135,7 +135,7 @@ func PerformCoreUpgrade(c *gin.Context) {
 		Message: "Performing core upgrade",
 	})
 	// dry run
-	if control.DryRun || settings.ServerSettings.Demo {
+	if control.DryRun || settings.NodeSettings.Demo {
 		return
 	}
 

+ 1 - 1
api/terminal/pty.go

@@ -1,7 +1,7 @@
 package terminal
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/pty"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"

+ 1 - 1
api/upstream/upstream.go

@@ -2,7 +2,7 @@ package upstream
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"

+ 1 - 1
api/user/auth.go

@@ -2,7 +2,7 @@ package user
 
 import (
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/user"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"

+ 2 - 2
api/user/otp.go

@@ -21,7 +21,7 @@ import (
 func GenerateTOTP(c *gin.Context) {
 	u := api.CurrentUser(c)
 
-	issuer := fmt.Sprintf("Nginx UI %s", settings.ServerSettings.Name)
+	issuer := fmt.Sprintf("Nginx UI %s", settings.NodeSettings.Name)
 	issuer = strings.TrimSpace(issuer)
 
 	otpOpts := totp.GenerateOpts{
@@ -70,7 +70,7 @@ func EnrollTOTP(c *gin.Context) {
 		return
 	}
 
-	if settings.ServerSettings.Demo {
+	if settings.NodeSettings.Demo {
 		c.JSON(http.StatusBadRequest, gin.H{
 			"message": "This feature is disabled in demo mode",
 		})

+ 2 - 2
api/user/passkey.go

@@ -5,8 +5,6 @@ import (
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/cache"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/passkey"
 	"github.com/0xJacky/Nginx-UI/internal/user"
 	"github.com/0xJacky/Nginx-UI/model"
@@ -15,6 +13,8 @@ import (
 	"github.com/go-webauthn/webauthn/webauthn"
 	"github.com/google/uuid"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
+	"github.com/uozi-tech/cosy/logger"
 	"gorm.io/gorm"
 	"net/http"
 	"strings"

+ 2 - 2
api/user/user.go

@@ -2,12 +2,12 @@ package user
 
 import (
 	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
+	"github.com/uozi-tech/cosy"
 	"golang.org/x/crypto/bcrypt"
 	"net/http"
 )
@@ -71,7 +71,7 @@ func AddUser(c *gin.Context) {
 func EditUser(c *gin.Context) {
 	userId := cast.ToInt(c.Param("id"))
 
-	if settings.ServerSettings.Demo && userId == 1 {
+	if settings.NodeSettings.Demo && userId == 1 {
 		c.JSON(http.StatusNotAcceptable, gin.H{
 			"message": "Changing user password is forbidden in demo mode",
 		})

+ 0 - 1
app/src/components/StdDesign/types.d.ts

@@ -77,7 +77,6 @@ export interface Column extends TableColumnType {
   extra?: string | (() => string)
   pithy?: boolean
   search?: boolean | StdDesignEdit
-  sortable?: boolean
   handle?: boolean
   hiddenInTable?: boolean
   hiddenInTrash?: boolean

+ 5 - 5
app/src/views/certificate/ACMEUser.vue

@@ -12,7 +12,7 @@ const columns: Column[] = [
   {
     title: () => $gettext('Name'),
     dataIndex: 'name',
-    sortable: true,
+    sorter: true,
     pithy: true,
     edit: {
       type: input,
@@ -23,7 +23,7 @@ const columns: Column[] = [
   }, {
     title: () => $gettext('Email'),
     dataIndex: 'email',
-    sortable: true,
+    sorter: true,
     pithy: true,
     edit: {
       type: input,
@@ -34,7 +34,7 @@ const columns: Column[] = [
   }, {
     title: () => $gettext('CA Dir'),
     dataIndex: 'ca_dir',
-    sortable: true,
+    sorter: true,
     pithy: true,
     edit: {
       type: input,
@@ -66,7 +66,7 @@ const columns: Column[] = [
 
       return <Tag color="red">{$gettext('Invalid')}</Tag>
     },
-    sortable: true,
+    sorter: true,
     pithy: true,
   }, {
     title: () => $gettext('Register On Startup'),
@@ -82,7 +82,7 @@ const columns: Column[] = [
     title: () => $gettext('Updated at'),
     dataIndex: 'updated_at',
     customRender: datetime,
-    sortable: true,
+    sorter: true,
     pithy: true,
   }, {
     title: () => $gettext('Action'),

+ 4 - 4
app/src/views/certificate/CertificateList/certColumns.tsx

@@ -9,7 +9,7 @@ import { PrivateKeyTypeMask } from '@/constants'
 const columns: Column[] = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   customRender: (args: customRender) => {
     const { text, record } = args
@@ -48,13 +48,13 @@ const columns: Column[] = [{
 
     return h('div', template)
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Key Type'),
   dataIndex: 'key_type',
   customRender: mask(PrivateKeyTypeMask),
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Status'),
@@ -83,7 +83,7 @@ const columns: Column[] = [{
   title: () => $gettext('Not After'),
   dataIndex: ['certificate_info', 'not_after'],
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Action'),

+ 3 - 3
app/src/views/certificate/DNSCredential.vue

@@ -10,7 +10,7 @@ import type { Column } from '@/components/StdDesign/types'
 const columns: Column[] = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -21,13 +21,13 @@ const columns: Column[] = [{
   customRender: (args: customRender) => {
     return args.record.provider
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Updated at'),
   dataIndex: 'updated_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Action'),

+ 6 - 6
app/src/views/environment/envColumns.tsx

@@ -8,7 +8,7 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor
 const columns: Column[] = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -18,7 +18,7 @@ const columns: Column[] = [{
 {
   title: () => $gettext('URL'),
   dataIndex: 'url',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -35,7 +35,7 @@ const columns: Column[] = [{
 {
   title: () => 'NodeSecret',
   dataIndex: 'token',
-  sortable: true,
+  sorter: true,
   hiddenInTable: true,
   edit: {
     type: input,
@@ -97,7 +97,7 @@ const columns: Column[] = [{
 
     return h('div', template)
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 },
 {
@@ -117,14 +117,14 @@ const columns: Column[] = [{
   edit: {
     type: switcher,
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 },
 {
   title: () => $gettext('Updated at'),
   dataIndex: 'updated_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 },
 {

+ 2 - 2
app/src/views/notification/notificationColumns.tsx

@@ -30,7 +30,7 @@ const columns: Column[] = [{
     </Tag>
     }
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Title'),
@@ -47,7 +47,7 @@ const columns: Column[] = [{
 }, {
   title: () => $gettext('Created at'),
   dataIndex: 'created_at',
-  sortable: true,
+  sorter: true,
   customRender: datetime,
   pithy: true,
 }, {

+ 3 - 3
app/src/views/site/SiteList.vue

@@ -12,7 +12,7 @@ import type { Column, JSXElements } from '@/components/StdDesign/types'
 const columns: Column[] = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -42,13 +42,13 @@ const columns: Column[] = [{
       false: $gettext('Disabled'),
     },
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Updated at'),
   dataIndex: 'modified_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Action'),

+ 3 - 3
app/src/views/stream/StreamList.vue

@@ -12,7 +12,7 @@ import StreamDuplicate from '@/views/stream/components/StreamDuplicate.vue'
 const columns: Column[] = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -35,13 +35,13 @@ const columns: Column[] = [{
 
     return h('div', template)
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Updated at'),
   dataIndex: 'modified_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Action'),

+ 5 - 5
app/src/views/user/userColumns.tsx

@@ -8,7 +8,7 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor
 const columns: Column[] = [{
   title: () => $gettext('Username'),
   dataIndex: 'name',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: input,
@@ -17,7 +17,7 @@ const columns: Column[] = [{
 }, {
   title: () => $gettext('Password'),
   dataIndex: 'password',
-  sortable: true,
+  sorter: true,
   pithy: true,
   edit: {
     type: password,
@@ -42,19 +42,19 @@ const columns: Column[] = [{
 
     return h('div', template)
   },
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Created at'),
   dataIndex: 'created_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Updated at'),
   dataIndex: 'updated_at',
   customRender: datetime,
-  sortable: true,
+  sorter: true,
   pithy: true,
 }, {
   title: () => $gettext('Action'),

+ 15 - 5
go.mod

@@ -10,6 +10,7 @@ require (
 	github.com/creack/pty v1.1.23
 	github.com/dgraph-io/ristretto v1.0.0
 	github.com/dustin/go-humanize v1.0.1
+	github.com/elliotchance/orderedmap/v2 v2.4.0
 	github.com/fatih/color v1.17.0
 	github.com/gin-contrib/static v1.1.2
 	github.com/gin-gonic/gin v1.10.0
@@ -24,20 +25,19 @@ require (
 	github.com/jpillora/overseer v1.1.6
 	github.com/lib/pq v1.10.9
 	github.com/minio/selfupdate v0.6.0
-	github.com/mitchellh/mapstructure v1.5.0
 	github.com/pkg/errors v0.9.1
 	github.com/pquerna/otp v1.4.0
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
 	github.com/samber/lo v1.47.0
 	github.com/sashabaranov/go-openai v1.32.2
 	github.com/shirou/gopsutil/v3 v3.24.5
-	github.com/shopspring/decimal v1.4.0
 	github.com/spf13/cast v1.7.0
 	github.com/stretchr/testify v1.9.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20241013191809-e73b7dd454e8
+	github.com/uozi-tech/cosy v1.9.4
+	github.com/uozi-tech/cosy-driver-sqlite v0.2.0
 	go.uber.org/zap v1.27.0
 	golang.org/x/crypto v0.28.0
-	gopkg.in/guregu/null.v4 v4.0.0
 	gopkg.in/ini.v1 v1.67.0
 	gorm.io/driver/sqlite v1.5.6
 	gorm.io/gen v0.3.26
@@ -90,8 +90,9 @@ require (
 	github.com/aws/smithy-go v1.22.0 // indirect
 	github.com/benbjohnson/clock v1.3.5 // indirect
 	github.com/boombuler/barcode v1.0.2 // indirect
+	github.com/bsm/redislock v0.9.4 // indirect
 	github.com/bytedance/sonic v1.12.3 // indirect
-	github.com/bytedance/sonic/loader v0.2.0 // indirect
+	github.com/bytedance/sonic/loader v0.2.1 // indirect
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/civo/civogo v0.3.84 // indirect
@@ -100,6 +101,7 @@ require (
 	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/cpu/goacmedns v0.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
 	github.com/exoscale/egoscale/v3 v3.1.7 // indirect
@@ -110,6 +112,7 @@ require (
 	github.com/gabriel-vasile/mimetype v1.4.6 // indirect
 	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-co-op/gocron/v2 v2.12.1 // indirect
 	github.com/go-errors/errors v1.5.1 // indirect
 	github.com/go-jose/go-jose/v4 v4.0.4 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
@@ -144,9 +147,12 @@ require (
 	github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
 	github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
 	github.com/itchyny/timefmt-go v0.1.6 // indirect
+	github.com/jackc/pgio v1.0.0 // indirect
+	github.com/jackc/pgtype v1.14.4 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
+	github.com/jonboulle/clockwork v0.4.0 // indirect
 	github.com/jpillora/s3 v1.1.4 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
@@ -167,6 +173,7 @@ require (
 	github.com/miekg/dns v1.1.62 // indirect
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
@@ -190,6 +197,7 @@ require (
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
+	github.com/redis/go-redis/v9 v9.7.0 // indirect
 	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/sacloud/api-client-go v0.2.10 // indirect
 	github.com/sacloud/go-http v0.1.8 // indirect
@@ -201,11 +209,13 @@ require (
 	github.com/selectel/domains-go v1.1.0 // indirect
 	github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect
 	github.com/shoenig/go-m1cpu v0.1.6 // indirect
+	github.com/shopspring/decimal v1.4.0 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
 	github.com/softlayer/softlayer-go v1.1.6 // indirect
 	github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
 	github.com/sony/gobreaker v1.0.0 // indirect
+	github.com/sony/sonyflake v1.2.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/spf13/afero v1.11.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -252,6 +262,7 @@ require (
 	google.golang.org/grpc v1.67.1 // indirect
 	google.golang.org/protobuf v1.35.1 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
+	gopkg.in/guregu/null.v4 v4.0.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.12.2 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
@@ -259,7 +270,6 @@ require (
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gorm.io/datatypes v1.2.4 // indirect
 	gorm.io/driver/mysql v1.5.7 // indirect
-	gorm.io/driver/postgres v1.5.6 // indirect
 	gorm.io/hints v1.1.2 // indirect
 	k8s.io/api v0.31.1 // indirect
 	k8s.io/apimachinery v0.31.1 // indirect

+ 137 - 130
go.sum

@@ -39,8 +39,6 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY
 cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
 cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
 cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
-cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
-cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
 cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4=
 cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=
 cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E=
@@ -102,8 +100,6 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo
 cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
 cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
 cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
-cloud.google.com/go/auth v0.9.7 h1:ha65jNwOfI48YmUzNfMaUDfqt5ykuYIUnSartpU1+BA=
-cloud.google.com/go/auth v0.9.7/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM=
 cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8=
 cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
 cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
@@ -182,7 +178,6 @@ cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvj
 cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=
 cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
 cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
-cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o=
 cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
@@ -617,16 +612,12 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs
 github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0 h1:eXzkOEXbSTOa7cJ7EqeCVi/OFi/ppDrUtQuttCWy74c=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
@@ -663,6 +654,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
 github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
+github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -672,6 +665,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -689,10 +683,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.23 h1:qVHm1EZhZ4JGfB9RMHREtbcNcPDDFyCKA+0/nMk6JP8=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.23/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.28 h1:sfIgg5sLKlJQJonmnY43YHCU3mvTOyFSQgE3FNCl63U=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.28/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.32 h1:aBtZr6N7HXVpJCMybTSBuinHauehf/R0LNMB03TkrE0=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.32/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
@@ -705,58 +695,32 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
 github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aws/aws-sdk-go-v2 v1.32.0 h1:GuHp7GvMN74PXD5C97KT5D87UhIy4bQPkflQKbfkndg=
-github.com/aws/aws-sdk-go-v2 v1.32.0/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
 github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI=
 github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
-github.com/aws/aws-sdk-go-v2/config v1.27.41 h1:esG3WpmEuNJ6F4kVFLumN8nCfA5VBav1KKb3JPx83O4=
-github.com/aws/aws-sdk-go-v2/config v1.27.41/go.mod h1:haUg09ebP+ClvPjU3EB/xe0HF9PguO19PD2fdjM2X14=
-github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU=
-github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc=
 github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ=
 github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.39 h1:tmVexAhoGqJxNE2oc4/SJqL+Jz1x1iCPt5ts9XcqZCU=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.39/go.mod h1:zgOdbDI9epE608PdboJ87CYvPIejAgFevazeJW6iauQ=
 github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8=
 github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15 h1:kGjlNc2IXXcxPDcfMyCshNCjVgxUhC/vTJv7NvC9wKk=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15/go.mod h1:rk/HmqPo+dX0Uv0Q1+4w3QKFdICEGSsTYz1hRWvH8UI=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19 h1:Q/k5wCeJkSWs+62kDfOillkNIJ5NqmE3iOfm48g/W8c=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19/go.mod h1:Wns1C66VvtA2Bv/cUBuKZKQKdjo7EVMhp90aAa+8oTI=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19 h1:AYLE0lUfKvN6icFTR/p+NmD1amYKTbqHQ1Nm+jwE6BM=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19/go.mod h1:1giLakj64GjuH1NBzF/DXqly5DWHtMTaOzRZ53nFX0I=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0 h1:AdbiDUgQZmM28rDIZbiSwFxz8+3B94aOXxzs6oH+EA0=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0/go.mod h1:uV476Bd80tiDTX4X2redMtagQUg65aU/gzPojSJ4kSI=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.0 h1:vUdg9qrgYd8ShPj8FhE3qfBx+UoOH2ZJW1Te/V4Hn+I=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.0/go.mod h1:TWMPrc4+ZJRzkrDBUNOQzhVqhhUqv7DRkgoboTn4PGk=
 github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.2 h1:KACHg9TlCAph5Brs8RqVrm1SK0FVLBiDPhkZApIG5x4=
 github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.2/go.mod h1:eZZLyXEbSmrhlNXeGnZUyBUQXUwnzaJqT8tFoQGxSRA=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.45.0 h1:rwDRzOudNWFLRmpHIC6zZjGKovvgdfobPgXn/aXTdcs=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.45.0/go.mod h1:NAmFsZ4aGISCGa2nX+EGxPQGukb/z+XwriLW0i+EHKs=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.45.2 h1:P4ElvGTPph12a87YpxPDIqCvVICeYJFV32UMMS/TIPc=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.45.2/go.mod h1:zLKE53MjadFH0VYrDerAx25brxLYiSg4Vk3C+qPY4BQ=
-github.com/aws/aws-sdk-go-v2/service/sso v1.24.0 h1:71FvP6XFj53NK+YiAEGVzeiccLVeFnHOCvMig0zOHsE=
-github.com/aws/aws-sdk-go-v2/service/sso v1.24.0/go.mod h1:UVJqtKXSd9YppRKgdBIkyv7qgbSGv5DchM3yX0BN2mU=
 github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk=
 github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0 h1:Uco4o19bi3AmBapImNzuMk+rfzlui52BDyVK1UfJeRA=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0/go.mod h1:+HLFhCpnG08hBee8bUdfd1mBK+rFKPt4O5igR9lXDfk=
 github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o=
 github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI=
-github.com/aws/aws-sdk-go-v2/service/sts v1.32.0 h1:GiQUjZM2KUZX68o/LpZ1xqxYMuvoxpRrOwYARYog3vc=
-github.com/aws/aws-sdk-go-v2/service/sts v1.32.0/go.mod h1:dKnu7M4MAS2SDlng1ytxd03H+y0LoUfEQ5E2VaaSw/4=
 github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo=
 github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo=
 github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
@@ -774,19 +738,21 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW
 github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
 github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
+github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
+github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
+github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
+github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw=
+github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk=
 github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU=
 github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
-github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
-github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
+github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
 github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
 github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg=
 github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc=
-github.com/casdoor/casdoor-go-sdk v0.52.0 h1:UKcZfczO3U5H7md6bTtI6zIJzeorBrbg/WE8Q4qsczE=
-github.com/casdoor/casdoor-go-sdk v0.52.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
-github.com/casdoor/casdoor-go-sdk v1.1.0 h1:QW1pMoGG18X+GrcMolKKaTXCLDOpoYCu2kbfUZZQ+5A=
-github.com/casdoor/casdoor-go-sdk v1.1.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
 github.com/casdoor/casdoor-go-sdk v1.2.0 h1:DHLO8joZwgrAgdhhEZCPdrtLHdV89cXAa9UKxT7kwXg=
 github.com/casdoor/casdoor-go-sdk v1.2.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -794,7 +760,6 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -805,13 +770,9 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/civo/civogo v0.3.83 h1:GPLbSA4jJqCXCY291QO0jtr/k7jhkL+MgBT5bsgfPgc=
-github.com/civo/civogo v0.3.83/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM=
 github.com/civo/civogo v0.3.84 h1:jf5IT7VJFPaReO6g8B0zqKhsYCIizaGo4PjDLY7Sl6Y=
 github.com/civo/civogo v0.3.84/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/cloudflare-go v0.106.0 h1:q41gC5Wc1nfi0D1ZhSHokWcd9mGMbqC7RE7qiP+qE00=
-github.com/cloudflare/cloudflare-go v0.106.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM=
 github.com/cloudflare/cloudflare-go v0.107.0 h1:cMDIw2tzt6TXCJyMFVyP+BPOVkIfMvcKjhMNSNvuEPc=
 github.com/cloudflare/cloudflare-go v0.107.0/go.mod h1:5cYGzVBqNTLxMYSLdVjuSs5LJL517wJDSvMPWUrzHzc=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
@@ -831,16 +792,19 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpu/goacmedns v0.1.1 h1:DM3H2NiN2oam7QljgGY5ygy4yDXhK5Z4JUnqaugs2C4=
 github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobeGqugQ=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
 github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
@@ -853,6 +817,8 @@ github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88Nh
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
@@ -862,6 +828,8 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/elliotchance/orderedmap/v2 v2.4.0 h1:6tUmMwD9F998FNpwFxA5E6NQvSpk2PVw7RKsVq3+2Cw=
+github.com/elliotchance/orderedmap/v2 v2.4.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -901,8 +869,6 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
 github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
 github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
-github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
 github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
 github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -918,6 +884,8 @@ github.com/go-acme/lego/v4 v4.19.2/go.mod h1:wtDe3dDkmV4/oI2nydpNXSJpvV10J9RCyZ6
 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
 github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
 github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
+github.com/go-co-op/gocron/v2 v2.12.1 h1:dCIIBFbzhWKdgXeEifBjHPzgQ1hoWhjS4289Hjjy1uw=
+github.com/go-co-op/gocron/v2 v2.12.1/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
 github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
@@ -984,6 +952,7 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
 github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
 github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -1193,10 +1162,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
 github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.116 h1:2xdw38EHrdkciWjRdwd75p6a+cXe4PxWSgHMNYMbQnI=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.116/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.117 h1:TUiy5+4+Q7AWNfvKjQQL6lXOylnp7HL47JyYJ+HgN+I=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.117/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
 github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.118 h1:YHcixaT7Le4PxuxN07KQ5j9nPeH4ZdyXtMTSgA+Whh8=
 github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.118/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
@@ -1210,14 +1175,62 @@ github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768
 github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
 github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
 github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
+github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
-github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
-github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
-github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
-github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
+github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=
+github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
+github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
+github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
+github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
+github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
 github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
 github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
@@ -1230,6 +1243,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
 github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
+github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/jpillora/overseer v1.1.6 h1:3ygYfNcR3FfOr22miu3vR1iQcXKMHbmULBh98rbkIyo=
 github.com/jpillora/overseer v1.1.6/go.mod h1:aPXQtxuVb9PVWRWTXpo+LdnC/YXQ0IBLNXqKMJmgk88=
@@ -1252,6 +1267,8 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
 github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
 github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
+github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -1265,6 +1282,7 @@ github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgSh
 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -1275,6 +1293,7 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -1286,6 +1305,10 @@ github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
 github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/linode/linodego v1.41.0 h1:GcP7JIBr9iLRJ9FwAtb9/WCT1DuPJS/xUApapfdjtiY=
@@ -1307,6 +1330,7 @@ github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -1316,6 +1340,8 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
@@ -1423,10 +1449,6 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
 github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
-github.com/oracle/oci-go-sdk/v65 v65.75.1 h1:c7U7WQWeWZdPpzbsxf8dNRd4jXkyTNCNKaCAndvjTqw=
-github.com/oracle/oci-go-sdk/v65 v65.75.1/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
-github.com/oracle/oci-go-sdk/v65 v65.75.2 h1:Qw3Eotrq7SJ5LquOc//Iq6xzcBJSi8AD3cXps9IBN7g=
-github.com/oracle/oci-go-sdk/v65 v65.75.2/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
 github.com/oracle/oci-go-sdk/v65 v65.76.0 h1:mecdD9at/CMaQNEkcC5aMUR9aBF3brdiEyVkDRu/qVc=
 github.com/oracle/oci-go-sdk/v65 v65.76.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
 github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI=
@@ -1493,6 +1515,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
+github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
@@ -1504,6 +1528,9 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
@@ -1525,12 +1552,9 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
 github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
 github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
-github.com/sashabaranov/go-openai v1.31.0 h1:rGe77x7zUeCjtS2IS7NCY6Tp4bQviXNMhkQM6hz/UC4=
-github.com/sashabaranov/go-openai v1.31.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
-github.com/sashabaranov/go-openai v1.32.1 h1:JmdOa6d+cQwvGpBJigQf+dq40Qc20b+1HcXRGVOmqFw=
-github.com/sashabaranov/go-openai v1.32.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
 github.com/sashabaranov/go-openai v1.32.2 h1:8z9PfYaLPbRzmJIYpwcWu6z3XU8F+RwVMF1QRSeSF2M=
 github.com/sashabaranov/go-openai v1.32.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30 h1:yoKAVkEVwAqbGbR8n87rHQ1dulL25rKloGadb3vm770=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30/go.mod h1:sH0u6fq6x4R5M7WxkoQFY/o7UaiItec0o1LinLCJNq8=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -1544,10 +1568,13 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt
 github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
 github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
 github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
 github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -1568,6 +1595,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ=
 github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/sony/sonyflake v1.2.0 h1:Pfr3A+ejSg+0SPqpoAmQgEtNDAhc2G1SUYk205qVMLQ=
+github.com/sony/sonyflake v1.2.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
 github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -1598,6 +1627,7 @@ github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
 github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
@@ -1621,16 +1651,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1015 h1:O60uxxfWztVPVUBQjlJaop2Dw/J7CXGK9fSErMdWw+Y=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1015/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1021 h1:PziIST/T1MUZHQwCKpF+CX9FmBeTd3J6EJNbhtB31xI=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1021/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026 h1:6iBtl1CunsfWcT6IyCuRdgefJ/Zmsp5MTDujnolyuQs=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1015 h1:D+umrlpUPSDOiSLGIgPECIJ8Rrary9m7aFYnznbE/lM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1015/go.mod h1:QpUpIeygPrCIBKYX2gWvRFo7fdGHs3faTNFlmePVo3g=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1021 h1:dijBHnKKmOoE6lDKGwmT4mPtmC/JVX8TrJkcyH5ioDU=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1021/go.mod h1:zAlqm80JiBwcsJXEczgRtCvJxoT2HC3ZndyvKjP/uis=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026 h1:W6wPKS41uNKs7RBcJP5iB0HrcglXNSFUmnQaBEorVpg=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026/go.mod h1:aqLJU0aRU1k7l+TPyYCao+KQHrFEF6lNQqK04FIiLJw=
 github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
@@ -1653,14 +1675,18 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK
 github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/ultradns/ultradns-go-sdk v1.7.0-20240913052650-970ca9a h1:R6IR+Vj/RnGZLnX8PpPQsbbQthctO7Ah2q4tj5eoe2o=
-github.com/ultradns/ultradns-go-sdk v1.7.0-20240913052650-970ca9a/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
+github.com/uozi-tech/cosy v1.9.4 h1:oG5TbrS8XUpZnQ++9gxI5if0++uJ7h9nMPZPNeDgly0=
+github.com/uozi-tech/cosy v1.9.4/go.mod h1:aQI/OU3EVF125K5ECgSg3+CTfG4cp5XOkr++DEP/Fas=
+github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
+github.com/uozi-tech/cosy-driver-mysql v0.2.2/go.mod h1:EZnRIbSj1V5U0gEeTobrXai/d1SV11lkl4zP9NFEmyE=
+github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CGXLmk/zD+aS51Z2o=
+github.com/uozi-tech/cosy-driver-postgres v0.2.1/go.mod h1:eAy1A89yHbAEfjkhNAifaJQk172NqrNoRyRtFcZc9Go=
+github.com/uozi-tech/cosy-driver-sqlite v0.2.0 h1:eTpIMyGoFUK4JcaiKfJHD5AyiM6vtCwN98c7Bz5n25o=
+github.com/uozi-tech/cosy-driver-sqlite v0.2.0/go.mod h1:87a6mzn5IuEtIR4z7U4Ey8eKLGfNEOSkv7kPQlbNQgM=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
-github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
-github.com/vultr/govultr/v3 v3.9.1/go.mod h1:Rd8ebpXm7jxH3MDmhnEs+zrlYW212ouhx+HeUMfHm2o=
 github.com/vultr/govultr/v3 v3.10.0 h1:NjtFMcccmP2+5EXb5dEamwwrdeJjzzc8iAsPWOuAyao=
 github.com/vultr/govultr/v3 v3.10.0/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w=
 github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@@ -1672,16 +1698,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/yandex-cloud/go-genproto v0.0.0-20241004153110-80386e3567fa h1:OEaAUuoBdU7Opsk/JP4KlNe8YCphmMr4ibyYIOAzAKE=
-github.com/yandex-cloud/go-genproto v0.0.0-20241004153110-80386e3567fa/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
-github.com/yandex-cloud/go-genproto v0.0.0-20241014130938-6bcc214f8c09 h1:yPngbVL7P9+BAA/F4ekNHW+Fxw+XhztG809lhlU7Yvk=
-github.com/yandex-cloud/go-genproto v0.0.0-20241014130938-6bcc214f8c09/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
 github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be h1:jGNL9PedKrHWl1WCRdlBEFo7nDl589LKvkulZRf7ZTA=
 github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
-github.com/yandex-cloud/go-sdk v0.0.0-20240919120105-e63f9f4339a3 h1:t4T2EYu9LCNGYYjJA8x/ZIn8PHzJIxghjEGa9+Cx4xg=
-github.com/yandex-cloud/go-sdk v0.0.0-20240919120105-e63f9f4339a3/go.mod h1:RI42kDbwc4lOD8MtWmJDji5N/1P4AEToQQAprJby6XU=
-github.com/yandex-cloud/go-sdk v0.0.0-20241007112728-a06ce15e89c7 h1:pnIBO/B6vz9+JnHXGdxdAJ5OJePKEPccYJiFvKbTr1Y=
-github.com/yandex-cloud/go-sdk v0.0.0-20241007112728-a06ce15e89c7/go.mod h1:OISl+xMxmCNom9wbLTwfOWvlS9uu+PpdjKhXKYsXSgE=
 github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660 h1:/XDcP3XiGxwW6GGYzjHtQ82ZEEdpCuDQlmmsmx6Zyuc=
 github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660/go.mod h1:7Ru6CfLQ1pfa5WcWdzdr8UY7xRsvVTykxBh5dzjx+Ic=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
@@ -1696,6 +1714,7 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
 github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
 github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
 go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
@@ -1715,26 +1734,21 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
-go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
-go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
 go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
 go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
-go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
-go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
 go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
 go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
-go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
-go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
 go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
 go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -1743,13 +1757,18 @@ go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0=
 go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -1759,6 +1778,7 @@ golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -1767,8 +1787,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -1782,6 +1805,7 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
 golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
@@ -1800,8 +1824,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
-golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw=
-golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
@@ -1866,6 +1888,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -1983,6 +2006,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1991,6 +2015,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2148,16 +2173,20 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -2166,6 +2195,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -2208,6 +2238,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
 golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2282,10 +2314,6 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
 google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
 google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
 google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
-google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs=
-google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28=
-google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU=
-google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8=
 google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0=
 google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -2427,22 +2455,10 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl
 google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-google.golang.org/genproto v0.0.0-20240930140551-af27646dc61f h1:mCJ6SGikSxVlt9scCayUl2dMq0msUgmBArqRY6umieI=
-google.golang.org/genproto v0.0.0-20240930140551-af27646dc61f/go.mod h1:xtVODtPkMQRUZ4kqOTgp6JrXQrPevvfCSdk4mJtHUbM=
-google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk=
-google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms=
 google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE=
 google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE=
-google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA=
-google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE=
-google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg=
-google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M=
 google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
 google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -2507,8 +2523,6 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
 google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@@ -2525,6 +2539,7 @@ gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
 gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
 gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
 gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -2532,8 +2547,6 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ns1/ns1-go.v2 v2.12.1 h1:GiiZPB8JusUF/ruyUDzddd70b3HZGa5A3njtKUe84jA=
-gopkg.in/ns1/ns1-go.v2 v2.12.1/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
 gopkg.in/ns1/ns1-go.v2 v2.12.2 h1:SPM5BTTMJ1zVBhMMiiPFdF7l6Y3fq5o7bKM7jDqsUfM=
 gopkg.in/ns1/ns1-go.v2 v2.12.2/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
@@ -2554,16 +2567,12 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/datatypes v1.2.2 h1:sdn7ZmG4l7JWtMDUb3L98f2Ym7CO5F8mZLlrQJMfF9g=
-gorm.io/datatypes v1.2.2/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
-gorm.io/datatypes v1.2.3 h1:95ucr9ip9dZMPhB3Tc9zbcoAi62hxYAgHicu7SLjK4g=
-gorm.io/datatypes v1.2.3/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
 gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4=
 gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
 gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
 gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
-gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU=
-gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
+gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
+gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
 gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
 gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
 gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
@@ -2637,8 +2646,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
-sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=

BIN
img.png


+ 5 - 2
install.sh

@@ -290,9 +290,12 @@ install_config() {
     if [[ ! -f "$DataPath/app.ini" ]]; then
 cat > "$DataPath/app.ini" << EOF
 [server]
+HOST = 127.0.0.1
+PORT = 9000
 RunMode = release
-HttpPort = 9000
-HTTPChallengePort = 9180
+
+[cert]
+HTTPChallengePort    = 9180
 EOF
         echo "info: The default configuration file was installed to '$DataPath/app.ini' successfully!"
     fi

+ 1 - 1
internal/analytic/analytic.go

@@ -1,7 +1,7 @@
 package analytic
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/shirou/gopsutil/v3/net"
 	"time"
 )

+ 1 - 1
internal/analytic/node.go

@@ -2,7 +2,7 @@ package analytic
 
 import (
 	"encoding/json"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/transport"
 	"github.com/0xJacky/Nginx-UI/internal/upgrader"
 	"github.com/0xJacky/Nginx-UI/model"

+ 1 - 1
internal/analytic/node_record.go

@@ -3,7 +3,7 @@ package analytic
 import (
 	"context"
 	"encoding/json"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gorilla/websocket"

+ 1 - 1
internal/analytic/node_stat.go

@@ -1,7 +1,7 @@
 package analytic
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/shirou/gopsutil/v3/cpu"
 	"github.com/shirou/gopsutil/v3/load"
 	"github.com/shirou/gopsutil/v3/net"

+ 1 - 1
internal/analytic/record.go

@@ -1,7 +1,7 @@
 package analytic
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/shirou/gopsutil/v3/cpu"
 	"github.com/shirou/gopsutil/v3/disk"
 	"github.com/shirou/gopsutil/v3/net"

+ 1 - 1
internal/cache/cache.go

@@ -1,7 +1,7 @@
 package cache
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/dgraph-io/ristretto"
 	"time"
 )

+ 3 - 3
internal/cert/auto_cert.go

@@ -1,11 +1,11 @@
 package cert
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
 	"runtime"
 	"strings"
 	"time"
@@ -60,8 +60,8 @@ func autoCert(certModel *model.Cert) {
 		notification.Error("Renew Certificate Error", strings.Join(certModel.Domains, ", "))
 		return
 	}
-	if int(time.Now().Sub(certInfo.NotBefore).Hours()/24) < settings.ServerSettings.GetCertRenewalInterval() {
-		// not after settings.ServerSettings.CertRenewalInterval, ignore
+	if int(time.Now().Sub(certInfo.NotBefore).Hours()/24) < settings.CertSettings.GetCertRenewalInterval() {
+		// not after settings.ServerSettings.RenewalInterval, ignore
 		return
 	}
 

+ 4 - 4
internal/cert/cert.go

@@ -2,7 +2,6 @@ package cert
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/cert/dns"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/transport"
 	"github.com/0xJacky/Nginx-UI/query"
@@ -13,6 +12,7 @@ import (
 	legolog "github.com/go-acme/lego/v4/log"
 	dnsproviders "github.com/go-acme/lego/v4/providers/dns"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
 	"log"
 	"os"
 	"time"
@@ -87,7 +87,7 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error)
 		l.Println("[INFO] [Nginx UI] Setting HTTP01 challenge provider")
 		err = client.Challenge.SetHTTP01Provider(
 			http01.NewProviderServer("",
-				settings.ServerSettings.HTTPChallengePort,
+				settings.CertSettings.HTTPChallengePort,
 			),
 		)
 	case DNS01:
@@ -125,9 +125,9 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error)
 			}
 			challengeOptions := make([]dns01.ChallengeOption, 0)
 
-			if len(settings.ServerSettings.RecursiveNameservers) > 0 {
+			if len(settings.CertSettings.RecursiveNameservers) > 0 {
 				challengeOptions = append(challengeOptions,
-					dns01.AddRecursiveNameservers(settings.ServerSettings.RecursiveNameservers),
+					dns01.AddRecursiveNameservers(settings.CertSettings.RecursiveNameservers),
 				)
 			}
 

+ 1 - 1
internal/cert/logger.go

@@ -2,7 +2,7 @@ package cert
 
 import (
 	"fmt"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"strings"
 	"time"

+ 1 - 1
internal/cert/payload.go

@@ -2,7 +2,7 @@ package cert
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"

+ 10 - 8
internal/cert/register.go

@@ -1,23 +1,25 @@
 package cert
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
 	"gorm.io/gorm"
 )
 
 // InitRegister init the default user for acme
 func InitRegister() {
-	if settings.ServerSettings.Email == "" {
+	email := settings.CertSettings.Email
+	if settings.CertSettings.Email == "" {
 		return
 	}
+	caDir := settings.CertSettings.GetCADir()
 	u := query.AcmeUser
 
-	_, err := u.Where(u.Email.Eq(settings.ServerSettings.Email),
-		u.CADir.Eq(settings.ServerSettings.GetCADir())).First()
+	_, err := u.Where(u.Email.Eq(email),
+		u.CADir.Eq(caDir)).First()
 
 	if err == nil {
 		return
@@ -31,8 +33,8 @@ func InitRegister() {
 	// Create a new user
 	user := &model.AcmeUser{
 		Name:  "System Initial User",
-		Email: settings.ServerSettings.Email,
-		CADir: settings.ServerSettings.GetCADir(),
+		Email: email,
+		CADir: caDir,
 	}
 
 	err = user.Register()
@@ -52,8 +54,8 @@ func InitRegister() {
 
 func GetDefaultACMEUser() (user *model.AcmeUser, err error) {
 	u := query.AcmeUser
-	user, err = u.Where(u.Email.Eq(settings.ServerSettings.Email),
-		u.CADir.Eq(settings.ServerSettings.GetCADir())).First()
+	user, err = u.Where(u.Email.Eq(settings.CertSettings.Email),
+		u.CADir.Eq(settings.CertSettings.GetCADir())).First()
 
 	if err != nil {
 		err = errors.Wrap(err, "get default user error")

+ 1 - 1
internal/cert/sync.go

@@ -5,7 +5,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/internal/transport"

+ 1 - 1
internal/chatbot/context.go

@@ -2,7 +2,7 @@ package chatbot
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/sashabaranov/go-openai"
 	"os"

+ 1 - 1
internal/cluster/cluster.go

@@ -1,7 +1,7 @@
 package cluster
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"

+ 2 - 2
internal/config/sync.go

@@ -6,7 +6,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/internal/transport"
@@ -14,6 +13,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy/logger"
 	"io"
 	"net/http"
 	"os"
@@ -205,7 +205,7 @@ func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
 
 	client := http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.HTTPSettings.InsecureSkipVerify},
 		},
 	}
 

+ 0 - 117
internal/cosy/cosy.go

@@ -1,117 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/gin-gonic/gin"
-	"github.com/go-playground/validator/v10"
-	"gorm.io/gorm"
-)
-
-var validate *validator.Validate
-
-func init() {
-	validate = validator.New()
-}
-
-type Ctx[T any] struct {
-	ctx                      *gin.Context
-	rules                    gin.H
-	Payload                  map[string]interface{}
-	Model                    T
-	OriginModel              T
-	table                    string
-	tableArgs                []interface{}
-	abort                    bool
-	nextHandler              *gin.HandlerFunc
-	skipAssociationsOnCreate bool
-	beforeDecodeHookFunc     []func(ctx *Ctx[T])
-	beforeExecuteHookFunc    []func(ctx *Ctx[T])
-	executedHookFunc         []func(ctx *Ctx[T])
-	gormScopes               []func(tx *gorm.DB) *gorm.DB
-	preloads                 []string
-	scan                     func(tx *gorm.DB) any
-	transformer              func(*T) any
-	permanentlyDelete        bool
-	SelectedFields           []string
-	itemKey                  string
-}
-
-func Core[T any](c *gin.Context) *Ctx[T] {
-	return &Ctx[T]{
-		ctx:                      c,
-		gormScopes:               make([]func(tx *gorm.DB) *gorm.DB, 0),
-		beforeExecuteHookFunc:    make([]func(ctx *Ctx[T]), 0),
-		beforeDecodeHookFunc:     make([]func(ctx *Ctx[T]), 0),
-		itemKey:                  "`id`",
-		skipAssociationsOnCreate: true,
-	}
-}
-
-func (c *Ctx[T]) SetTable(table string, args ...interface{}) *Ctx[T] {
-	c.table = table
-	c.tableArgs = args
-	return c
-}
-
-func (c *Ctx[T]) SetItemKey(key string) *Ctx[T] {
-	c.itemKey = key
-	return c
-}
-
-func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] {
-	c.rules = rules
-
-	return c
-}
-
-func (c *Ctx[T]) SetPreloads(args ...string) *Ctx[T] {
-	c.preloads = append(c.preloads, args...)
-	return c
-}
-
-func (c *Ctx[T]) validate() (errs gin.H) {
-	c.Payload = make(gin.H)
-
-	_ = c.ctx.ShouldBindJSON(&c.Payload)
-
-	errs = validate.ValidateMap(c.Payload, c.rules)
-
-	if len(errs) > 0 {
-		logger.Debug(errs)
-		for k := range errs {
-			errs[k] = c.rules[k]
-		}
-		return
-	}
-	// Make sure that the key in c.Payload is also the key of rules
-	validated := make(map[string]interface{})
-
-	for k, v := range c.Payload {
-		if _, ok := c.rules[k]; ok {
-			validated[k] = v
-		}
-	}
-
-	c.Payload = validated
-
-	return
-}
-
-func (c *Ctx[T]) SetScan(scan func(tx *gorm.DB) any) *Ctx[T] {
-	c.scan = scan
-	return c
-}
-
-func (c *Ctx[T]) SetTransformer(t func(m *T) any) *Ctx[T] {
-	c.transformer = t
-	return c
-}
-
-func (c *Ctx[T]) AbortWithError(err error) {
-	c.abort = true
-	errHandler(c.ctx, err)
-}
-
-func (c *Ctx[T]) Abort() {
-	c.abort = true
-}

+ 0 - 81
internal/cosy/create.go

@@ -1,81 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/cosy/map2struct"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/gin-gonic/gin"
-	"gorm.io/gorm/clause"
-	"net/http"
-)
-
-func (c *Ctx[T]) Create() {
-
-	errs := c.validate()
-
-	if len(errs) > 0 {
-		c.ctx.JSON(http.StatusNotAcceptable, gin.H{
-			"message": "Requested with wrong parameters",
-			"errors":  errs,
-		})
-		return
-	}
-
-	db := model.UseDB()
-
-	c.beforeDecodeHook()
-
-	if c.abort {
-		return
-	}
-
-	err := map2struct.WeakDecode(c.Payload, &c.Model)
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	c.beforeExecuteHook()
-
-	if c.abort {
-		return
-	}
-
-	if c.skipAssociationsOnCreate {
-		err = db.Omit(clause.Associations).Create(&c.Model).Error
-	} else {
-		err = db.Create(&c.Model).Error
-	}
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	if len(c.executedHookFunc) > 0 {
-		for _, v := range c.executedHookFunc {
-			v(c)
-
-			if c.abort {
-				return
-			}
-		}
-	}
-
-	tx := db.Preload(clause.Associations)
-	for _, v := range c.preloads {
-		tx = tx.Preload(v)
-	}
-	tx.Table(c.table, c.tableArgs...).First(&c.Model)
-
-	if c.nextHandler != nil {
-		(*c.nextHandler)(c.ctx)
-	} else {
-		c.ctx.JSON(http.StatusOK, c.Model)
-	}
-}
-
-func (c *Ctx[T]) WithAssociations() *Ctx[T] {
-	c.skipAssociationsOnCreate = false
-	return c
-}

+ 0 - 39
internal/cosy/custom.go

@@ -1,39 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/cosy/map2struct"
-	"github.com/gin-gonic/gin"
-	"net/http"
-)
-
-func (c *Ctx[T]) Custom(fx func(ctx *Ctx[T])) {
-	if c.abort {
-		return
-	}
-	errs := c.validate()
-
-	if len(errs) > 0 {
-		c.ctx.JSON(http.StatusNotAcceptable, gin.H{
-			"message": "Requested with wrong parameters",
-			"errors":  errs,
-		})
-		return
-	}
-
-	c.beforeDecodeHook()
-
-	for k := range c.Payload {
-		c.SelectedFields = append(c.SelectedFields, k)
-	}
-
-	err := map2struct.WeakDecode(c.Payload, &c.Model)
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	c.beforeExecuteHook()
-
-	fx(c)
-}

+ 0 - 113
internal/cosy/delete.go

@@ -1,113 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/spf13/cast"
-	"gorm.io/gorm"
-	"net/http"
-)
-
-func (c *Ctx[T]) PermanentlyDelete() {
-	c.permanentlyDelete = true
-	c.Destroy()
-}
-
-func (c *Ctx[T]) Destroy() {
-	if c.abort {
-		return
-	}
-	id := c.ctx.Param("id")
-
-	c.beforeExecuteHook()
-
-	db := model.UseDB()
-
-	result := db
-
-	if cast.ToBool(c.ctx.Query("permanent")) || c.permanentlyDelete {
-		result = result.Unscoped()
-	}
-
-	if len(c.gormScopes) > 0 {
-		result = result.Scopes(c.gormScopes...)
-	}
-
-	var err error
-	session := result.Session(&gorm.Session{})
-	if c.table != "" {
-		err = session.Table(c.table, c.tableArgs...).Take(c.OriginModel, id).Error
-	} else {
-		err = session.First(&c.OriginModel, id).Error
-	}
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	err = result.Delete(&c.OriginModel).Error
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	if len(c.executedHookFunc) > 0 {
-		for _, v := range c.executedHookFunc {
-			v(c)
-
-			if c.abort {
-				return
-			}
-		}
-	}
-
-	c.ctx.JSON(http.StatusNoContent, nil)
-}
-
-func (c *Ctx[T]) Recover() {
-	if c.abort {
-		return
-	}
-	id := c.ctx.Param("id")
-
-	c.beforeExecuteHook()
-
-	db := model.UseDB()
-	var dbModel T
-
-	result := db.Unscoped()
-	if len(c.gormScopes) > 0 {
-		result = result.Scopes(c.gormScopes...)
-	}
-
-	var err error
-	session := result.Session(&gorm.Session{})
-	if c.table != "" {
-		err = session.Table(c.table).Take(&dbModel, id).Error
-	} else {
-		err = session.First(&dbModel, id).Error
-	}
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	err = result.Model(&dbModel).Update("deleted_at", nil).Error
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	if len(c.executedHookFunc) > 0 {
-		for _, v := range c.executedHookFunc {
-			v(c)
-
-			if c.abort {
-				return
-			}
-		}
-	}
-
-	c.ctx.JSON(http.StatusNoContent, nil)
-}

+ 0 - 23
internal/cosy/error.go

@@ -1,23 +0,0 @@
-package cosy
-
-import (
-	"errors"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/gin-gonic/gin"
-	"go.uber.org/zap"
-	"gorm.io/gorm"
-	"net/http"
-)
-
-func errHandler(c *gin.Context, err error) {
-	logger.GetLogger().WithOptions(zap.AddCallerSkip(1)).Errorln(err)
-	if errors.Is(err, gorm.ErrRecordNotFound) {
-		c.JSON(http.StatusNotFound, gin.H{
-			"message": err.Error(),
-		})
-		return
-	}
-	c.JSON(http.StatusInternalServerError, gin.H{
-		"message": err.Error(),
-	})
-}

+ 0 - 212
internal/cosy/filter.go

@@ -1,212 +0,0 @@
-package cosy
-
-import (
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/gin-gonic/gin"
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-	"strings"
-)
-
-func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToFussySearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToFussyKeysSearch(c.ctx, tx, value, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToEqualSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToInSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToOrFussySearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToOrEqualSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return QueryToOrInSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func QueryToInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		queryArray := c.QueryArray(v + "[]")
-		if len(queryArray) == 0 {
-			queryArray = c.QueryArray(v)
-		}
-		if len(queryArray) == 1 && queryArray[0] == "" {
-			continue
-		}
-		if len(queryArray) >= 1 {
-			var builder strings.Builder
-			stmt := db.Statement
-
-			stmt.QuoteTo(&builder, clause.Column{Table: stmt.Table, Name: v})
-			builder.WriteString(" IN ?")
-
-			db = db.Where(builder.String(), queryArray)
-		}
-	}
-	return db
-}
-
-func QueryToEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		if c.Query(v) != "" {
-			var sb strings.Builder
-
-			_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			db = db.Where(sb.String(), c.Query(v))
-		}
-	}
-	return db
-}
-
-func QueryToFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		if c.Query(v) != "" {
-			var sb strings.Builder
-
-			_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			var sbValue strings.Builder
-
-			_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
-
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			db = db.Where(sb.String(), sbValue.String())
-		}
-	}
-	return db
-}
-
-func QueryToFussyKeysSearch(c *gin.Context, db *gorm.DB, value string, keys ...string) *gorm.DB {
-	if c.Query(value) == "" {
-		return db
-	}
-
-	var condition *gorm.DB
-	for i, v := range keys {
-		sb := v + " LIKE ?"
-		sv := "%" + c.Query(value) + "%"
-
-		switch i {
-		case 0:
-			condition = db.Where(db.Where(sb, sv))
-		default:
-			condition = condition.Or(sb, sv)
-		}
-	}
-
-	return db.Where(condition)
-}
-
-func QueryToOrInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		queryArray := c.QueryArray(v + "[]")
-		if len(queryArray) == 0 {
-			queryArray = c.QueryArray(v)
-		}
-		if len(queryArray) == 1 && queryArray[0] == "" {
-			continue
-		}
-		if len(queryArray) >= 1 {
-			var sb strings.Builder
-
-			_, err := fmt.Fprintf(&sb, "`%s` IN ?", v)
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			db = db.Or(sb.String(), queryArray)
-		}
-	}
-	return db
-}
-
-func QueryToOrEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		if c.Query(v) != "" {
-			var sb strings.Builder
-
-			_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			db = db.Or(sb.String(), c.Query(v))
-		}
-	}
-	return db
-}
-
-func QueryToOrFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
-	for _, v := range keys {
-		if c.Query(v) != "" {
-			var sb strings.Builder
-
-			_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			var sbValue strings.Builder
-
-			_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
-
-			if err != nil {
-				logger.Error(err)
-				continue
-			}
-
-			db = db.Or(sb.String(), sbValue.String())
-		}
-	}
-	return db
-}

+ 0 - 39
internal/cosy/hook.go

@@ -1,39 +0,0 @@
-package cosy
-
-import "gorm.io/gorm"
-
-func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, hook)
-	return c
-}
-
-func (c *Ctx[T]) beforeExecuteHook() {
-	if len(c.beforeExecuteHookFunc) > 0 {
-		for _, v := range c.beforeExecuteHookFunc {
-			v(c)
-		}
-	}
-}
-
-func (c *Ctx[T]) beforeDecodeHook() {
-	if len(c.beforeDecodeHookFunc) > 0 {
-		for _, v := range c.beforeDecodeHookFunc {
-			v(c)
-		}
-	}
-}
-
-func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...)
-	return c
-}
-
-func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...)
-	return c
-}
-
-func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.executedHookFunc = append(c.executedHookFunc, hook...)
-	return c
-}

+ 0 - 172
internal/cosy/list.go

@@ -1,172 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/gin-gonic/gin"
-	"github.com/spf13/cast"
-	"gorm.io/gorm"
-	"net/http"
-)
-
-func GetPagingParams(c *gin.Context) (page, offset, pageSize int) {
-	page = cast.ToInt(c.Query("page"))
-	if page == 0 {
-		page = 1
-	}
-	pageSize = settings.ServerSettings.PageSize
-	reqPageSize := c.Query("page_size")
-	if reqPageSize != "" {
-		pageSize = cast.ToInt(reqPageSize)
-	}
-	offset = (page - 1) * pageSize
-	return
-}
-
-func (c *Ctx[T]) combineStdSelectorRequest() {
-	StdSelectorInitID := c.ctx.QueryArray("id[]")
-
-	if len(StdSelectorInitID) > 0 {
-		c.GormScope(func(tx *gorm.DB) *gorm.DB {
-			return tx.Where(c.itemKey+" IN ?", StdSelectorInitID)
-		})
-	}
-}
-
-func (c *Ctx[T]) result() (*gorm.DB, bool) {
-	for _, v := range c.preloads {
-		t := v
-		c.GormScope(func(tx *gorm.DB) *gorm.DB {
-			tx = tx.Preload(t)
-			return tx
-		})
-	}
-
-	c.beforeExecuteHook()
-
-	var dbModel T
-	result := model.UseDB()
-
-	if cast.ToBool(c.ctx.Query("trash")) {
-		tableName := c.table
-		if c.table == "" {
-			stmt := &gorm.Statement{DB: model.UseDB()}
-			err := stmt.Parse(&dbModel)
-			if err != nil {
-				logger.Error(err)
-				return nil, false
-			}
-			tableName = stmt.Schema.Table
-		}
-
-		result = result.Unscoped().Where(tableName + ".deleted_at IS NOT NULL")
-	}
-
-	result = result.Model(&dbModel)
-	if c.table != "" {
-		result = result.Table(c.table, c.tableArgs...)
-	}
-
-	c.combineStdSelectorRequest()
-
-	if len(c.gormScopes) > 0 {
-		result = result.Scopes(c.gormScopes...)
-	}
-
-	return result, true
-}
-
-func (c *Ctx[T]) ListAllData() (data any, ok bool) {
-	result, ok := c.result()
-	if !ok {
-		return nil, false
-	}
-
-	result = result.Scopes(c.SortOrder())
-	if c.scan == nil {
-		models := make([]*T, 0)
-		result.Find(&models)
-
-		if c.transformer != nil {
-			transformed := make([]any, 0)
-			for k := range models {
-				transformed = append(transformed, c.transformer(models[k]))
-			}
-			data = transformed
-		} else {
-			data = models
-		}
-	} else {
-		data = c.scan(result)
-	}
-	return data, true
-}
-
-func (c *Ctx[T]) PagingListData() (*model.DataList, bool) {
-	result, ok := c.result()
-	if !ok {
-		return nil, false
-	}
-
-	scopesResult := result.Scopes(c.OrderAndPaginate())
-	data := &model.DataList{}
-	if c.scan == nil {
-		models := make([]*T, 0)
-		scopesResult.Find(&models)
-
-		if c.transformer != nil {
-			transformed := make([]any, 0)
-			for k := range models {
-				transformed = append(transformed, c.transformer(models[k]))
-			}
-			data.Data = transformed
-		} else {
-			data.Data = models
-		}
-	} else {
-		data.Data = c.scan(scopesResult)
-	}
-
-	var totalRecords int64
-	delete(result.Statement.Clauses, "ORDER BY")
-	delete(result.Statement.Clauses, "LIMIT")
-	result.Count(&totalRecords)
-
-	page := cast.ToInt(c.ctx.Query("page"))
-	if page == 0 {
-		page = 1
-	}
-
-	pageSize := settings.ServerSettings.PageSize
-	if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" {
-		pageSize = cast.ToInt(reqPageSize)
-	}
-
-	data.Pagination = model.Pagination{
-		Total:       totalRecords,
-		PerPage:     pageSize,
-		CurrentPage: page,
-		TotalPages:  model.TotalPage(totalRecords, pageSize),
-	}
-	return data, true
-}
-
-func (c *Ctx[T]) PagingList() {
-	data, ok := c.PagingListData()
-	if ok {
-		c.ctx.JSON(http.StatusOK, data)
-	}
-}
-
-// EmptyPagingList return empty list
-func (c *Ctx[T]) EmptyPagingList() {
-	pageSize := settings.ServerSettings.PageSize
-	if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" {
-		pageSize = cast.ToInt(reqPageSize)
-	}
-
-	data := &model.DataList{Data: make([]any, 0)}
-	data.Pagination.PerPage = pageSize
-	c.ctx.JSON(http.StatusOK, data)
-}

+ 0 - 96
internal/cosy/map2struct/hook.go

@@ -1,96 +0,0 @@
-package map2struct
-
-import (
-	"github.com/mitchellh/mapstructure"
-	"github.com/shopspring/decimal"
-	"github.com/spf13/cast"
-	"gopkg.in/guregu/null.v4"
-	"reflect"
-	"time"
-)
-
-var timeLocation *time.Location
-
-func init() {
-	timeLocation, _ = time.LoadLocation("Asia/Shanghai")
-}
-
-func ToTimeHookFunc() mapstructure.DecodeHookFunc {
-	return func(
-		f reflect.Type,
-		t reflect.Type,
-		data interface{}) (interface{}, error) {
-		if t != reflect.TypeOf(time.Time{}) {
-			return data, nil
-		}
-
-		switch f.Kind() {
-		case reflect.String:
-			return cast.ToTimeInDefaultLocationE(data, timeLocation)
-		case reflect.Float64:
-			return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil
-		case reflect.Int64:
-			return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil
-		default:
-			return data, nil
-		}
-		// Convert it by parsing
-	}
-}
-
-func ToTimePtrHookFunc() mapstructure.DecodeHookFunc {
-	return func(
-		f reflect.Type,
-		t reflect.Type,
-		data interface{}) (interface{}, error) {
-		if t != reflect.TypeOf(&time.Time{}) {
-			return data, nil
-		}
-
-		switch f.Kind() {
-		case reflect.String:
-			if data == "" {
-				return nil, nil
-			}
-			v, err := cast.ToTimeInDefaultLocationE(data, timeLocation)
-			return &v, err
-		case reflect.Float64:
-			v := time.Unix(0, int64(data.(float64))*int64(time.Millisecond))
-			return &v, nil
-		case reflect.Int64:
-			v := time.Unix(0, data.(int64)*int64(time.Millisecond))
-			return &v, nil
-		default:
-			return data, nil
-		}
-		// Convert it by parsing
-	}
-}
-
-func ToDecimalHookFunc() mapstructure.DecodeHookFunc {
-	return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
-
-		if t == reflect.TypeOf(decimal.Decimal{}) {
-			if f.Kind() == reflect.Float64 {
-				return decimal.NewFromFloat(data.(float64)), nil
-			}
-
-			if input := data.(string); input != "" {
-				return decimal.NewFromString(data.(string))
-			}
-			return decimal.Decimal{}, nil
-		}
-
-		return data, nil
-	}
-}
-
-func ToNullableStringHookFunc() mapstructure.DecodeHookFunc {
-	return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
-		if t == reflect.TypeOf(null.String{}) {
-			return null.StringFrom(data.(string)), nil
-		}
-
-		return data, nil
-	}
-}

+ 0 - 25
internal/cosy/map2struct/map2struct.go

@@ -1,25 +0,0 @@
-package map2struct
-
-import (
-	"github.com/mitchellh/mapstructure"
-)
-
-func WeakDecode(input, output interface{}) error {
-	config := &mapstructure.DecoderConfig{
-		Metadata:         nil,
-		Result:           output,
-		WeaklyTypedInput: true,
-		DecodeHook: mapstructure.ComposeDecodeHookFunc(
-			ToDecimalHookFunc(), ToTimeHookFunc(), ToNullableStringHookFunc(),
-			ToTimePtrHookFunc(),
-		),
-		TagName: "json",
-	}
-
-	decoder, err := mapstructure.NewDecoder(config)
-	if err != nil {
-		return err
-	}
-
-	return decoder.Decode(input)
-}

+ 0 - 46
internal/cosy/order.go

@@ -1,46 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/model"
-	"gorm.io/gorm"
-	"net/http"
-)
-
-func (c *Ctx[T]) UpdateOrder() {
-	var json struct {
-		TargetID    int   `json:"target_id"`
-		Direction   int   `json:"direction" binding:"oneof=-1 1"`
-		AffectedIDs []int `json:"affected_ids"`
-	}
-
-	if !api.BindAndValid(c.ctx, &json) {
-		return
-	}
-
-	affectedLen := len(json.AffectedIDs)
-
-	db := model.UseDB()
-
-	if c.table != "" {
-		db = db.Table(c.table, c.tableArgs...)
-	}
-
-	// update target
-	err := db.Model(&c.Model).Where("id = ?", json.TargetID).Update("order_id", gorm.Expr("order_id + ?", affectedLen*(-json.Direction))).Error
-
-	if err != nil {
-		api.ErrHandler(c.ctx, err)
-		return
-	}
-
-	// update affected
-	err = db.Model(&c.Model).Where("id in ?", json.AffectedIDs).Update("order_id", gorm.Expr("order_id + ?", json.Direction)).Error
-
-	if err != nil {
-		api.ErrHandler(c.ctx, err)
-		return
-	}
-
-	c.ctx.JSON(http.StatusOK, json)
-}

+ 0 - 41
internal/cosy/sort.go

@@ -1,41 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"gorm.io/gorm"
-	"gorm.io/gorm/schema"
-	"strings"
-	"sync"
-)
-
-func (c *Ctx[T]) SortOrder() func(db *gorm.DB) *gorm.DB {
-	return func(db *gorm.DB) *gorm.DB {
-		order := c.ctx.DefaultQuery("order", "desc")
-		if order != "desc" && order != "asc" {
-			order = "desc"
-		}
-
-		sortBy := c.ctx.DefaultQuery("sort_by", c.itemKey)
-
-		s, _ := schema.Parse(c.Model, &sync.Map{}, schema.NamingStrategy{})
-		if _, ok := s.FieldsByDBName[sortBy]; !ok && sortBy != c.itemKey {
-			logger.Error("invalid order field:", sortBy)
-			return db
-		}
-
-		var sb strings.Builder
-		sb.WriteString(sortBy)
-		sb.WriteString(" ")
-		sb.WriteString(order)
-
-		return db.Order(sb.String())
-	}
-}
-
-func (c *Ctx[T]) OrderAndPaginate() func(db *gorm.DB) *gorm.DB {
-	return func(db *gorm.DB) *gorm.DB {
-		db = c.SortOrder()(db)
-		_, offset, pageSize := GetPagingParams(c.ctx)
-		return db.Offset(offset).Limit(pageSize)
-	}
-}

+ 0 - 101
internal/cosy/update.go

@@ -1,101 +0,0 @@
-package cosy
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/cosy/map2struct"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/gin-gonic/gin"
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-	"net/http"
-)
-
-func (c *Ctx[T]) SetNextHandler(handler gin.HandlerFunc) *Ctx[T] {
-	c.nextHandler = &handler
-	return c
-}
-
-func (c *Ctx[T]) Modify() {
-	if c.abort {
-		return
-	}
-	id := c.ctx.Param("id")
-	errs := c.validate()
-
-	if len(errs) > 0 {
-		c.ctx.JSON(http.StatusNotAcceptable, gin.H{
-			"message": "Requested with wrong parameters",
-			"errors":  errs,
-		})
-		return
-	}
-
-	db := model.UseDB()
-
-	result := db
-	if len(c.gormScopes) > 0 {
-		result = result.Scopes(c.gormScopes...)
-	}
-
-	err := result.Session(&gorm.Session{}).First(&c.OriginModel, id).Error
-
-	if err != nil {
-		c.AbortWithError(err)
-		return
-	}
-
-	c.beforeDecodeHook()
-	if c.abort {
-		return
-	}
-
-	var selectedFields []string
-
-	for k := range c.Payload {
-		selectedFields = append(selectedFields, k)
-	}
-
-	err = map2struct.WeakDecode(c.Payload, &c.Model)
-
-	if err != nil {
-		errHandler(c.ctx, err)
-		return
-	}
-
-	c.beforeExecuteHook()
-	if c.abort {
-		return
-	}
-
-	if c.table != "" {
-		db = db.Table(c.table, c.tableArgs...)
-	}
-	err = db.Model(&c.OriginModel).Select(selectedFields).Updates(&c.Model).Error
-
-	if err != nil {
-		c.AbortWithError(err)
-		return
-	}
-
-	err = db.Preload(clause.Associations).First(&c.Model, id).Error
-
-	if err != nil {
-		c.AbortWithError(err)
-		return
-	}
-
-	if len(c.executedHookFunc) > 0 {
-		for _, v := range c.executedHookFunc {
-			v(c)
-
-			if c.abort {
-				return
-			}
-		}
-	}
-
-	if c.nextHandler != nil {
-		(*c.nextHandler)(c.ctx)
-	} else {
-		c.ctx.JSON(http.StatusOK, c.Model)
-	}
-}

+ 1 - 1
internal/cron/cron.go

@@ -2,7 +2,7 @@ package cron
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/cert"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/logrotate"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"

+ 1 - 1
internal/helper/directory.go

@@ -1,7 +1,7 @@
 package helper
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"path/filepath"
 	"strings"
 )

+ 1 - 1
internal/helper/hash.go

@@ -3,7 +3,7 @@ package helper
 import (
 	"crypto/sha512"
 	"fmt"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"io"
 	"os"
 )

+ 17 - 10
internal/kernal/boot.go

@@ -8,14 +8,18 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/cert"
 	"github.com/0xJacky/Nginx-UI/internal/cluster"
 	"github.com/0xJacky/Nginx-UI/internal/cron"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/passkey"
 	"github.com/0xJacky/Nginx-UI/internal/validation"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/google/uuid"
+	"github.com/uozi-tech/cosy"
+	sqlite "github.com/uozi-tech/cosy-driver-sqlite"
+	"github.com/uozi-tech/cosy/logger"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"mime"
+	"path"
 	"runtime"
 )
 
@@ -23,6 +27,7 @@ func Boot() {
 	defer recovery()
 
 	async := []func(){
+		settings.Init,
 		InitJsExtensionType,
 		InitDatabase,
 		InitNodeSecret,
@@ -70,12 +75,13 @@ func recovery() {
 
 func InitDatabase() {
 	// Skip install
-	if settings.ServerSettings.SkipInstallation {
+	if settings.NodeSettings.SkipInstallation {
 		skipInstall()
 	}
 
-	if "" != settings.ServerSettings.JwtSecret {
-		db := model.Init()
+	if "" != cSettings.AppSettings.JwtSecret {
+		db := cosy.InitDB(sqlite.Open(path.Dir(cSettings.ConfPath), cSettings.DataBaseSettings))
+		model.Use(db)
 		query.Init(db)
 
 		InitAfterDatabase()
@@ -83,21 +89,22 @@ func InitDatabase() {
 }
 
 func InitNodeSecret() {
-	if "" == settings.ServerSettings.NodeSecret {
-		logger.Warn("NodeSecret is empty, generating...")
-		settings.ServerSettings.NodeSecret = uuid.New().String()
+	if "" == settings.NodeSettings.Secret {
+		logger.Info("Secret is empty, generating...")
+		uuidStr := uuid.New().String()
+		settings.NodeSettings.Secret = uuidStr
 
 		err := settings.Save()
 		if err != nil {
 			logger.Error("Error save settings", err)
 		}
-		logger.Warn("Generated NodeSecret: ", settings.ServerSettings.NodeSecret)
+		logger.Info("Generated Secret: ", uuidStr)
 	}
 }
 
 func InitCryptoSecret() {
 	if "" == settings.CryptoSettings.Secret {
-		logger.Warn("Secret is empty, generating...")
+		logger.Info("Secret is empty, generating...")
 
 		key := make([]byte, 32)
 		if _, err := rand.Read(key); err != nil {
@@ -111,7 +118,7 @@ func InitCryptoSecret() {
 		if err != nil {
 			logger.Error("Error save settings", err)
 		}
-		logger.Warn("Secret Generated")
+		logger.Info("Secret Generated")
 	}
 }
 

+ 1 - 1
internal/kernal/register_acme_user.go

@@ -1,7 +1,7 @@
 package kernal
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/query"
 )
 

+ 8 - 7
internal/kernal/skip_install.go

@@ -1,13 +1,14 @@
 package kernal
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/caarlos0/env/v11"
 	"github.com/google/uuid"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"golang.org/x/crypto/bcrypt"
 	"gorm.io/gorm"
 )
@@ -20,13 +21,13 @@ type predefinedUser struct {
 func skipInstall() {
 	logger.Info("Skip installation mode enabled")
 
-	if settings.ServerSettings.JwtSecret == "" {
-		settings.ServerSettings.JwtSecret = uuid.New().String()
+	if cSettings.AppSettings.JwtSecret == "" {
+		cSettings.AppSettings.JwtSecret = uuid.New().String()
 	}
 
-	if settings.ServerSettings.NodeSecret == "" {
-		settings.ServerSettings.NodeSecret = uuid.New().String()
-		logger.Infof("NodeSecret: %s", settings.ServerSettings.NodeSecret)
+	if settings.NodeSettings.Secret == "" {
+		settings.NodeSettings.Secret = uuid.New().String()
+		logger.Infof("Secret: %s", settings.NodeSettings.Secret)
 	}
 
 	err := settings.Save()
@@ -37,7 +38,7 @@ func skipInstall() {
 
 func registerPredefinedUser() {
 	// when skip installation mode is enabled, the predefined user will be created
-	if !settings.ServerSettings.SkipInstallation {
+	if !settings.NodeSettings.SkipInstallation {
 		return
 	}
 	pUser := &predefinedUser{}

+ 1 - 1
internal/logrotate/logrotate.go

@@ -1,7 +1,7 @@
 package logrotate
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"os/exec"
 	"strings"

+ 3 - 22
internal/middleware/middleware.go

@@ -3,36 +3,17 @@ package middleware
 import (
 	"encoding/base64"
 	"github.com/0xJacky/Nginx-UI/app"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/user"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-contrib/static"
 	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy/logger"
 	"io/fs"
 	"net/http"
 	"path"
-	"runtime"
 	"strings"
 )
 
-func Recovery() gin.HandlerFunc {
-	return func(c *gin.Context) {
-		defer func() {
-			if err := recover(); err != nil {
-				buf := make([]byte, 1024)
-				runtime.Stack(buf, false)
-				logger.Errorf("%s\n%s", err, buf)
-
-				c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
-					"message": err.(error).Error(),
-				})
-			}
-		}()
-
-		c.Next()
-	}
-}
-
 func AuthRequired() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		abortWithAuthFailure := func() {
@@ -43,8 +24,8 @@ func AuthRequired() gin.HandlerFunc {
 
 		token := c.GetHeader("Authorization")
 		if token == "" {
-			if token = c.GetHeader("X-Node-Secret"); token != "" && token == settings.ServerSettings.NodeSecret {
-				c.Set("NodeSecret", token)
+			if token = c.GetHeader("X-Node-Secret"); token != "" && token == settings.NodeSettings.Secret {
+				c.Set("Secret", token)
 				c.Next()
 				return
 			} else {

+ 1 - 1
internal/middleware/proxy.go

@@ -1,7 +1,7 @@
 package middleware
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/internal/transport"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"

+ 1 - 1
internal/middleware/proxy_ws.go

@@ -1,7 +1,7 @@
 package middleware
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
 	"github.com/pretty66/websocketproxy"

+ 1 - 1
internal/nginx/config_args.go

@@ -2,7 +2,7 @@ package nginx
 
 import (
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"os/exec"
 	"path/filepath"

+ 3 - 3
internal/passkey/webauthn.go

@@ -1,7 +1,7 @@
 package passkey
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/go-webauthn/webauthn/protocol"
 	"github.com/go-webauthn/webauthn/webauthn"
@@ -10,7 +10,7 @@ import (
 var instance *webauthn.WebAuthn
 
 func Init() {
-	options := &settings.WebAuthnSettings
+	options := settings.WebAuthnSettings
 
 	if !Enabled() {
 		logger.Debug("WebAuthn settings are not configured")
@@ -34,7 +34,7 @@ func Init() {
 }
 
 func Enabled() bool {
-	options := &settings.WebAuthnSettings
+	options := settings.WebAuthnSettings
 	if options.RPDisplayName == "" || options.RPID == "" || len(options.RPOrigins) == 0 {
 		return false
 	}

+ 2 - 2
internal/pty/pipeline.go

@@ -2,11 +2,11 @@ package pty
 
 import (
 	"encoding/json"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/creack/pty"
 	"github.com/gorilla/websocket"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
 	"os"
 	"os/exec"
 	"time"
@@ -27,7 +27,7 @@ type Message struct {
 const bufferSize = 2048
 
 func NewPipeLine(conn *websocket.Conn) (p *Pipeline, err error) {
-	c := exec.Command(settings.ServerSettings.StartCmd)
+	c := exec.Command(settings.TerminalSettings.StartCmd)
 
 	ptmx, err := pty.StartWithSize(c, &pty.Winsize{Cols: 90, Rows: 60})
 	if err != nil {

+ 4 - 3
internal/template/template.go

@@ -3,7 +3,6 @@ package template
 import (
 	"bufio"
 	"bytes"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/settings"
 	templ "github.com/0xJacky/Nginx-UI/template"
@@ -11,6 +10,8 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/pkg/errors"
 	"github.com/tufanbarisyildirim/gonginx/parser"
+	"github.com/uozi-tech/cosy/logger"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"io"
 	"io/fs"
 	"path/filepath"
@@ -115,8 +116,8 @@ func ParseTemplate(path, name string, bindData map[string]Variable) (c ConfigDet
 	}
 
 	data := gin.H{
-		"HTTPPORT":   settings.ServerSettings.HttpPort,
-		"HTTP01PORT": settings.ServerSettings.HTTPChallengePort,
+		"HTTPPORT":   cSettings.ServerSettings.Port,
+		"HTTP01PORT": settings.CertSettings.HTTPChallengePort,
 	}
 
 	for k, v := range bindData {

+ 1 - 1
internal/transport/transport.go

@@ -11,7 +11,7 @@ import (
 func NewTransport(options ...func(transport *http.Transport) error) (t *http.Transport, err error) {
 	t = &http.Transport{
 		Proxy:           http.ProxyFromEnvironment,
-		TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.HTTPSettings.InsecureSkipVerify},
 	}
 
 	for _, option := range options {

+ 6 - 5
internal/upgrader/upgrade.go

@@ -5,11 +5,11 @@ import (
 	"fmt"
 	_github "github.com/0xJacky/Nginx-UI/.github"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/jpillora/overseer"
 	"github.com/minio/selfupdate"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
 	"io"
 	"net/http"
 	"net/url"
@@ -138,8 +138,9 @@ func (u *Upgrader) DownloadLatestRelease(progressChan chan float64) (tarName str
 		return
 	}
 
-	if settings.ServerSettings.GithubProxy != "" {
-		digest.BrowserDownloadUrl, err = url.JoinPath(settings.ServerSettings.GithubProxy, digest.BrowserDownloadUrl)
+	githubProxy := settings.HTTPSettings.GithubProxy
+	if githubProxy != "" {
+		digest.BrowserDownloadUrl, err = url.JoinPath(githubProxy, digest.BrowserDownloadUrl)
 		if err != nil {
 			err = errors.Wrap(err, "service.DownloadLatestRelease url.JoinPath error")
 			return
@@ -156,8 +157,8 @@ func (u *Upgrader) DownloadLatestRelease(progressChan chan float64) (tarName str
 
 	dir := filepath.Dir(u.ExPath)
 
-	if settings.ServerSettings.GithubProxy != "" {
-		downloadUrl, err = url.JoinPath(settings.ServerSettings.GithubProxy, downloadUrl)
+	if githubProxy != "" {
+		downloadUrl, err = url.JoinPath(githubProxy, downloadUrl)
 		if err != nil {
 			err = errors.Wrap(err, "service.DownloadLatestRelease url.JoinPath error")
 			return

+ 4 - 4
internal/user/user.go

@@ -1,12 +1,12 @@
 package user
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
-	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/golang-jwt/jwt/v4"
 	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy/logger"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"strings"
 	"time"
 )
@@ -68,7 +68,7 @@ func GenerateJWT(user *model.User) (string, error) {
 	}
 
 	unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
-	signedToken, err := unsignedToken.SignedString([]byte(settings.ServerSettings.JwtSecret))
+	signedToken, err := unsignedToken.SignedString([]byte(cSettings.AppSettings.JwtSecret))
 	if err != nil {
 		return "", err
 	}
@@ -96,7 +96,7 @@ func ValidateJWT(token string) (claims *JWTClaims, err error) {
 		token,
 		&JWTClaims{},
 		func(token *jwt.Token) (interface{}, error) {
-			return []byte(settings.ServerSettings.JwtSecret), nil
+			return []byte(cSettings.AppSettings.JwtSecret), nil
 		},
 	)
 	if err != nil {

+ 1 - 1
internal/validation/validation.go

@@ -1,7 +1,7 @@
 package validation
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"github.com/gin-gonic/gin/binding"
 	val "github.com/go-playground/validator/v10"
 )

+ 20 - 18
main.go

@@ -4,31 +4,34 @@ import (
 	"flag"
 	"fmt"
 	"github.com/0xJacky/Nginx-UI/internal/kernal"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
+	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/router"
 	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/gin-gonic/gin"
 	"github.com/jpillora/overseer"
-	"net/http"
+	"github.com/uozi-tech/cosy"
+	"github.com/uozi-tech/cosy/logger"
+	cSettings "github.com/uozi-tech/cosy/settings"
 	"time"
 )
 
-func Program(state overseer.State) {
-	defer logger.Sync()
+func Program(confPath string) func(state overseer.State) {
+	return func(state overseer.State) {
+		defer logger.Sync()
 
-	logger.Infof("Nginx configuration directory: %s", nginx.GetConfPath())
+		cosy.RegisterModels(model.GenerateAllModel()...)
 
-	kernal.Boot()
+		cosy.RegisterAsyncFunc(kernal.Boot, router.InitRouter)
 
-	if state.Listener != nil {
-		err := http.Serve(state.Listener, router.InitRouter())
-		if err != nil {
-			logger.Error(err)
+		if state.Listener != nil {
+			cosy.SetListener(state.Listener)
+
+			cosy.Boot(confPath)
+
+			logger.Infof("Nginx configuration directory: %s", nginx.GetConfPath())
 		}
+		logger.Info("Server exited")
 	}
-
-	logger.Info("Server exited")
 }
 
 func main() {
@@ -36,13 +39,12 @@ func main() {
 	flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
 	flag.Parse()
 
-	settings.Init(confPath)
-
-	gin.SetMode(settings.ServerSettings.RunMode)
+	settings.Migrate(confPath)
+	cSettings.Init(confPath)
 
 	overseer.Run(overseer.Config{
-		Program:          Program,
-		Address:          fmt.Sprintf("%s:%s", settings.ServerSettings.HttpHost, settings.ServerSettings.HttpPort),
+		Program:          Program(confPath),
+		Address:          fmt.Sprintf("%s:%d", cSettings.ServerSettings.Host, cSettings.ServerSettings.Port),
 		TerminateTimeout: 5 * time.Second,
 	})
 }

+ 1 - 1
model/config_backup.go

@@ -1,7 +1,7 @@
 package model
 
 import (
-	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/uozi-tech/cosy/logger"
 	"os"
 	"path/filepath"
 )

+ 3 - 39
model/model.go

@@ -1,15 +1,8 @@
 package model
 
 import (
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/gin-gonic/gin"
-	"gorm.io/driver/sqlite"
 	"gorm.io/gen"
 	"gorm.io/gorm"
-	gormlogger "gorm.io/gorm/logger"
-	"path"
 	"time"
 )
 
@@ -38,47 +31,18 @@ func GenerateAllModel() []any {
 		BanIP{},
 		Config{},
 		Passkey{},
+		SiteCategory{},
 	}
 }
 
-func logMode() gormlogger.Interface {
-	switch settings.ServerSettings.RunMode {
-	case gin.ReleaseMode:
-		return gormlogger.Default.LogMode(gormlogger.Warn)
-	default:
-		fallthrough
-	case gin.DebugMode:
-		return gormlogger.Default.LogMode(gormlogger.Info)
-	}
+func Use(tx *gorm.DB) {
+	db = tx
 }
 
 func UseDB() *gorm.DB {
 	return db
 }
 
-func Init() *gorm.DB {
-	dbPath := path.Join(path.Dir(settings.ConfPath), fmt.Sprintf("%s.db", settings.ServerSettings.Database))
-
-	var err error
-	db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
-		Logger:                                   logMode(),
-		PrepareStmt:                              true,
-		DisableForeignKeyConstraintWhenMigrating: true,
-	})
-
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-
-	// Migrate the schema
-	err = db.AutoMigrate(GenerateAllModel()...)
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-
-	return db
-}
-
 type Pagination struct {
 	Total       int64 `json:"total"`
 	PerPage     int   `json:"per_page"`

+ 7 - 0
model/site_category.go

@@ -0,0 +1,7 @@
+package model
+
+type SiteCategory struct {
+	Model
+	Name        string `json:"name"`
+	SyncNodeIds []int  `json:"sync_node_ids" gorm:"serializer:json"`
+}

+ 3 - 6
router/routers.go

@@ -19,14 +19,13 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/middleware"
 	"github.com/gin-contrib/static"
 	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
 	"net/http"
 )
 
-func InitRouter() *gin.Engine {
-	r := gin.New()
+func InitRouter() {
+	r := cosy.GetEngine()
 	r.Use(
-		gin.Logger(),
-		middleware.Recovery(),
 		middleware.CacheJs(),
 		middleware.IPWhiteList(),
 		static.Serve("/", middleware.MustFs("")),
@@ -78,6 +77,4 @@ func InitRouter() *gin.Engine {
 			system.InitWebSocketRouter(w)
 		}
 	}
-
-	return r
 }

+ 82 - 0
settings/app.testing.ini

@@ -0,0 +1,82 @@
+[app]
+PageSize  = 20
+JwtSecret = newSecret
+
+[server]
+Host    = 0.0.0.0
+Port    = 9000
+RunMode = debug
+
+[database]
+Host        = 
+Port        = 0
+User        = 
+Password    = 
+Name        = database
+TablePrefix = 
+
+[auth]
+IPWhiteList         = 127.0.0.1
+BanThresholdMinutes = 10
+MaxAttempts         = 10
+
+[casdoor]
+Endpoint        = http://127.0.0.1:8001
+ClientId        = 1234567890qwertyuiop
+ClientSecret    = 1234567890qwertyuiop1234567890qwertyuiop
+CertificatePath = ./casdoor.pub
+Organization    = built-in
+Application     = nginx-ui-dev
+RedirectUri     = 
+
+[cert]
+Email                = test
+CADir                = /test
+CertRenewalInterval  = 7
+RecursiveNameservers = 8.8.8.8,1.1.1.1
+HTTPChallengePort    = 9181
+
+[cluster]
+Node = http://10.0.0.1:9000?name=test&node_secret=asdfghjklqwertyuiopzxcvbnm&enabled=true
+
+[crypto]
+Secret = 12345678901234567890
+
+[http]
+GithubProxy        = https://mirror.ghproxy.com/
+InsecureSkipVerify = true
+
+[logrotate]
+Enabled  = true
+CMD      = logrotate /etc/logrotate.d/nginx
+Interval = 1440
+
+[nginx]
+AccessLogPath   = 
+ErrorLogPath    = 
+LogDirWhiteList = /var/log/nginx
+ConfigDir       = 
+PIDPath         = 
+TestConfigCmd   = 
+ReloadCmd       = 
+RestartCmd      = 
+
+[node]
+Name             = Local
+Secret           = 
+SkipInstallation = false
+Demo             = false
+
+[openai]
+BaseUrl = 
+Token   = 
+Proxy   = 
+Model   = gpt-4o
+
+[terminal]
+StartCmd = bash
+
+[webauthn]
+RPDisplayName = Nginx UI
+RPID          = localhost
+RPOrigins     = http://localhost:3002,http://127.0.0.1:3002

+ 1 - 1
settings/auth.go

@@ -6,7 +6,7 @@ type Auth struct {
 	MaxAttempts         int      `json:"max_attempts" binding:"min=1"`
 }
 
-var AuthSettings = Auth{
+var AuthSettings = &Auth{
 	BanThresholdMinutes: 10,
 	MaxAttempts:         10,
 }

+ 1 - 1
settings/casdoor.go

@@ -10,7 +10,7 @@ type Casdoor struct {
 	RedirectUri     string `json:"redirect_uri" protected:"true"`
 }
 
-var CasdoorSettings = Casdoor{
+var CasdoorSettings = &Casdoor{
 	Endpoint:        "",
 	ClientId:        "",
 	ClientSecret:    "",

+ 36 - 0
settings/cert.go

@@ -0,0 +1,36 @@
+package settings
+
+import "github.com/go-acme/lego/v4/lego"
+
+type Cert struct {
+	Email                string   `json:"email" protected:"true"`
+	CADir                string   `json:"ca_dir" binding:"omitempty,url"`
+	RenewalInterval      int      `json:"cert_renewal_interval" binding:"min=7,max=21"`
+	RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"`
+	HTTPChallengePort    string   `json:"http_challenge_port"`
+}
+
+var CertSettings = &Cert{
+	Email:                "",
+	CADir:                "",
+	RenewalInterval:      7,
+	RecursiveNameservers: []string{},
+	HTTPChallengePort:    "9180",
+}
+
+func (s *Cert) GetCADir() string {
+	if s.CADir != "" {
+		return s.CADir
+	}
+	return lego.LEDirectoryProduction
+}
+
+func (s *Cert) GetCertRenewalInterval() int {
+	if s.RenewalInterval < 7 {
+		return 7
+	}
+	if s.RenewalInterval > 21 {
+		return 21
+	}
+	return s.RenewalInterval
+}

+ 5 - 3
settings/cluster.go

@@ -1,19 +1,21 @@
 package settings
 
+import "github.com/uozi-tech/cosy/settings"
+
 type Cluster struct {
 	Node []string `ini:",,allowshadow"`
 }
 
-var ClusterSettings = Cluster{
+var ClusterSettings = &Cluster{
 	Node: []string{},
 }
 
 func ReloadCluster() (err error) {
-	err = load()
+	err = settings.Reload()
 
 	if err != nil {
 		return err
 	}
 
-	return mapTo("cluster", &ClusterSettings)
+	return settings.MapTo("cluster", &ClusterSettings)
 }

+ 0 - 16
settings/cluster_test.go

@@ -1,16 +0,0 @@
-package settings
-
-import (
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestCluster(t *testing.T) {
-	Init("../app.example.ini")
-
-	assert.Equal(t, []string{
-		"http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true",
-		"http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true",
-		"http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true",
-	}, ClusterSettings.Node)
-}

+ 1 - 1
settings/crypto.go

@@ -6,7 +6,7 @@ type Crypto struct {
 	Secret string
 }
 
-var CryptoSettings = Crypto{}
+var CryptoSettings = &Crypto{}
 
 func (c *Crypto) GetSecretMd5() []byte {
 	k := md5.Sum([]byte(c.Secret))

+ 3 - 3
settings/crypto_test.go

@@ -9,7 +9,7 @@ import (
 )
 
 func TestGetSecretMd5_WithNonEmptySecret_ReturnsExpectedMd5Hash(t *testing.T) {
-	// Setup
+	// Init
 	CryptoSettings.Secret = "testSecret"
 	expectedMd5 := md5.Sum([]byte("testSecret"))
 	expectedMd5String := hex.EncodeToString(expectedMd5[:])
@@ -23,7 +23,7 @@ func TestGetSecretMd5_WithNonEmptySecret_ReturnsExpectedMd5Hash(t *testing.T) {
 }
 
 func TestGetSecretMd5_WithEmptySecret_ReturnsMd5OfEmptyString(t *testing.T) {
-	// Setup
+	// Init
 	CryptoSettings.Secret = ""
 	expectedMd5 := md5.Sum([]byte(""))
 	expectedMd5String := hex.EncodeToString(expectedMd5[:])
@@ -37,7 +37,7 @@ func TestGetSecretMd5_WithEmptySecret_ReturnsMd5OfEmptyString(t *testing.T) {
 }
 
 func TestGetSecretMd5_WithDifferentSecrets_ReturnsDifferentMd5Hashes(t *testing.T) {
-	// Setup
+	// Init
 	CryptoSettings.Secret = "secret1"
 	firstMd5 := CryptoSettings.GetSecretMd5()
 	CryptoSettings.Secret = "secret2"

+ 11 - 0
settings/http.go

@@ -0,0 +1,11 @@
+package settings
+
+type HTTP struct {
+	GithubProxy        string `json:"github_proxy" binding:"omitempty,url"`
+	InsecureSkipVerify bool   `json:"insecure_skip_verify" protected:"true"`
+}
+
+var HTTPSettings = &HTTP{
+	GithubProxy:        "",
+	InsecureSkipVerify: false,
+}

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません