From 33a996e7772d8f6e88ff3c49eac3d8fa8e0c1781 Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 22 Oct 2024 16:38:38 +0800 Subject: [PATCH] refactor: migrate to new cosy --- .gitignore | 1 + api/analytic/analytic.go | 2 +- api/analytic/nodes.go | 2 +- api/api.go | 2 +- api/certificate/acme_user.go | 6 +- api/certificate/certificate.go | 2 +- api/certificate/dns_credential.go | 2 +- api/certificate/issue.go | 2 +- api/cluster/environment.go | 2 +- api/cluster/node.go | 2 +- api/config/list.go | 2 +- api/config/rename.go | 2 +- api/nginx/nginx_log.go | 2 +- api/notification/notification.go | 2 +- api/settings/settings.go | 17 +- api/sites/category.go | 41 +++ api/sites/domain.go | 63 +---- api/sites/list.go | 70 +++++ api/sites/router.go | 9 + api/system/install.go | 11 +- api/system/upgrade.go | 4 +- api/terminal/pty.go | 2 +- api/upstream/upstream.go | 2 +- api/user/auth.go | 2 +- api/user/otp.go | 4 +- api/user/passkey.go | 4 +- api/user/user.go | 4 +- app/src/components/StdDesign/types.d.ts | 1 - app/src/views/certificate/ACMEUser.vue | 10 +- .../CertificateList/certColumns.tsx | 8 +- app/src/views/certificate/DNSCredential.vue | 6 +- app/src/views/environment/envColumns.tsx | 12 +- .../notification/notificationColumns.tsx | 4 +- app/src/views/site/SiteList.vue | 6 +- app/src/views/stream/StreamList.vue | 6 +- app/src/views/user/userColumns.tsx | 10 +- go.mod | 20 +- go.sum | 267 +++++++++--------- img.png | Bin 0 -> 40441 bytes install.sh | 7 +- internal/analytic/analytic.go | 2 +- internal/analytic/node.go | 2 +- internal/analytic/node_record.go | 2 +- internal/analytic/node_stat.go | 2 +- internal/analytic/record.go | 2 +- internal/cache/cache.go | 2 +- internal/cert/auto_cert.go | 6 +- internal/cert/cert.go | 8 +- internal/cert/logger.go | 2 +- internal/cert/payload.go | 2 +- internal/cert/register.go | 18 +- internal/cert/sync.go | 2 +- internal/chatbot/context.go | 2 +- internal/cluster/cluster.go | 2 +- internal/config/sync.go | 4 +- internal/cosy/cosy.go | 117 -------- internal/cosy/create.go | 81 ------ internal/cosy/custom.go | 39 --- internal/cosy/delete.go | 113 -------- internal/cosy/error.go | 23 -- internal/cosy/filter.go | 212 -------------- internal/cosy/hook.go | 39 --- internal/cosy/list.go | 172 ----------- internal/cosy/map2struct/hook.go | 96 ------- internal/cosy/map2struct/map2struct.go | 25 -- internal/cosy/order.go | 46 --- internal/cosy/sort.go | 41 --- internal/cosy/update.go | 101 ------- internal/cron/cron.go | 2 +- internal/helper/directory.go | 2 +- internal/helper/hash.go | 2 +- internal/kernal/boot.go | 27 +- internal/kernal/register_acme_user.go | 2 +- internal/kernal/skip_install.go | 15 +- internal/logrotate/logrotate.go | 2 +- internal/middleware/middleware.go | 25 +- internal/middleware/proxy.go | 2 +- internal/middleware/proxy_ws.go | 2 +- internal/nginx/config_args.go | 2 +- internal/passkey/webauthn.go | 6 +- internal/pty/pipeline.go | 4 +- internal/template/template.go | 7 +- internal/transport/transport.go | 2 +- internal/upgrader/upgrade.go | 11 +- internal/user/user.go | 8 +- internal/validation/validation.go | 2 +- main.go | 38 +-- model/config_backup.go | 2 +- model/model.go | 42 +-- model/site_category.go | 7 + router/routers.go | 9 +- settings/app.testing.ini | 82 ++++++ settings/auth.go | 2 +- settings/casdoor.go | 2 +- settings/cert.go | 36 +++ settings/cluster.go | 8 +- settings/cluster_test.go | 16 -- settings/crypto.go | 2 +- settings/crypto_test.go | 6 +- settings/http.go | 11 + settings/logrotate.go | 2 +- settings/nginx.go | 2 +- settings/node.go | 15 + settings/openai.go | 2 +- settings/server.go | 63 ----- settings/server_v1.go | 227 +++++++++++++++ settings/server_v1_test.go | 125 ++++++++ settings/settings.go | 133 +++------ settings/settings_test.go | 187 ++++++++---- settings/terminal.go | 7 + settings/webauthn.go | 2 +- 111 files changed, 1163 insertions(+), 1772 deletions(-) create mode 100644 api/sites/category.go create mode 100644 api/sites/list.go create mode 100644 img.png delete mode 100644 internal/cosy/cosy.go delete mode 100644 internal/cosy/create.go delete mode 100644 internal/cosy/custom.go delete mode 100644 internal/cosy/delete.go delete mode 100644 internal/cosy/error.go delete mode 100644 internal/cosy/filter.go delete mode 100644 internal/cosy/hook.go delete mode 100644 internal/cosy/list.go delete mode 100644 internal/cosy/map2struct/hook.go delete mode 100644 internal/cosy/map2struct/map2struct.go delete mode 100644 internal/cosy/order.go delete mode 100644 internal/cosy/sort.go delete mode 100644 internal/cosy/update.go create mode 100644 model/site_category.go create mode 100644 settings/app.testing.ini create mode 100644 settings/cert.go delete mode 100644 settings/cluster_test.go create mode 100644 settings/http.go create mode 100644 settings/node.go delete mode 100644 settings/server.go create mode 100644 settings/server_v1.go create mode 100644 settings/server_v1_test.go create mode 100644 settings/terminal.go diff --git a/.gitignore b/.gitignore index 6ab491f9..095b6dbf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ tmp node_modules .pnpm-store app.ini +app.testing.ini dist *.exe *.po~ diff --git a/api/analytic/analytic.go b/api/analytic/analytic.go index 3551cf5c..918a3ee8 100644 --- a/api/analytic/analytic.go +++ b/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" diff --git a/api/analytic/nodes.go b/api/analytic/nodes.go index b880991c..4f698c3b 100644 --- a/api/analytic/nodes.go +++ b/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" diff --git a/api/api.go b/api/api.go index e7237ddb..d5989690 100644 --- a/api/api.go +++ b/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" diff --git a/api/certificate/acme_user.go b/api/certificate/acme_user.go index 65928dc5..13431dd9 100644 --- a/api/certificate/acme_user.go +++ b/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 || diff --git a/api/certificate/certificate.go b/api/certificate/certificate.go index a2dd0c68..f333cfc9 100644 --- a/api/certificate/certificate.go +++ b/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" ) diff --git a/api/certificate/dns_credential.go b/api/certificate/dns_credential.go index 59df26d8..0fec35f4 100644 --- a/api/certificate/dns_credential.go +++ b/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" ) diff --git a/api/certificate/issue.go b/api/certificate/issue.go index f5a7e78d..bd9b70e7 100644 --- a/api/certificate/issue.go +++ b/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" diff --git a/api/cluster/environment.go b/api/cluster/environment.go index fb0686cb..ca9f5310 100644 --- a/api/cluster/environment.go +++ b/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" ) diff --git a/api/cluster/node.go b/api/cluster/node.go index 57848efb..75c54f32 100644 --- a/api/cluster/node.go +++ b/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", }) diff --git a/api/config/list.go b/api/config/list.go index 44b31aa4..27e517d7 100644 --- a/api/config/list.go +++ b/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" diff --git a/api/config/rename.go b/api/config/rename.go index f028833f..e90542a6 100644 --- a/api/config/rename.go +++ b/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" diff --git a/api/nginx/nginx_log.go b/api/nginx/nginx_log.go index 2ac82319..22661ded 100644 --- a/api/nginx/nginx_log.go +++ b/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" diff --git a/api/notification/notification.go b/api/notification/notification.go index 1a3998d2..f0c02304 100644 --- a/api/notification/notification.go +++ b/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" ) diff --git a/api/settings/settings.go b/api/settings/settings.go index 1c6ad46d..c0bab080 100644 --- a/api/settings/settings.go +++ b/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 { diff --git a/api/sites/category.go b/api/sites/category.go new file mode 100644 index 00000000..d8ded05d --- /dev/null +++ b/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() +} diff --git a/api/sites/domain.go b/api/sites/domain.go index 00b8c295..8956ffc6 100644 --- a/api/sites/domain.go +++ b/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") diff --git a/api/sites/list.go b/api/sites/list.go new file mode 100644 index 00000000..1cb29c93 --- /dev/null +++ b/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, + }) +} diff --git a/api/sites/router.go b/api/sites/router.go index 2a2f3381..a604e77c 100644 --- a/api/sites/router.go +++ b/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) +} diff --git a/api/system/install.go b/api/system/install.go index 94fc52c7..1d86c101 100644 --- a/api/system/install.go +++ b/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() diff --git a/api/system/upgrade.go b/api/system/upgrade.go index 1b245e69..3dbd3478 100644 --- a/api/system/upgrade.go +++ b/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 } diff --git a/api/terminal/pty.go b/api/terminal/pty.go index c8cde40b..c7abf154 100644 --- a/api/terminal/pty.go +++ b/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" diff --git a/api/upstream/upstream.go b/api/upstream/upstream.go index 0839b10b..64a6ee86 100644 --- a/api/upstream/upstream.go +++ b/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" diff --git a/api/user/auth.go b/api/user/auth.go index 28d618cd..d3565ceb 100644 --- a/api/user/auth.go +++ b/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" diff --git a/api/user/otp.go b/api/user/otp.go index 26ee3356..368c211c 100644 --- a/api/user/otp.go +++ b/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", }) diff --git a/api/user/passkey.go b/api/user/passkey.go index a79174db..c27260e3 100644 --- a/api/user/passkey.go +++ b/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" diff --git a/api/user/user.go b/api/user/user.go index 4080dce5..bfbe9ecc 100644 --- a/api/user/user.go +++ b/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", }) diff --git a/app/src/components/StdDesign/types.d.ts b/app/src/components/StdDesign/types.d.ts index 05bc76bd..c8053e43 100644 --- a/app/src/components/StdDesign/types.d.ts +++ b/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 diff --git a/app/src/views/certificate/ACMEUser.vue b/app/src/views/certificate/ACMEUser.vue index 7c88efcc..3d7a38ca 100644 --- a/app/src/views/certificate/ACMEUser.vue +++ b/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 {$gettext('Invalid')} }, - 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'), diff --git a/app/src/views/certificate/CertificateList/certColumns.tsx b/app/src/views/certificate/CertificateList/certColumns.tsx index 8211c5f5..289e10b4 100644 --- a/app/src/views/certificate/CertificateList/certColumns.tsx +++ b/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'), diff --git a/app/src/views/certificate/DNSCredential.vue b/app/src/views/certificate/DNSCredential.vue index 10c7d41d..d9d080cf 100644 --- a/app/src/views/certificate/DNSCredential.vue +++ b/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'), diff --git a/app/src/views/environment/envColumns.tsx b/app/src/views/environment/envColumns.tsx index da594971..58f7af57 100644 --- a/app/src/views/environment/envColumns.tsx +++ b/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, }, { diff --git a/app/src/views/notification/notificationColumns.tsx b/app/src/views/notification/notificationColumns.tsx index 3be96594..5a997994 100644 --- a/app/src/views/notification/notificationColumns.tsx +++ b/app/src/views/notification/notificationColumns.tsx @@ -30,7 +30,7 @@ const columns: Column[] = [{ } }, - 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, }, { diff --git a/app/src/views/site/SiteList.vue b/app/src/views/site/SiteList.vue index 9a5a24db..40a863f8 100644 --- a/app/src/views/site/SiteList.vue +++ b/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'), diff --git a/app/src/views/stream/StreamList.vue b/app/src/views/stream/StreamList.vue index f751e7c1..244c65aa 100644 --- a/app/src/views/stream/StreamList.vue +++ b/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'), diff --git a/app/src/views/user/userColumns.tsx b/app/src/views/user/userColumns.tsx index 67b6e1f5..24eac21f 100644 --- a/app/src/views/user/userColumns.tsx +++ b/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'), diff --git a/go.mod b/go.mod index 4d600b92..4ac64e22 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index ee6b8a30..9a17ffe0 100644 --- a/go.sum +++ b/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= diff --git a/img.png b/img.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c9d3fbd826974d2279bd7afc8f90e6e1910649 GIT binary patch literal 40441 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 YMH9ZEzc%n|G690VXl78Q?-uj_0O$VRU;qFB literal 0 HcmV?d00001 diff --git a/install.sh b/install.sh index eb968cf3..715a5738 100644 --- a/install.sh +++ b/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 diff --git a/internal/analytic/analytic.go b/internal/analytic/analytic.go index a5a26461..1e8f0b60 100644 --- a/internal/analytic/analytic.go +++ b/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" ) diff --git a/internal/analytic/node.go b/internal/analytic/node.go index 16c8c232..57ba06a4 100644 --- a/internal/analytic/node.go +++ b/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" diff --git a/internal/analytic/node_record.go b/internal/analytic/node_record.go index 65da0c64..9aabfc32 100644 --- a/internal/analytic/node_record.go +++ b/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" diff --git a/internal/analytic/node_stat.go b/internal/analytic/node_stat.go index 7a46d08e..beb0964c 100644 --- a/internal/analytic/node_stat.go +++ b/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" diff --git a/internal/analytic/record.go b/internal/analytic/record.go index bd941241..8bdf6f51 100644 --- a/internal/analytic/record.go +++ b/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" diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 597cfe7d..f8a9d4d9 100644 --- a/internal/cache/cache.go +++ b/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" ) diff --git a/internal/cert/auto_cert.go b/internal/cert/auto_cert.go index c1c96e01..8a5c73d7 100644 --- a/internal/cert/auto_cert.go +++ b/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 } diff --git a/internal/cert/cert.go b/internal/cert/cert.go index 0a1efd1d..b88cf8d4 100644 --- a/internal/cert/cert.go +++ b/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), ) } diff --git a/internal/cert/logger.go b/internal/cert/logger.go index 8c84116a..81323bb9 100644 --- a/internal/cert/logger.go +++ b/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" diff --git a/internal/cert/payload.go b/internal/cert/payload.go index 8127668a..781123e4 100644 --- a/internal/cert/payload.go +++ b/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" diff --git a/internal/cert/register.go b/internal/cert/register.go index 3cddd7ea..82f621f6 100644 --- a/internal/cert/register.go +++ b/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") diff --git a/internal/cert/sync.go b/internal/cert/sync.go index 9991e69a..b03cb9ec 100644 --- a/internal/cert/sync.go +++ b/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" diff --git a/internal/chatbot/context.go b/internal/chatbot/context.go index f2703815..cbc3bf5c 100644 --- a/internal/chatbot/context.go +++ b/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" diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index b7ff216f..0309855b 100644 --- a/internal/cluster/cluster.go +++ b/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" diff --git a/internal/config/sync.go b/internal/config/sync.go index 76080815..8828a25a 100644 --- a/internal/config/sync.go +++ b/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}, }, } diff --git a/internal/cosy/cosy.go b/internal/cosy/cosy.go deleted file mode 100644 index 282b6f59..00000000 --- a/internal/cosy/cosy.go +++ /dev/null @@ -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 -} diff --git a/internal/cosy/create.go b/internal/cosy/create.go deleted file mode 100644 index b29ae7c4..00000000 --- a/internal/cosy/create.go +++ /dev/null @@ -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 -} diff --git a/internal/cosy/custom.go b/internal/cosy/custom.go deleted file mode 100644 index 5fd847be..00000000 --- a/internal/cosy/custom.go +++ /dev/null @@ -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) -} diff --git a/internal/cosy/delete.go b/internal/cosy/delete.go deleted file mode 100644 index 82b0e7c6..00000000 --- a/internal/cosy/delete.go +++ /dev/null @@ -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) -} diff --git a/internal/cosy/error.go b/internal/cosy/error.go deleted file mode 100644 index caa5a5ba..00000000 --- a/internal/cosy/error.go +++ /dev/null @@ -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(), - }) -} diff --git a/internal/cosy/filter.go b/internal/cosy/filter.go deleted file mode 100644 index 25bd36fc..00000000 --- a/internal/cosy/filter.go +++ /dev/null @@ -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 -} diff --git a/internal/cosy/hook.go b/internal/cosy/hook.go deleted file mode 100644 index e409971d..00000000 --- a/internal/cosy/hook.go +++ /dev/null @@ -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 -} diff --git a/internal/cosy/list.go b/internal/cosy/list.go deleted file mode 100644 index bbfd5143..00000000 --- a/internal/cosy/list.go +++ /dev/null @@ -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) -} diff --git a/internal/cosy/map2struct/hook.go b/internal/cosy/map2struct/hook.go deleted file mode 100644 index 50161615..00000000 --- a/internal/cosy/map2struct/hook.go +++ /dev/null @@ -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 - } -} diff --git a/internal/cosy/map2struct/map2struct.go b/internal/cosy/map2struct/map2struct.go deleted file mode 100644 index 49f4f4cd..00000000 --- a/internal/cosy/map2struct/map2struct.go +++ /dev/null @@ -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) -} diff --git a/internal/cosy/order.go b/internal/cosy/order.go deleted file mode 100644 index 4f6b4ac1..00000000 --- a/internal/cosy/order.go +++ /dev/null @@ -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) -} diff --git a/internal/cosy/sort.go b/internal/cosy/sort.go deleted file mode 100644 index 20634427..00000000 --- a/internal/cosy/sort.go +++ /dev/null @@ -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) - } -} diff --git a/internal/cosy/update.go b/internal/cosy/update.go deleted file mode 100644 index 19e91477..00000000 --- a/internal/cosy/update.go +++ /dev/null @@ -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) - } -} diff --git a/internal/cron/cron.go b/internal/cron/cron.go index decda2e2..98721dfd 100644 --- a/internal/cron/cron.go +++ b/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" diff --git a/internal/helper/directory.go b/internal/helper/directory.go index fef5b90a..b710e83e 100644 --- a/internal/helper/directory.go +++ b/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" ) diff --git a/internal/helper/hash.go b/internal/helper/hash.go index 86959e6a..3d5a82ce 100644 --- a/internal/helper/hash.go +++ b/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" ) diff --git a/internal/kernal/boot.go b/internal/kernal/boot.go index 20ea8359..a2256a82 100644 --- a/internal/kernal/boot.go +++ b/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") } } diff --git a/internal/kernal/register_acme_user.go b/internal/kernal/register_acme_user.go index 89b141ca..da2cadd8 100644 --- a/internal/kernal/register_acme_user.go +++ b/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" ) diff --git a/internal/kernal/skip_install.go b/internal/kernal/skip_install.go index 907b3298..bc146467 100644 --- a/internal/kernal/skip_install.go +++ b/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{} diff --git a/internal/logrotate/logrotate.go b/internal/logrotate/logrotate.go index 3036ea8f..51dda63b 100644 --- a/internal/logrotate/logrotate.go +++ b/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" diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 1f946442..1c250dd2 100644 --- a/internal/middleware/middleware.go +++ b/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 { diff --git a/internal/middleware/proxy.go b/internal/middleware/proxy.go index ef9914a6..2fd9c1d9 100644 --- a/internal/middleware/proxy.go +++ b/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" diff --git a/internal/middleware/proxy_ws.go b/internal/middleware/proxy_ws.go index 24b55d25..0dfc14b3 100644 --- a/internal/middleware/proxy_ws.go +++ b/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" diff --git a/internal/nginx/config_args.go b/internal/nginx/config_args.go index e6f71b31..bb7d15bb 100644 --- a/internal/nginx/config_args.go +++ b/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" diff --git a/internal/passkey/webauthn.go b/internal/passkey/webauthn.go index cb47294c..e71d93a8 100644 --- a/internal/passkey/webauthn.go +++ b/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 } diff --git a/internal/pty/pipeline.go b/internal/pty/pipeline.go index 80f821a7..8a9526ae 100644 --- a/internal/pty/pipeline.go +++ b/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 { diff --git a/internal/template/template.go b/internal/template/template.go index eeba0471..1c8acdf5 100644 --- a/internal/template/template.go +++ b/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 { diff --git a/internal/transport/transport.go b/internal/transport/transport.go index cb499b32..7abcc38f 100644 --- a/internal/transport/transport.go +++ b/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 { diff --git a/internal/upgrader/upgrade.go b/internal/upgrader/upgrade.go index cad1a2ae..6ce42e73 100644 --- a/internal/upgrader/upgrade.go +++ b/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 diff --git a/internal/user/user.go b/internal/user/user.go index be26be7e..10581ab6 100644 --- a/internal/user/user.go +++ b/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 { diff --git a/internal/validation/validation.go b/internal/validation/validation.go index 07b60ac2..769bd60e 100644 --- a/internal/validation/validation.go +++ b/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" ) diff --git a/main.go b/main.go index bff525c5..d33be71a 100644 --- a/main.go +++ b/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, }) } diff --git a/model/config_backup.go b/model/config_backup.go index 7e76ff90..3192a0eb 100644 --- a/model/config_backup.go +++ b/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" ) diff --git a/model/model.go b/model/model.go index fd601e1e..bf5392e6 100644 --- a/model/model.go +++ b/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"` diff --git a/model/site_category.go b/model/site_category.go new file mode 100644 index 00000000..036b4638 --- /dev/null +++ b/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"` +} diff --git a/router/routers.go b/router/routers.go index 32bb1742..5f1111e4 100644 --- a/router/routers.go +++ b/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 } diff --git a/settings/app.testing.ini b/settings/app.testing.ini new file mode 100644 index 00000000..76d3b1c4 --- /dev/null +++ b/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 diff --git a/settings/auth.go b/settings/auth.go index cf75c7b4..8c2a717c 100644 --- a/settings/auth.go +++ b/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, } diff --git a/settings/casdoor.go b/settings/casdoor.go index f9f58406..4dc1054a 100644 --- a/settings/casdoor.go +++ b/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: "", diff --git a/settings/cert.go b/settings/cert.go new file mode 100644 index 00000000..19eba1bf --- /dev/null +++ b/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 +} diff --git a/settings/cluster.go b/settings/cluster.go index d86ec370..dc7e603e 100644 --- a/settings/cluster.go +++ b/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) } diff --git a/settings/cluster_test.go b/settings/cluster_test.go deleted file mode 100644 index 235b47b6..00000000 --- a/settings/cluster_test.go +++ /dev/null @@ -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) -} diff --git a/settings/crypto.go b/settings/crypto.go index 57d5e0c6..a4c9d093 100644 --- a/settings/crypto.go +++ b/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)) diff --git a/settings/crypto_test.go b/settings/crypto_test.go index db10bae5..945879cb 100644 --- a/settings/crypto_test.go +++ b/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" diff --git a/settings/http.go b/settings/http.go new file mode 100644 index 00000000..022b6f30 --- /dev/null +++ b/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, +} diff --git a/settings/logrotate.go b/settings/logrotate.go index 4390b154..4f3d5a1a 100644 --- a/settings/logrotate.go +++ b/settings/logrotate.go @@ -6,7 +6,7 @@ type Logrotate struct { Interval int `json:"interval"` } -var LogrotateSettings = Logrotate{ +var LogrotateSettings = &Logrotate{ Enabled: false, CMD: "logrotate /etc/logrotate.d/nginx", Interval: 1440, // 24 hours diff --git a/settings/nginx.go b/settings/nginx.go index 9be09184..51a1d923 100644 --- a/settings/nginx.go +++ b/settings/nginx.go @@ -11,7 +11,7 @@ type Nginx struct { RestartCmd string `json:"restart_cmd" protected:"true"` } -var NginxSettings = Nginx{ +var NginxSettings = &Nginx{ AccessLogPath: "", ErrorLogPath: "", } diff --git a/settings/node.go b/settings/node.go new file mode 100644 index 00000000..a0890c82 --- /dev/null +++ b/settings/node.go @@ -0,0 +1,15 @@ +package settings + +type Node struct { + Name string `json:"name" binding:"omitempty,safety_text"` + Secret string `json:"secret" protected:"true"` + SkipInstallation bool `json:"skip_installation" protected:"true"` + Demo bool `json:"demo" protected:"true"` +} + +var NodeSettings = &Node{ + Name: "", + Secret: "", + SkipInstallation: false, + Demo: false, +} diff --git a/settings/openai.go b/settings/openai.go index 66eaa47f..c5a119a9 100644 --- a/settings/openai.go +++ b/settings/openai.go @@ -7,4 +7,4 @@ type OpenAI struct { Model string `json:"model" binding:"omitempty,safety_text"` } -var OpenAISettings = OpenAI{} +var OpenAISettings = &OpenAI{} diff --git a/settings/server.go b/settings/server.go deleted file mode 100644 index 7f2d303a..00000000 --- a/settings/server.go +++ /dev/null @@ -1,63 +0,0 @@ -package settings - -import ( - "github.com/go-acme/lego/v4/lego" -) - -type Server struct { - HttpHost string `json:"http_host" protected:"true"` - HttpPort string `json:"http_port" protected:"true"` - RunMode string `json:"run_mode" protected:"true"` - JwtSecret string `json:"jwt_secret" protected:"true"` - NodeSecret string `json:"node_secret" protected:"true"` - HTTPChallengePort string `json:"http_challenge_port"` - Email string `json:"email" protected:"true"` - Database string `json:"database" protected:"true"` - StartCmd string `json:"start_cmd" protected:"true"` - CADir string `json:"ca_dir" binding:"omitempty,url"` - Demo bool `json:"demo" protected:"true"` - PageSize int `json:"page_size" protected:"true"` - GithubProxy string `json:"github_proxy" binding:"omitempty,url"` - CertRenewalInterval int `json:"cert_renewal_interval" binding:"min=7,max=21"` - RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"` - SkipInstallation bool `json:"skip_installation" protected:"true"` - InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"` - Name string `json:"name" binding:"omitempty,safety_text"` -} - -func (s *Server) GetCADir() string { - if s.Demo { - return lego.LEDirectoryStaging - } - - if s.CADir != "" { - return s.CADir - } - - return lego.LEDirectoryProduction -} - -func (s *Server) GetCertRenewalInterval() int { - if s.CertRenewalInterval < 7 { - return 7 - } - if s.CertRenewalInterval > 21 { - return 21 - } - return s.CertRenewalInterval -} - -var ServerSettings = Server{ - HttpHost: "0.0.0.0", - HttpPort: "9000", - RunMode: "debug", - HTTPChallengePort: "9180", - Database: "database", - StartCmd: "login", - Demo: false, - PageSize: 10, - CADir: "", - GithubProxy: "", - CertRenewalInterval: 7, - RecursiveNameservers: make([]string, 0), -} diff --git a/settings/server_v1.go b/settings/server_v1.go new file mode 100644 index 00000000..3f1118b7 --- /dev/null +++ b/settings/server_v1.go @@ -0,0 +1,227 @@ +package settings + +import ( + "github.com/elliotchance/orderedmap/v2" + "github.com/spf13/cast" + "github.com/uozi-tech/cosy/logger" + "github.com/uozi-tech/cosy/settings" + "gopkg.in/ini.v1" + "os" + "reflect" +) + +// Note: This section will be deprecated in the future version. + +type serverV1 struct { + HttpHost string `json:"http_host" protected:"true"` + HttpPort string `json:"http_port" protected:"true"` + RunMode string `json:"run_mode" protected:"true"` + JwtSecret string `json:"jwt_secret" protected:"true"` + NodeSecret string `json:"node_secret" protected:"true"` + HTTPChallengePort string `json:"http_challenge_port"` + Email string `json:"email" protected:"true"` + Database string `json:"database" protected:"true"` + StartCmd string `json:"start_cmd" protected:"true"` + CADir string `json:"ca_dir"` + Demo bool `json:"demo" protected:"true"` + PageSize int `json:"page_size" protected:"true"` + GithubProxy string `json:"github_proxy"` + CertRenewalInterval int `json:"cert_renewal_interval"` + RecursiveNameservers []string `json:"recursive_nameservers"` + SkipInstallation bool `json:"skip_installation" protected:"true"` + InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"` + Name string `json:"name"` +} + +type settingsV2 struct { + // Cosy + App settings.App + Server settings.Server + DataBase settings.DataBase + // Nginx UI + Auth Auth + Casdoor Casdoor + Cert Cert + Cluster Cluster + Crypto Crypto + Http HTTP + Logrotate Logrotate + Nginx Nginx + Node Node + OpenAI OpenAI + Terminal Terminal + WebAuthn WebAuthn +} + +func (v1 *serverV1) migrateToV2() (v2 *settingsV2) { + v2 = &settingsV2{} + v2.Server.Host = v1.HttpHost + v2.Server.Port = cast.ToUint(v1.HttpPort) + v2.Server.RunMode = v1.RunMode + v2.App.JwtSecret = v1.JwtSecret + v2.App.PageSize = v1.PageSize + v2.Node.Secret = v1.NodeSecret + v2.Cert.HTTPChallengePort = v1.HTTPChallengePort + v2.Cert.Email = v1.Email + v2.DataBase.Name = v1.Database + v2.Terminal.StartCmd = v1.StartCmd + v2.Cert.CADir = v1.CADir + v2.Node.Demo = v1.Demo + v2.Http.GithubProxy = v1.GithubProxy + v2.Cert.RenewalInterval = v1.CertRenewalInterval + v2.Cert.RecursiveNameservers = v1.RecursiveNameservers + v2.Node.SkipInstallation = v1.SkipInstallation + v2.Http.InsecureSkipVerify = v1.InsecureSkipVerify + v2.Node.Name = v1.Name + + return +} + +func isZeroValue(v reflect.Value) bool { + zeroValue := reflect.Zero(v.Type()).Interface() + return reflect.DeepEqual(v.Interface(), zeroValue) +} + +func mergeStructs(src, dst interface{}) { + dstVal := reflect.ValueOf(dst).Elem() + srcVal := reflect.ValueOf(src).Elem() + + for i := 0; i < dstVal.NumField(); i++ { + dstField := dstVal.Field(i) + srcField := srcVal.Field(i) + if isZeroValue(dstField) { + dstField.Set(srcField) + } + } + return +} + +func Migrate(confPath string) { + logger.Init("debug") + Conf, err := ini.LoadSources(ini.LoadOptions{ + Loose: true, + AllowShadows: true, + }, confPath) + if err != nil { + logger.Fatalf("setting.init, fail to parse 'app.ini': %v", err) + } + + var v1 = &serverV1{} + err = Conf.Section("server").MapTo(v1) + if err != nil { + logger.Error(err) + return + } + + // If settings is v1, jwt_secret is not empty. + if v1.JwtSecret == "" { + return + } + + // Cosy + app := &settings.App{} + server := &settings.Server{} + database := &settings.DataBase{} + // Nginx UI + auth := &Auth{} + casdoor := &Casdoor{} + cert := &Cert{} + cluster := &Cluster{} + crypto := &Crypto{} + http := &HTTP{} + logrotate := &Logrotate{} + nginx := &Nginx{} + node := &Node{} + openai := &OpenAI{} + terminal := &Terminal{} + webauthn := &WebAuthn{} + + var migrated = orderedmap.NewOrderedMap[string, any]() + migrated.Set("app", app) + migrated.Set("server", server) + migrated.Set("database", database) + migrated.Set("auth", auth) + migrated.Set("casdoor", casdoor) + migrated.Set("cert", cert) + migrated.Set("cluster", cluster) + migrated.Set("crypto", crypto) + migrated.Set("http", http) + migrated.Set("logrotate", logrotate) + migrated.Set("nginx", nginx) + migrated.Set("node", node) + migrated.Set("openai", openai) + migrated.Set("terminal", terminal) + migrated.Set("webauthn", webauthn) + + for name, ptr := range migrated.Iterator() { + err = Conf.Section(name).MapTo(ptr) + if err != nil { + logger.Error("Migrate.MapTo %s err: %v", name, err) + } + } + + v2 := v1.migrateToV2() + + mergeStructs(&v2.App, app) + mergeStructs(&v2.Server, server) + mergeStructs(&v2.DataBase, database) + mergeStructs(&v2.Auth, auth) + mergeStructs(&v2.Casdoor, casdoor) + mergeStructs(&v2.Cert, cert) + mergeStructs(&v2.Cluster, cluster) + mergeStructs(&v2.Crypto, crypto) + mergeStructs(&v2.Http, http) + mergeStructs(&v2.Logrotate, logrotate) + mergeStructs(&v2.Nginx, nginx) + mergeStructs(&v2.Node, node) + mergeStructs(&v2.OpenAI, openai) + mergeStructs(&v2.Terminal, terminal) + mergeStructs(&v2.WebAuthn, webauthn) + + Conf = ini.Empty() + + for section, ptr := range migrated.Iterator() { + err = Conf.Section(section).ReflectFrom(ptr) + if err != nil { + logger.Fatalf("Migrate.ReflectFrom %s err: %v", section, err) + } + } + + err = Conf.SaveTo(confPath) + if err != nil { + logger.Fatalf("Fail to save the migrated settings: %v", err) + return + } + + migrateEnv() +} + +func migrateEnv() { + deprecated := orderedmap.NewOrderedMap[string, string]() + deprecated.Set("SERVER_HTTP_HOST", "SERVER_HOST") + deprecated.Set("SERVER_HTTP_PORT", "SERVER_PORT") + deprecated.Set("SERVER_JWT_SECRET", "APP_JWT_SECRET") + deprecated.Set("SERVER_NODE_SECRET", "NODE_SECRET") + deprecated.Set("SERVER_HTTP_CHALLENGE_PORT", "CERT_HTTP_CHALLENGE_PORT") + deprecated.Set("SERVER_EMAIL", "CERT_EMAIL") + deprecated.Set("SERVER_DATABASE", "DATABASE_NAME") + deprecated.Set("SERVER_START_CMD", "TERMINAL_START_CMD") + deprecated.Set("SERVER_CA_DIR", "CERT_CA_DIR") + deprecated.Set("SERVER_DEMO", "NODE_DEMO") + deprecated.Set("SERVER_PAGE_SIZE", "APP_PAGE_SIZE") + deprecated.Set("SERVER_GITHUB_PROXY", "HTTP_GITHUB_PROXY") + deprecated.Set("SERVER_CERT_RENEWAL_INTERVAL", "CERT_RENEWAL_INTERVAL") + deprecated.Set("SERVER_RECURSIVE_NAMESERVERS", "CERT_RECURSIVE_NAMESERVERS") + deprecated.Set("SERVER_SKIP_INSTALLATION", "NODE_SKIP_INSTALLATION") + deprecated.Set("SERVER_NAME", "NODE_NAME") + + for d, n := range deprecated.Iterator() { + oldValue := os.Getenv(EnvPrefix + d) + if oldValue != "" { + _ = os.Setenv(EnvPrefix+n, oldValue) + logger.Warnf("The environment variable %s is deprecated and has been automatically migrated to %s. "+ + "Please update your environment variables as automatic migration may be removed in the future.", + EnvPrefix+d, EnvPrefix+n) + } + } +} diff --git a/settings/server_v1_test.go b/settings/server_v1_test.go new file mode 100644 index 00000000..ce29093e --- /dev/null +++ b/settings/server_v1_test.go @@ -0,0 +1,125 @@ +package settings + +import ( + "github.com/stretchr/testify/assert" + "github.com/uozi-tech/cosy/logger" + "os" + "testing" +) + +func TestDeprecatedEnvMigration(t *testing.T) { + logger.Init("debug") + // Deprecated + _ = os.Setenv("NGINX_UI_SERVER_HTTP_HOST", "127.0.0.1") + _ = os.Setenv("NGINX_UI_SERVER_HTTP_PORT", "8080") + // _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "testing") + _ = os.Setenv("NGINX_UI_SERVER_JWT_SECRET", "newSecret123") + _ = os.Setenv("NGINX_UI_SERVER_NODE_SECRET", "newSercet123") + _ = os.Setenv("NGINX_UI_SERVER_HTTP_CHALLENGE_PORT", "9181") + _ = os.Setenv("NGINX_UI_SERVER_EMAIL", "test") + _ = os.Setenv("NGINX_UI_SERVER_DATABASE", "testDB") + _ = os.Setenv("NGINX_UI_SERVER_START_CMD", "start") + _ = os.Setenv("NGINX_UI_SERVER_CA_DIR", "/test/ca") + _ = os.Setenv("NGINX_UI_SERVER_DEMO", "true") + _ = os.Setenv("NGINX_UI_SERVER_PAGE_SIZE", "20") + _ = os.Setenv("NGINX_UI_SERVER_GITHUB_PROXY", "http://proxy.example.com") + _ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14") + _ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8,1.1.1.1") + _ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true") + _ = os.Setenv("NGINX_UI_SERVER_NAME", "test") + + migrateEnv() + + assert.Equal(t, "127.0.0.1", os.Getenv("NGINX_UI_SERVER_HOST")) + assert.Equal(t, "8080", os.Getenv("NGINX_UI_SERVER_PORT")) + // assert.Equal(t, "testing", os.Getenv("NGINX_UI_SERVER_RUN_MODE")) + assert.Equal(t, "newSecret123", os.Getenv("NGINX_UI_APP_JWT_SECRET")) + assert.Equal(t, "newSercet123", os.Getenv("NGINX_UI_NODE_SECRET")) + assert.Equal(t, "9181", os.Getenv("NGINX_UI_CERT_HTTP_CHALLENGE_PORT")) + assert.Equal(t, "test", os.Getenv("NGINX_UI_CERT_EMAIL")) + assert.Equal(t, "testDB", os.Getenv("NGINX_UI_DATABASE_NAME")) + assert.Equal(t, "start", os.Getenv("NGINX_UI_TERMINAL_START_CMD")) + assert.Equal(t, "/test/ca", os.Getenv("NGINX_UI_CERT_CA_DIR")) + assert.Equal(t, "true", os.Getenv("NGINX_UI_NODE_DEMO")) + assert.Equal(t, "20", os.Getenv("NGINX_UI_APP_PAGE_SIZE")) + assert.Equal(t, "http://proxy.example.com", os.Getenv("NGINX_UI_HTTP_GITHUB_PROXY")) + assert.Equal(t, "14", os.Getenv("NGINX_UI_CERT_RENEWAL_INTERVAL")) + assert.Equal(t, "8.8.8.8,1.1.1.1", os.Getenv("NGINX_UI_CERT_RECURSIVE_NAMESERVERS")) + assert.Equal(t, "true", os.Getenv("NGINX_UI_NODE_SKIP_INSTALLATION")) + assert.Equal(t, "test", os.Getenv("NGINX_UI_NODE_NAME")) +} + +func TestMigration(t *testing.T) { + const confName = "app.testing.ini" + confText := `[server] +HttpPort = 9000 +RunMode = debug +JwtSecret = newSecret +Email = test +HTTPChallengePort = 9181 +StartCmd = bash +Database = database +CADir = /test +GithubProxy = https://mirror.ghproxy.com/ +Secret = newSecret +Demo = false +PageSize = 20 +HttpHost = 0.0.0.0 +RenewalInterval = 7 +RecursiveNameservers = 8.8.8.8,1.1.1.1 +SkipInstallation = false +Name = Local +InsecureSkipVerify = true + +[nginx] +AccessLogPath = +ErrorLogPath = +ConfigDir = +PIDPath = +ReloadCmd = +RestartCmd = +TestConfigCmd = +LogDirWhiteList = /var/log/nginx + +[openai] +Model = gpt-4o +BaseUrl = +Proxy = +Token = + +[casdoor] +Endpoint = http://127.0.0.1:8001 +ClientId = 1234567890qwertyuiop +ClientSecret = 1234567890qwertyuiop1234567890qwertyuiop +CertificatePath = ./casdoor.pub +Organization = built-in +Application = nginx-ui-dev +RedirectUri = + +[logrotate] +Enabled = true +CMD = logrotate /etc/logrotate.d/nginx +Interval = 1440 + +[cluster] +Node = http://10.0.0.1:9000?name=test&node_secret=asdfghjklqwertyuiopzxcvbnm&enabled=true + +[auth] +IPWhiteList = 127.0.0.1 +BanThresholdMinutes = 10 +MaxAttempts = 10 + +[crypto] +Secret = 12345678901234567890 + +[webauthn] +RPDisplayName = Nginx UI +RPID = localhost +RPOrigins = http://localhost:3002,http://127.0.0.1:3002` + err := os.WriteFile(confName, []byte(confText), 0644) + if err != nil { + t.Fatalf("Failed to write config to file: %v", err) + } + + Migrate(confName) +} diff --git a/settings/settings.go b/settings/settings.go index cf9aa264..099a9b18 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -2,11 +2,11 @@ package settings import ( "github.com/caarlos0/env/v11" + "github.com/elliotchance/orderedmap/v2" "github.com/spf13/cast" - "gopkg.in/ini.v1" + "github.com/uozi-tech/cosy/settings" "log" "os" - "reflect" "strings" "time" ) @@ -14,60 +14,59 @@ import ( var ( buildTime string LastModified string - - Conf *ini.File - ConfPath string - EnvPrefix = "NGINX_UI_" + EnvPrefix = "NGINX_UI_" ) -var sections = map[string]interface{}{ - "server": &ServerSettings, - "nginx": &NginxSettings, - "openai": &OpenAISettings, - "casdoor": &CasdoorSettings, - "logrotate": &LogrotateSettings, - "cluster": &ClusterSettings, - "auth": &AuthSettings, - "crypto": &CryptoSettings, - "webauthn": &WebAuthnSettings, +var sections = orderedmap.NewOrderedMap[string, any]() + +var envPrefixMap = map[string]interface{}{ + // Cosy + "APP": settings.AppSettings, + "SERVER": settings.ServerSettings, + "DB": settings.DataBaseSettings, + // Nginx UI + "AUTH": AuthSettings, + "CASDOOR": CasdoorSettings, + "CERT": CertSettings, + "CLUSTER": ClusterSettings, + "CRYPTO": CryptoSettings, + "HTTP": HTTPSettings, + "LOGROTATE": LogrotateSettings, + "NGINX": NginxSettings, + "NODE": NodeSettings, + "OPENAI": OpenAISettings, + "TERMINAL": TerminalSettings, + "WEBAUTHN": WebAuthnSettings, } func init() { t := time.Unix(cast.ToInt64(buildTime), 0) LastModified = strings.ReplaceAll(t.Format(time.RFC1123), "UTC", "GMT") -} -func Init(confPath string) { - ConfPath = confPath - Setup() -} + sections.Set("auth", AuthSettings) + sections.Set("casdoor", CasdoorSettings) + sections.Set("cert", CertSettings) + sections.Set("cluster", ClusterSettings) + sections.Set("crypto", CryptoSettings) + sections.Set("http", HTTPSettings) + sections.Set("logrotate", LogrotateSettings) + sections.Set("nginx", NginxSettings) + sections.Set("node", NodeSettings) + sections.Set("openai", OpenAISettings) + sections.Set("terminal", TerminalSettings) + sections.Set("webauthn", WebAuthnSettings) -func load() (err error) { - Conf, err = ini.LoadSources(ini.LoadOptions{ - Loose: true, - AllowShadows: true, - }, ConfPath) - - return -} - -func Setup() { - err := load() - - if err != nil { - log.Fatalf("settings.Setup: %v\n", err) + for k, v := range sections.Iterator() { + settings.Register(k, v) } + settings.WithoutRedis() + settings.WithoutSonyflake() +} - MapTo() - - parseEnv(&ServerSettings, "SERVER_") - parseEnv(&NginxSettings, "NGINX_") - parseEnv(&OpenAISettings, "OPENAI_") - parseEnv(&CasdoorSettings, "CASDOOR_") - parseEnv(&LogrotateSettings, "LOGROTATE_") - parseEnv(&AuthSettings, "AUTH_") - parseEnv(&CryptoSettings, "CRYPTO_") - parseEnv(&WebAuthnSettings, "WEBAUTHN_") +func Init() { + for prefix, ptr := range envPrefixMap { + parseEnv(ptr, prefix+"_") + } // if in official docker, set the restart cmd of nginx to "nginx -s stop", // then the supervisor of s6-overlay will start the nginx again. @@ -84,57 +83,19 @@ func Setup() { } } -func MapTo() { - for k, v := range sections { - err := mapTo(k, v) - - if err != nil { - log.Fatalf("Cfg.MapTo %s err: %v", k, err) - } - } -} - func Save() (err error) { - for k, v := range sections { - reflectFrom(k, v) - } - // fix unable to save empty slice - if len(ServerSettings.RecursiveNameservers) == 0 { - Conf.Section("server").Key("RecursiveNameservers").SetValue("") + if len(CertSettings.RecursiveNameservers) == 0 { + settings.Conf.Section("server").Key("RecursiveNameservers").SetValue("") } - err = Conf.SaveTo(ConfPath) + err = settings.Save() if err != nil { return } return } -func ProtectedFill(targetSettings interface{}, newSettings interface{}) { - s := reflect.TypeOf(targetSettings).Elem() - vt := reflect.ValueOf(targetSettings).Elem() - vn := reflect.ValueOf(newSettings).Elem() - - // copy the values from new to target settings if it is not protected - for i := 0; i < s.NumField(); i++ { - if s.Field(i).Tag.Get("protected") != "true" { - vt.Field(i).Set(vn.Field(i)) - } - } -} - -func mapTo(section string, v interface{}) error { - return Conf.Section(section).MapTo(v) -} - -func reflectFrom(section string, v interface{}) { - err := Conf.Section(section).ReflectFrom(v) - if err != nil { - log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err) - } -} - func parseEnv(ptr interface{}, prefix string) { err := env.ParseWithOptions(ptr, env.Options{ Prefix: EnvPrefix + prefix, diff --git a/settings/settings_test.go b/settings/settings_test.go index ccde9725..b7ad8250 100644 --- a/settings/settings_test.go +++ b/settings/settings_test.go @@ -2,32 +2,65 @@ package settings import ( "github.com/stretchr/testify/assert" + cSettings "github.com/uozi-tech/cosy/settings" "os" "testing" ) func TestSetup(t *testing.T) { - Init("../app.example.ini") - _ = os.Setenv("NGINX_UI_OFFICIAL_DOCKER", "true") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_PORT", "8080") - _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "test") - _ = os.Setenv("NGINX_UI_SERVER_JWT_SECRET", "newSecret123") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_CHALLENGE_PORT", "9181") - _ = os.Setenv("NGINX_UI_SERVER_START_CMD", "start") - _ = os.Setenv("NGINX_UI_SERVER_DATABASE", "testDB") - _ = os.Setenv("NGINX_UI_SERVER_CA_DIR", "/test/ca") - _ = os.Setenv("NGINX_UI_SERVER_GITHUB_PROXY", "http://proxy.example.com") - _ = os.Setenv("NGINX_UI_SERVER_NODE_SECRET", "nodeSecret") - _ = os.Setenv("NGINX_UI_SERVER_DEMO", "true") - _ = os.Setenv("NGINX_UI_SERVER_PAGE_SIZE", "20") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_HOST", "127.0.0.1") - _ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14") - _ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8") - _ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true") - _ = os.Setenv("NGINX_UI_SERVER_NAME", "test") + // Server + _ = os.Setenv("NGINX_UI_SERVER_HOST", "127.0.0.1") + _ = os.Setenv("NGINX_UI_SERVER_PORT", "8080") + _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "testing") + // App + _ = os.Setenv("NGINX_UI_APP_PAGE_SIZE", "20") + _ = os.Setenv("NGINX_UI_APP_JWT_SECRET", "newSecret123") + + // Database + _ = os.Setenv("NGINX_UI_DB_NAME", "testDB") + + // Auth + _ = os.Setenv("NGINX_UI_AUTH_IP_WHITE_LIST", "127.0.0.1,192.168.1.1") + _ = os.Setenv("NGINX_UI_AUTH_BAN_THRESHOLD_MINUTES", "20") + _ = os.Setenv("NGINX_UI_AUTH_MAX_ATTEMPTS", "20") + + // Casdoor + _ = os.Setenv("NGINX_UI_CASDOOR_ENDPOINT", "https://casdoor.example.com") + _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_ID", "clientId") + _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_SECRET", "clientSecret") + _ = os.Setenv("NGINX_UI_CASDOOR_CERTIFICATE_PATH", "cert.pem") + _ = os.Setenv("NGINX_UI_CASDOOR_ORGANIZATION", "org1") + _ = os.Setenv("NGINX_UI_CASDOOR_APPLICATION", "app1") + _ = os.Setenv("NGINX_UI_CASDOOR_REDIRECT_URI", "https://redirect.example.com") + + // Cert + _ = os.Setenv("NGINX_UI_CERT_EMAIL", "test") + _ = os.Setenv("NGINX_UI_CERT_CA_DIR", "/test/ca") + _ = os.Setenv("NGINX_UI_CERT_CERT_RENEWAL_INTERVAL", "14") + _ = os.Setenv("NGINX_UI_CERT_RECURSIVE_NAMESERVERS", "8.8.8.8,1.1.1.1") + _ = os.Setenv("NGINX_UI_CERT_HTTP_CHALLENGE_PORT", "1080") + + // Cluster + _ = os.Setenv("NGINX_UI_CLUSTER_NODE", + "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=false") + + // Crypto + _ = os.Setenv("NGINX_UI_CRYPTO_SECRET", "mySecret") + + // Http + _ = os.Setenv("NGINX_UI_HTTP_GITHUB_PROXY", "http://proxy.example.com") + _ = os.Setenv("NGINX_UI_HTTP_INSECURE_SKIP_VERIFY", "true") + + // Logrotate + _ = os.Setenv("NGINX_UI_LOGROTATE_ENABLED", "true") + _ = os.Setenv("NGINX_UI_LOGROTATE_CMD", "logrotate /custom/logrotate.conf") + _ = os.Setenv("NGINX_UI_LOGROTATE_INTERVAL", "60") + + // Nginx _ = os.Setenv("NGINX_UI_NGINX_ACCESS_LOG_PATH", "/tmp/nginx/access.log") _ = os.Setenv("NGINX_UI_NGINX_ERROR_LOG_PATH", "/tmp/nginx/error.log") _ = os.Setenv("NGINX_UI_NGINX_CONFIG_DIR", "/etc/nginx/conf") @@ -37,47 +70,81 @@ func TestSetup(t *testing.T) { _ = os.Setenv("NGINX_UI_NGINX_RESTART_CMD", "nginx -s restart") _ = os.Setenv("NGINX_UI_NGINX_LOG_DIR_WHITE_LIST", "/var/log/nginx") - _ = os.Setenv("NGINX_UI_OPENAI_MODEL", "davinci") + // Node + _ = os.Setenv("NGINX_UI_NODE_NAME", "test") + _ = os.Setenv("NGINX_UI_NODE_NODE_SECRET", "nodeSecret") + _ = os.Setenv("NGINX_UI_NODE_SKIP_INSTALLATION", "true") + _ = os.Setenv("NGINX_UI_NODE_DEMO", "true") + + // OpenAI + _ = os.Setenv("NGINX_UI_OPENAI_MODEL", "gpt4o") _ = os.Setenv("NGINX_UI_OPENAI_BASE_URL", "https://api.openai.com") _ = os.Setenv("NGINX_UI_OPENAI_PROXY", "https://proxy.openai.com") _ = os.Setenv("NGINX_UI_OPENAI_TOKEN", "token123") - _ = os.Setenv("NGINX_UI_CASDOOR_ENDPOINT", "https://casdoor.example.com") - _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_ID", "clientId") - _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_SECRET", "clientSecret") - _ = os.Setenv("NGINX_UI_CASDOOR_CERTIFICATE_PATH", "cert.pem") - _ = os.Setenv("NGINX_UI_CASDOOR_ORGANIZATION", "org1") - _ = os.Setenv("NGINX_UI_CASDOOR_APPLICATION", "app1") - _ = os.Setenv("NGINX_UI_CASDOOR_REDIRECT_URI", "https://redirect.example.com") - - _ = os.Setenv("NGINX_UI_LOGROTATE_ENABLED", "true") - _ = os.Setenv("NGINX_UI_LOGROTATE_CMD", "logrotate /custom/logrotate.conf") - _ = os.Setenv("NGINX_UI_LOGROTATE_INTERVAL", "60") + // Terminal + _ = os.Setenv("NGINX_UI_TERMINAL_START_CMD", "bash") + // WebAuthn _ = os.Setenv("NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME", "WebAuthn") _ = os.Setenv("NGINX_UI_WEBAUTHN_RPID", "localhost") _ = os.Setenv("NGINX_UI_WEBAUTHN_RP_ORIGINS", "http://localhost:3002") - ConfPath = "app.testing.ini" - Setup() + Init() - assert.Equal(t, "8080", ServerSettings.HttpPort) - assert.Equal(t, "test", ServerSettings.RunMode) - assert.Equal(t, "newSecret123", ServerSettings.JwtSecret) - assert.Equal(t, "9181", ServerSettings.HTTPChallengePort) - assert.Equal(t, "start", ServerSettings.StartCmd) - assert.Equal(t, "testDB", ServerSettings.Database) - assert.Equal(t, "/test/ca", ServerSettings.CADir) - assert.Equal(t, "http://proxy.example.com", ServerSettings.GithubProxy) - assert.Equal(t, "nodeSecret", ServerSettings.NodeSecret) - assert.Equal(t, true, ServerSettings.Demo) - assert.Equal(t, 20, ServerSettings.PageSize) - assert.Equal(t, "127.0.0.1", ServerSettings.HttpHost) - assert.Equal(t, 14, ServerSettings.CertRenewalInterval) - assert.Equal(t, []string{"8.8.8.8"}, ServerSettings.RecursiveNameservers) - assert.Equal(t, true, ServerSettings.SkipInstallation) - assert.Equal(t, "test", ServerSettings.Name) + // Server + assert.Equal(t, "127.0.0.1", cSettings.ServerSettings.Host) + assert.Equal(t, uint(8080), cSettings.ServerSettings.Port) + assert.Equal(t, "testing", cSettings.ServerSettings.RunMode) + // App + assert.Equal(t, 20, cSettings.AppSettings.PageSize) + assert.Equal(t, "newSecret123", cSettings.AppSettings.JwtSecret) + + // Database + assert.Equal(t, "testDB", cSettings.DataBaseSettings.Name) + + // Auth + assert.Equal(t, []string{"127.0.0.1", "192.168.1.1"}, AuthSettings.IPWhiteList) + assert.Equal(t, 20, AuthSettings.BanThresholdMinutes) + assert.Equal(t, 20, AuthSettings.MaxAttempts) + + // Casdoor + assert.Equal(t, "https://casdoor.example.com", CasdoorSettings.Endpoint) + assert.Equal(t, "clientId", CasdoorSettings.ClientId) + assert.Equal(t, "clientSecret", CasdoorSettings.ClientSecret) + assert.Equal(t, "cert.pem", CasdoorSettings.CertificatePath) + assert.Equal(t, "org1", CasdoorSettings.Organization) + assert.Equal(t, "app1", CasdoorSettings.Application) + assert.Equal(t, "https://redirect.example.com", CasdoorSettings.RedirectUri) + + // Cert + assert.Equal(t, "test", CertSettings.Email) + assert.Equal(t, "1080", CertSettings.HTTPChallengePort) + assert.Equal(t, "/test/ca", CertSettings.CADir) + assert.Equal(t, 14, CertSettings.RenewalInterval) + assert.Equal(t, []string{"8.8.8.8", "1.1.1.1"}, CertSettings.RecursiveNameservers) + + // Cluster + 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=false"}, + ClusterSettings.Node) + + // Crypto + assert.Equal(t, "mySecret", CryptoSettings.Secret) + + // Http + assert.Equal(t, "http://proxy.example.com", HTTPSettings.GithubProxy) + assert.Equal(t, true, HTTPSettings.InsecureSkipVerify) + + // Logrotate + assert.Equal(t, true, LogrotateSettings.Enabled) + assert.Equal(t, "logrotate /custom/logrotate.conf", LogrotateSettings.CMD) + assert.Equal(t, 60, LogrotateSettings.Interval) + + // Nginx assert.Equal(t, "/tmp/nginx/access.log", NginxSettings.AccessLogPath) assert.Equal(t, "/tmp/nginx/error.log", NginxSettings.ErrorLogPath) assert.Equal(t, "/etc/nginx/conf", NginxSettings.ConfigDir) @@ -87,27 +154,25 @@ func TestSetup(t *testing.T) { assert.Equal(t, "nginx -s stop", NginxSettings.RestartCmd) assert.Equal(t, []string{"/var/log/nginx"}, NginxSettings.LogDirWhiteList) - assert.Equal(t, "davinci", OpenAISettings.Model) + // Node + assert.Equal(t, "test", NodeSettings.Name) + assert.Equal(t, "nodeSecret", NodeSettings.Secret) + assert.Equal(t, true, NodeSettings.SkipInstallation) + assert.Equal(t, true, NodeSettings.Demo) + + // OpenAI + assert.Equal(t, "gpt4o", OpenAISettings.Model) assert.Equal(t, "https://api.openai.com", OpenAISettings.BaseUrl) assert.Equal(t, "https://proxy.openai.com", OpenAISettings.Proxy) assert.Equal(t, "token123", OpenAISettings.Token) - assert.Equal(t, "https://casdoor.example.com", CasdoorSettings.Endpoint) - assert.Equal(t, "clientId", CasdoorSettings.ClientId) - assert.Equal(t, "clientSecret", CasdoorSettings.ClientSecret) - assert.Equal(t, "cert.pem", CasdoorSettings.CertificatePath) - assert.Equal(t, "org1", CasdoorSettings.Organization) - assert.Equal(t, "app1", CasdoorSettings.Application) - assert.Equal(t, "https://redirect.example.com", CasdoorSettings.RedirectUri) - - assert.Equal(t, true, LogrotateSettings.Enabled) - assert.Equal(t, "logrotate /custom/logrotate.conf", LogrotateSettings.CMD) - assert.Equal(t, 60, LogrotateSettings.Interval) + // Terminal + assert.Equal(t, "bash", TerminalSettings.StartCmd) + // WebAuthn assert.Equal(t, "WebAuthn", WebAuthnSettings.RPDisplayName) assert.Equal(t, "localhost", WebAuthnSettings.RPID) assert.Equal(t, []string{"http://localhost:3002"}, WebAuthnSettings.RPOrigins) os.Clearenv() - _ = os.Remove("app.testing.ini") } diff --git a/settings/terminal.go b/settings/terminal.go new file mode 100644 index 00000000..bbae1a6c --- /dev/null +++ b/settings/terminal.go @@ -0,0 +1,7 @@ +package settings + +type Terminal struct { + StartCmd string `json:"start_cmd" protected:"true"` +} + +var TerminalSettings = &Terminal{} diff --git a/settings/webauthn.go b/settings/webauthn.go index 84e01b8b..e35d5acf 100644 --- a/settings/webauthn.go +++ b/settings/webauthn.go @@ -6,4 +6,4 @@ type WebAuthn struct { RPOrigins []string } -var WebAuthnSettings = WebAuthn{} +var WebAuthnSettings = &WebAuthn{}