diff --git a/go.mod b/go.mod index 83c74165..6841c300 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/mholt/acmez/v2 v2.0.3 github.com/orandin/slog-gorm v1.4.0 github.com/robfig/cron/v3 v3.0.1 + github.com/samber/do/v2 v2.0.0-beta.7 github.com/samber/lo v1.47.0 github.com/sethvargo/go-limiter v1.0.0 github.com/shirou/gopsutil v2.21.11+incompatible @@ -76,6 +77,7 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/samber/go-type-to-string v1.4.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1033 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1033 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect diff --git a/go.sum b/go.sum index ab76c63e..008f3a3a 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,10 @@ 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= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/samber/do/v2 v2.0.0-beta.7 h1:tmdLOVSCbTA6uGWLU5poi/nZvMRh5QxXFJ9vHytU+Jk= +github.com/samber/do/v2 v2.0.0-beta.7/go.mod h1:+LpV3vu4L81Q1JMZNSkMvSkW9lt4e5eJoXoZHkeBS4c= +github.com/samber/go-type-to-string v1.4.0 h1:KXphToZgiFdnJQxryU25brhlh/CqY/cwJVeX2rfmow0= +github.com/samber/go-type-to-string v1.4.0/go.mod h1:jpU77vIDoIxkahknKDoEx9C8bQ1ADnh2sotZ8I4QqBU= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/sethvargo/go-limiter v1.0.0 h1:JqW13eWEMn0VFv86OKn8wiYJY/m250WoXdrjRV0kLe4= diff --git a/internal/apps/fail2ban/service.go b/internal/apps/fail2ban/service.go index 58af5d98..cecefbc9 100644 --- a/internal/apps/fail2ban/service.go +++ b/internal/apps/fail2ban/service.go @@ -15,7 +15,6 @@ import ( "github.com/TheTNB/panel/internal/data" "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" - "github.com/TheTNB/panel/pkg/os" "github.com/TheTNB/panel/pkg/shell" ) @@ -55,7 +54,6 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { continue } jailEnabled := strings.Contains(jailRaw, "enabled = true") - jailLogPath := regexp.MustCompile(`logpath = (.*)`).FindStringSubmatch(jailRaw) jailMaxRetry := regexp.MustCompile(`maxretry = (.*)`).FindStringSubmatch(jailRaw) jailFindTime := regexp.MustCompile(`findtime = (.*)`).FindStringSubmatch(jailRaw) jailBanTime := regexp.MustCompile(`bantime = (.*)`).FindStringSubmatch(jailRaw) @@ -63,7 +61,6 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { jails = append(jails, Jail{ Name: jailName, Enabled: jailEnabled, - LogPath: jailLogPath[1], MaxRetry: cast.ToInt(jailMaxRetry[1]), FindTime: cast.ToInt(jailFindTime[1]), BanTime: cast.ToInt(jailBanTime[1]), @@ -128,7 +125,6 @@ port = ` + ports + ` maxretry = ` + jailMaxRetry + ` findtime = ` + jailFindTime + ` bantime = ` + jailBanTime + ` -action = %(action_mwl)s logpath = ` + app.Root + `/wwwlogs/` + website.Name + `.log # ` + jailWebsiteName + `-` + jailWebsiteMode + `-END ` @@ -158,25 +154,17 @@ ignoreregex = } case "service": - var logPath string var filter string var port string var err error switch jailName { case "ssh": - if os.IsDebian() || os.IsUbuntu() { - logPath = "/var/log/auth.log" - } else { - logPath = "/var/log/secure" - } filter = "sshd" port, err = shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") case "mysql": - logPath = app.Root + "/server/mysql/mysql-error.log" filter = "mysqld-auth" port, err = shell.Execf("cat %s/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'", app.Root) case "pure-ftpd": - logPath = "/var/log/messages" filter = "pure-ftpd" port, err = shell.Execf(`cat %s/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`, app.Root) default: @@ -197,8 +185,6 @@ port = ` + port + ` maxretry = ` + jailMaxRetry + ` findtime = ` + jailFindTime + ` bantime = ` + jailBanTime + ` -action = %(action_mwl)s -logpath = ` + logPath + ` # ` + jailName + `-END ` raw += rule @@ -208,7 +194,7 @@ logpath = ` + logPath + ` } } - if _, err := shell.Execf("fail2ban-client reload"); err != nil { + if _, err = shell.Execf("fail2ban-client reload"); err != nil { service.Error(w, http.StatusInternalServerError, "重载配置失败") return } diff --git a/internal/apps/fail2ban/types.go b/internal/apps/fail2ban/types.go index e9aaa3ff..3a71a996 100644 --- a/internal/apps/fail2ban/types.go +++ b/internal/apps/fail2ban/types.go @@ -3,7 +3,6 @@ package fail2ban type Jail struct { Name string `json:"name"` Enabled bool `json:"enabled"` - LogPath string `json:"log_path"` MaxRetry int `json:"max_retry"` FindTime int `json:"find_time"` BanTime int `json:"ban_time"` diff --git a/internal/apps/mysql/init.go b/internal/apps/mysql/init.go index 4667326d..1b760ca8 100644 --- a/internal/apps/mysql/init.go +++ b/internal/apps/mysql/init.go @@ -15,7 +15,6 @@ func init() { r.Get("/load", service.Load) r.Get("/config", service.GetConfig) r.Post("/config", service.UpdateConfig) - r.Get("/errorLog", service.ErrorLog) r.Post("/clearErrorLog", service.ClearErrorLog) r.Get("/slowLog", service.SlowLog) r.Post("/clearSlowLog", service.ClearSlowLog) diff --git a/internal/apps/mysql/service.go b/internal/apps/mysql/service.go index 9d8ba8bb..27448b81 100644 --- a/internal/apps/mysql/service.go +++ b/internal/apps/mysql/service.go @@ -142,14 +142,9 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { service.Success(w, load) } -// ErrorLog 获取错误日志 -func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) { - service.Success(w, fmt.Sprintf("%s/server/mysql/mysql-error.log", app.Root)) -} - // ClearErrorLog 清空错误日志 func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { - if _, err := shell.Execf("echo '' > %s/server/mysql/mysql-error.log", app.Root); err != nil { + if err := systemctl.LogsClear("mysqld"); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return } diff --git a/internal/biz/database.go b/internal/biz/database.go index 05892e08..052af046 100644 --- a/internal/biz/database.go +++ b/internal/biz/database.go @@ -66,4 +66,5 @@ type DatabaseRepo interface { Create(req *request.DatabaseCreate) error Update(req *request.DatabaseUpdate) error Delete(id uint) error + Add(serverID uint, name string) error } diff --git a/internal/data/app.go b/internal/data/app.go index 0d338865..fc3cbdf5 100644 --- a/internal/data/app.go +++ b/internal/data/app.go @@ -9,6 +9,7 @@ import ( "github.com/expr-lang/expr" "github.com/go-rat/utils/collect" "github.com/hashicorp/go-version" + "github.com/samber/do/v2" "github.com/spf13/cast" "github.com/TheTNB/panel/internal/app" @@ -19,21 +20,15 @@ import ( ) type appRepo struct { - cacheRepo biz.CacheRepo - taskRepo biz.TaskRepo - api *api.API + api *api.API } func NewAppRepo() biz.AppRepo { - return &appRepo{ - cacheRepo: NewCacheRepo(), - taskRepo: NewTaskRepo(), - api: api.NewAPI(app.Version), - } + return do.MustInvoke[biz.AppRepo](injector) } func (r *appRepo) All() api.Apps { - cached, err := r.cacheRepo.Get(biz.CacheKeyApps) + cached, err := NewCacheRepo().Get(biz.CacheKeyApps) if err != nil { return nil } @@ -190,7 +185,7 @@ func (r *appRepo) Install(channel, slug string) error { task.Shell = fmt.Sprintf(`curl -fsLm 10 --retry 3 "%s" | bash -s -- "%s" "%s" >> /tmp/%s.log 2>&1`, shellUrl, shellChannel, shellVersion, item.Slug) task.Log = "/tmp/" + item.Slug + ".log" - return r.taskRepo.Push(task) + return NewTaskRepo().Push(task) } func (r *appRepo) UnInstall(slug string) error { @@ -245,7 +240,7 @@ func (r *appRepo) UnInstall(slug string) error { task.Shell = fmt.Sprintf(`curl -fsLm 10 --retry 3 "%s" | bash -s -- "%s" "%s" >> /tmp/%s.log 2>&1`, shellUrl, shellChannel, shellVersion, item.Slug) task.Log = "/tmp/" + item.Slug + ".log" - return r.taskRepo.Push(task) + return NewTaskRepo().Push(task) } func (r *appRepo) Update(slug string) error { @@ -300,7 +295,7 @@ func (r *appRepo) Update(slug string) error { task.Shell = fmt.Sprintf(`curl -fsLm 10 --retry 3 "%s" | bash -s -- "%s" "%s" >> /tmp/%s.log 2>&1`, shellUrl, shellChannel, shellVersion, item.Slug) task.Log = "/tmp/" + item.Slug + ".log" - return r.taskRepo.Push(task) + return NewTaskRepo().Push(task) } func (r *appRepo) UpdateShow(slug string, show bool) error { @@ -331,7 +326,7 @@ func (r *appRepo) UpdateCache() error { return err } - return r.cacheRepo.Set(biz.CacheKeyApps, string(encoded)) + return NewCacheRepo().Set(biz.CacheKeyApps, string(encoded)) } func (r *appRepo) preCheck(app *api.App) error { diff --git a/internal/data/backup.go b/internal/data/backup.go index 6e4b1e8d..74e614e0 100644 --- a/internal/data/backup.go +++ b/internal/data/backup.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/samber/do/v2" "github.com/shirou/gopsutil/disk" "github.com/TheTNB/panel/internal/app" @@ -20,16 +21,10 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type backupRepo struct { - setting biz.SettingRepo - website biz.WebsiteRepo -} +type backupRepo struct{} func NewBackupRepo() biz.BackupRepo { - return &backupRepo{ - setting: NewSettingRepo(), - website: NewWebsiteRepo(), - } + return do.MustInvoke[biz.BackupRepo](injector) } // List 备份列表 @@ -197,7 +192,7 @@ func (r *backupRepo) ClearExpired(path, prefix string, save int) error { // GetPath 获取备份路径 func (r *backupRepo) GetPath(typ biz.BackupType) (string, error) { - backupPath, err := r.setting.Get(biz.SettingKeyBackupPath) + backupPath, err := NewSettingRepo().Get(biz.SettingKeyBackupPath) if err != nil { return "", err } @@ -217,7 +212,7 @@ func (r *backupRepo) GetPath(typ biz.BackupType) (string, error) { // createWebsite 创建网站备份 func (r *backupRepo) createWebsite(to string, name string) error { - website, err := r.website.GetByName(name) + website, err := NewWebsiteRepo().GetByName(name) if err != nil { return err } @@ -241,7 +236,7 @@ func (r *backupRepo) createWebsite(to string, name string) error { // createMySQL 创建 MySQL 备份 func (r *backupRepo) createMySQL(to string, name string) error { - rootPassword, err := r.setting.Get(biz.SettingKeyMySQLRootPassword) + rootPassword, err := NewSettingRepo().Get(biz.SettingKeyMySQLRootPassword) if err != nil { return err } @@ -370,7 +365,7 @@ func (r *backupRepo) restoreWebsite(backup, target string) error { return errors.New("备份文件不存在") } - website, err := r.website.GetByName(target) + website, err := NewWebsiteRepo().GetByName(target) if err != nil { return err } @@ -397,7 +392,7 @@ func (r *backupRepo) restoreMySQL(backup, target string) error { return errors.New("备份文件不存在") } - rootPassword, err := r.setting.Get(biz.SettingKeyMySQLRootPassword) + rootPassword, err := NewSettingRepo().Get(biz.SettingKeyMySQLRootPassword) if err != nil { return err } diff --git a/internal/data/cache.go b/internal/data/cache.go index 958577b2..fc38ea6f 100644 --- a/internal/data/cache.go +++ b/internal/data/cache.go @@ -3,6 +3,7 @@ package data import ( "errors" + "github.com/samber/do/v2" "gorm.io/gorm" "github.com/TheTNB/panel/internal/app" @@ -12,7 +13,7 @@ import ( type cacheRepo struct{} func NewCacheRepo() biz.CacheRepo { - return &cacheRepo{} + return do.MustInvoke[biz.CacheRepo](injector) } func (r *cacheRepo) Get(key biz.CacheKey, defaultValue ...string) (string, error) { diff --git a/internal/data/cert.go b/internal/data/cert.go index e3d4d21b..5b78d753 100644 --- a/internal/data/cert.go +++ b/internal/data/cert.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/samber/do/v2" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -24,7 +26,7 @@ type certRepo struct { } func NewCertRepo() biz.CertRepo { - return &certRepo{} + return do.MustInvoke[biz.CertRepo](injector) } func (r *certRepo) List(page, limit uint) ([]*types.CertList, int64, error) { diff --git a/internal/data/cert_account.go b/internal/data/cert_account.go index feb8cac7..1a616564 100644 --- a/internal/data/cert_account.go +++ b/internal/data/cert_account.go @@ -7,6 +7,7 @@ import ( "time" "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" @@ -18,7 +19,7 @@ import ( type certAccountRepo struct{} func NewCertAccountRepo() biz.CertAccountRepo { - return &certAccountRepo{} + return do.MustInvoke[biz.CertAccountRepo](injector) } func (r certAccountRepo) List(page, limit uint) ([]*biz.CertAccount, int64, error) { diff --git a/internal/data/cert_dns.go b/internal/data/cert_dns.go index a0c2158e..2bcf8a52 100644 --- a/internal/data/cert_dns.go +++ b/internal/data/cert_dns.go @@ -1,6 +1,8 @@ package data import ( + "github.com/samber/do/v2" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -9,7 +11,7 @@ import ( type certDNSRepo struct{} func NewCertDNSRepo() biz.CertDNSRepo { - return &certDNSRepo{} + return do.MustInvoke[biz.CertDNSRepo](injector) } func (r certDNSRepo) List(page, limit uint) ([]*biz.CertDNS, int64, error) { diff --git a/internal/data/container.go b/internal/data/container.go index d2b0cd82..8a25e232 100644 --- a/internal/data/container.go +++ b/internal/data/container.go @@ -1,15 +1,13 @@ package data import ( - "context" "fmt" - "net" - "net/http" "slices" "strings" "time" "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -22,23 +20,8 @@ type containerRepo struct { client *resty.Client } -func NewContainerRepo(sock ...string) biz.ContainerRepo { - if len(sock) == 0 { - sock = append(sock, "/var/run/docker.sock") - } - client := resty.New() - client.SetTimeout(1 * time.Minute) - client.SetRetryCount(2) - client.SetTransport(&http.Transport{ - DialContext: func(ctx context.Context, _ string, _ string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, "unix", sock[0]) - }, - }) - client.SetBaseURL("http://d/v1.40") - - return &containerRepo{ - client: client, - } +func NewContainerRepo() biz.ContainerRepo { + return do.MustInvoke[biz.ContainerRepo](injector) } // ListAll 列出所有容器 diff --git a/internal/data/container_image.go b/internal/data/container_image.go index db9bafbc..1a1010ac 100644 --- a/internal/data/container_image.go +++ b/internal/data/container_image.go @@ -1,15 +1,13 @@ package data import ( - "context" "fmt" - "net" - "net/http" "slices" "strings" "time" "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -23,23 +21,8 @@ type containerImageRepo struct { client *resty.Client } -func NewContainerImageRepo(sock ...string) biz.ContainerImageRepo { - if len(sock) == 0 { - sock = append(sock, "/var/run/docker.sock") - } - client := resty.New() - client.SetTimeout(1 * time.Minute) - client.SetRetryCount(2) - client.SetTransport(&http.Transport{ - DialContext: func(ctx context.Context, _ string, _ string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, "unix", sock[0]) - }, - }) - client.SetBaseURL("http://d/v1.40") - - return &containerImageRepo{ - client: client, - } +func NewContainerImageRepo() biz.ContainerImageRepo { + return do.MustInvoke[biz.ContainerImageRepo](injector) } // List 列出镜像 diff --git a/internal/data/container_network.go b/internal/data/container_network.go index eabb303a..195eaf1e 100644 --- a/internal/data/container_network.go +++ b/internal/data/container_network.go @@ -1,15 +1,13 @@ package data import ( - "context" "fmt" - "net" - "net/http" "slices" "strings" "time" "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -22,23 +20,8 @@ type containerNetworkRepo struct { client *resty.Client } -func NewContainerNetworkRepo(sock ...string) biz.ContainerNetworkRepo { - if len(sock) == 0 { - sock = append(sock, "/var/run/docker.sock") - } - client := resty.New() - client.SetTimeout(1 * time.Minute) - client.SetRetryCount(2) - client.SetTransport(&http.Transport{ - DialContext: func(ctx context.Context, _ string, _ string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, "unix", sock[0]) - }, - }) - client.SetBaseURL("http://d/v1.40") - - return &containerNetworkRepo{ - client: client, - } +func NewContainerNetworkRepo() biz.ContainerNetworkRepo { + return do.MustInvoke[biz.ContainerNetworkRepo](injector) } // List 列出网络 diff --git a/internal/data/container_volume.go b/internal/data/container_volume.go index 7c0deffb..d2615a95 100644 --- a/internal/data/container_volume.go +++ b/internal/data/container_volume.go @@ -1,15 +1,13 @@ package data import ( - "context" "fmt" - "net" - "net/http" "slices" "strings" "time" "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" @@ -23,23 +21,8 @@ type containerVolumeRepo struct { client *resty.Client } -func NewContainerVolumeRepo(sock ...string) biz.ContainerVolumeRepo { - if len(sock) == 0 { - sock = append(sock, "/var/run/docker.sock") - } - client := resty.New() - client.SetTimeout(1 * time.Minute) - client.SetRetryCount(2) - client.SetTransport(&http.Transport{ - DialContext: func(ctx context.Context, _ string, _ string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, "unix", sock[0]) - }, - }) - client.SetBaseURL("http://d/v1.40") - - return &containerVolumeRepo{ - client: client, - } +func NewContainerVolumeRepo() biz.ContainerVolumeRepo { + return do.MustInvoke[biz.ContainerVolumeRepo](injector) } // List 列出存储卷 diff --git a/internal/data/cron.go b/internal/data/cron.go index b5e3c83e..62237411 100644 --- a/internal/data/cron.go +++ b/internal/data/cron.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-rat/utils/str" + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" @@ -18,14 +19,10 @@ import ( "github.com/TheTNB/panel/pkg/systemctl" ) -type cronRepo struct { - settingRepo biz.SettingRepo -} +type cronRepo struct{} func NewCronRepo() biz.CronRepo { - return &cronRepo{ - settingRepo: NewSettingRepo(), - } + return do.MustInvoke[biz.CronRepo](injector) } func (r *cronRepo) Count() (int64, error) { diff --git a/internal/data/database.go b/internal/data/database.go index c6e71c11..b83dce89 100644 --- a/internal/data/database.go +++ b/internal/data/database.go @@ -3,20 +3,18 @@ package data import ( "fmt" + "github.com/samber/do/v2" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/db" ) -type databaseRepo struct { - databaseServer biz.DatabaseServerRepo -} +type databaseRepo struct{} func NewDatabaseRepo() biz.DatabaseRepo { - return &databaseRepo{ - databaseServer: NewDatabaseServerRepo(), - } + return do.MustInvoke[biz.DatabaseRepo](injector) } func (r databaseRepo) Count() (int64, error) { @@ -45,7 +43,7 @@ func (r databaseRepo) Get(id uint) (*biz.Database, error) { } func (r databaseRepo) Create(req *request.DatabaseCreate) error { - server, err := r.databaseServer.Get(req.ServerID) + server, err := NewDatabaseServerRepo().Get(req.ServerID) if err != nil { return err } @@ -107,3 +105,15 @@ func (r databaseRepo) Update(req *request.DatabaseUpdate) error { func (r databaseRepo) Delete(id uint) error { return app.Orm.Delete(&biz.Database{}, id).Error } + +func (r databaseRepo) Add(serverID uint, name string) error { + database := &biz.Database{ + Name: name, + Username: name, + ServerID: serverID, + Status: biz.DatabaseStatusNormal, + Remark: "sync from server", + } + + return app.Orm.Create(database).Error +} diff --git a/internal/data/database_server.go b/internal/data/database_server.go index 78b4a8ee..6597e23c 100644 --- a/internal/data/database_server.go +++ b/internal/data/database_server.go @@ -6,16 +6,20 @@ import ( "slices" "strings" + "github.com/samber/do/v2" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/db" ) -type databaseServerRepo struct{} +type databaseServerRepo struct { + database biz.DatabaseRepo +} func NewDatabaseServerRepo() biz.DatabaseServerRepo { - return &databaseServerRepo{} + return do.MustInvoke[biz.DatabaseServerRepo](injector) } func (r databaseServerRepo) Count() (int64, error) { @@ -115,11 +119,12 @@ func (r databaseServerRepo) Delete(id uint) error { } func (r databaseServerRepo) Sync(id uint) error { - /*server, err := r.Get(id) + server, err := r.Get(id) if err != nil { return err } + dbRepo := NewDatabaseRepo() switch server.Type { case biz.DatabaseTypeMysql: mysql, err := db.NewMySQL(server.Username, server.Password, fmt.Sprintf("%s:%d", server.Host, server.Port)) @@ -131,18 +136,10 @@ func (r databaseServerRepo) Sync(id uint) error { return err } for database := range slices.Values(databases) { - db := &biz.Database{ - Name: database.Name, - Username: server.Username, - Password: server.Password, - ServerID: server.ID, - Status: biz.DatabaseStatusInvalid, - } - if err := app.Orm.Where("name = ? AND server_id = ?", database.Name, server.ID).First(db).Error; err != nil { - app.Orm.Create(db) + if err = dbRepo.Add(id, database); err != nil { + return err } } - case biz.DatabaseTypePostgresql: postgres, err := db.NewPostgres(server.Username, server.Password, server.Host, server.Port) if err != nil { @@ -152,7 +149,12 @@ func (r databaseServerRepo) Sync(id uint) error { if err != nil { return err } - }*/ + for database := range slices.Values(databases) { + if err = dbRepo.Add(id, database.Name); err != nil { + return err + } + } + } return nil } diff --git a/internal/data/init.go b/internal/data/init.go new file mode 100644 index 00000000..dae029e6 --- /dev/null +++ b/internal/data/init.go @@ -0,0 +1,117 @@ +package data + +import ( + "context" + "net" + "net/http" + "time" + + "github.com/go-rat/utils/hash" + "github.com/go-resty/resty/v2" + "github.com/samber/do/v2" + + "github.com/TheTNB/panel/internal/app" + "github.com/TheTNB/panel/internal/biz" + "github.com/TheTNB/panel/pkg/api" + "github.com/TheTNB/panel/pkg/os" +) + +var injector = do.New() + +func init() { + do.Provide(injector, func(i do.Injector) (biz.AppRepo, error) { + return &appRepo{ + api: api.NewAPI(app.Version), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.BackupRepo, error) { + return &backupRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.CacheRepo, error) { + return &cacheRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.CertRepo, error) { + return &certRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.CertAccountRepo, error) { + return &certAccountRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.CertDNSRepo, error) { + return &certDNSRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.ContainerRepo, error) { + return &containerRepo{ + client: getDockerClient("/var/run/docker.sock"), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.ContainerImageRepo, error) { + return &containerImageRepo{ + client: getDockerClient("/var/run/docker.sock"), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.ContainerNetworkRepo, error) { + return &containerNetworkRepo{ + client: getDockerClient("/var/run/docker.sock"), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.ContainerVolumeRepo, error) { + return &containerVolumeRepo{ + client: getDockerClient("/var/run/docker.sock"), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.CronRepo, error) { + return &cronRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.DatabaseServerRepo, error) { + return &databaseServerRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.DatabaseRepo, error) { + return &databaseRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.MonitorRepo, error) { + return &monitorRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.SafeRepo, error) { + var ssh string + if os.IsRHEL() { + ssh = "sshd" + } else { + ssh = "ssh" + } + return &safeRepo{ + ssh: ssh, + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.SettingRepo, error) { + return &settingRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.SSHRepo, error) { + return &sshRepo{}, nil + }) + do.Provide(injector, func(i do.Injector) (biz.TaskRepo, error) { + task := &taskRepo{} + task.DispatchWaiting() + return task, nil + }) + do.Provide(injector, func(i do.Injector) (biz.UserRepo, error) { + return &userRepo{ + hasher: hash.NewArgon2id(), + }, nil + }) + do.Provide(injector, func(i do.Injector) (biz.WebsiteRepo, error) { + return &websiteRepo{}, nil + }) +} + +func getDockerClient(sock string) *resty.Client { + client := resty.New() + client.SetTimeout(1 * time.Minute) + client.SetRetryCount(2) + client.SetTransport(&http.Transport{ + DialContext: func(ctx context.Context, _ string, _ string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, "unix", sock) + }, + }) + client.SetBaseURL("http://d/v1.40") + return client +} diff --git a/internal/data/monitor.go b/internal/data/monitor.go index 67f09c56..edf31904 100644 --- a/internal/data/monitor.go +++ b/internal/data/monitor.go @@ -4,6 +4,7 @@ import ( "errors" "time" + "github.com/samber/do/v2" "github.com/spf13/cast" "github.com/TheTNB/panel/internal/app" @@ -11,22 +12,19 @@ import ( "github.com/TheTNB/panel/internal/http/request" ) -type monitorRepo struct { - settingRepo biz.SettingRepo -} +type monitorRepo struct{} func NewMonitorRepo() biz.MonitorRepo { - return &monitorRepo{ - settingRepo: NewSettingRepo(), - } + return do.MustInvoke[biz.MonitorRepo](injector) } func (r monitorRepo) GetSetting() (*request.MonitorSetting, error) { - monitor, err := r.settingRepo.Get(biz.SettingKeyMonitor) + repo := NewSettingRepo() + monitor, err := repo.Get(biz.SettingKeyMonitor) if err != nil { return nil, err } - monitorDays, err := r.settingRepo.Get(biz.SettingKeyMonitorDays) + monitorDays, err := repo.Get(biz.SettingKeyMonitorDays) if err != nil { return nil, err } @@ -39,10 +37,11 @@ func (r monitorRepo) GetSetting() (*request.MonitorSetting, error) { } func (r monitorRepo) UpdateSetting(setting *request.MonitorSetting) error { - if err := r.settingRepo.Set(biz.SettingKeyMonitor, cast.ToString(setting.Enabled)); err != nil { + repo := NewSettingRepo() + if err := repo.Set(biz.SettingKeyMonitor, cast.ToString(setting.Enabled)); err != nil { return err } - if err := r.settingRepo.Set(biz.SettingKeyMonitorDays, cast.ToString(setting.Days)); err != nil { + if err := repo.Set(biz.SettingKeyMonitorDays, cast.ToString(setting.Days)); err != nil { return err } diff --git a/internal/data/safe.go b/internal/data/safe.go index 4c36410b..3c4ef66b 100644 --- a/internal/data/safe.go +++ b/internal/data/safe.go @@ -4,11 +4,11 @@ import ( "fmt" "strings" + "github.com/samber/do/v2" "github.com/spf13/cast" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/pkg/firewall" - "github.com/TheTNB/panel/pkg/os" "github.com/TheTNB/panel/pkg/shell" "github.com/TheTNB/panel/pkg/systemctl" ) @@ -18,16 +18,7 @@ type safeRepo struct { } func NewSafeRepo() biz.SafeRepo { - var ssh string - if os.IsRHEL() { - ssh = "sshd" - } else { - ssh = "ssh" - } - - return &safeRepo{ - ssh: ssh, - } + return do.MustInvoke[biz.SafeRepo](injector) } func (r *safeRepo) GetSSH() (uint, bool, error) { diff --git a/internal/data/setting.go b/internal/data/setting.go index 5ba7e424..a18045a0 100644 --- a/internal/data/setting.go +++ b/internal/data/setting.go @@ -8,6 +8,7 @@ import ( "slices" "github.com/go-rat/utils/hash" + "github.com/samber/do/v2" "github.com/spf13/cast" "gopkg.in/yaml.v3" "gorm.io/gorm" @@ -24,14 +25,10 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type settingRepo struct { - taskRepo biz.TaskRepo -} +type settingRepo struct{} func NewSettingRepo() biz.SettingRepo { - return &settingRepo{ - taskRepo: NewTaskRepo(), - } + return do.MustInvoke[biz.SettingRepo](injector) } func (r *settingRepo) Get(key biz.SettingKey, defaultValue ...string) (string, error) { @@ -170,12 +167,13 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P } // 下面是需要需要重启的设置 + task := NewTaskRepo() // 面板HTTPS restartFlag := false oldCert, _ := io.Read(filepath.Join(app.Root, "panel/storage/cert.pem")) oldKey, _ := io.Read(filepath.Join(app.Root, "panel/storage/cert.key")) if oldCert != setting.Cert || oldKey != setting.Key { - if r.taskRepo.HasRunningTask() { + if task.HasRunningTask() { return false, errors.New("后台任务正在运行,禁止修改部分设置,请稍后再试") } restartFlag = true @@ -232,7 +230,7 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P return false, err } if raw != string(encoded) { - if r.taskRepo.HasRunningTask() { + if task.HasRunningTask() { return false, errors.New("后台任务正在运行,禁止修改部分设置,请稍后再试") } restartFlag = true diff --git a/internal/data/ssh.go b/internal/data/ssh.go index 567fbd6d..27b05dc2 100644 --- a/internal/data/ssh.go +++ b/internal/data/ssh.go @@ -3,20 +3,18 @@ package data import ( "fmt" + "github.com/samber/do/v2" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" pkgssh "github.com/TheTNB/panel/pkg/ssh" ) -type sshRepo struct { - settingRepo biz.SettingRepo -} +type sshRepo struct{} func NewSSHRepo() biz.SSHRepo { - return &sshRepo{ - settingRepo: NewSettingRepo(), - } + return do.MustInvoke[biz.SSHRepo](injector) } func (r *sshRepo) List(page, limit uint) ([]*biz.SSH, int64, error) { diff --git a/internal/data/task.go b/internal/data/task.go index 20b24140..3e5a4c68 100644 --- a/internal/data/task.go +++ b/internal/data/task.go @@ -3,21 +3,18 @@ package data import ( "fmt" "log/slog" - "sync" + + "github.com/samber/do/v2" "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/queuejob" ) -var taskDispatchOnce sync.Once - type taskRepo struct{} func NewTaskRepo() biz.TaskRepo { - task := &taskRepo{} - taskDispatchOnce.Do(task.DispatchWaiting) - return &taskRepo{} + return do.MustInvoke[biz.TaskRepo](injector) } func (r *taskRepo) HasRunningTask() bool { diff --git a/internal/data/user.go b/internal/data/user.go index 53edc121..e2419978 100644 --- a/internal/data/user.go +++ b/internal/data/user.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/go-rat/utils/hash" + "github.com/samber/do/v2" "gorm.io/gorm" "github.com/TheTNB/panel/internal/app" @@ -15,9 +16,7 @@ type userRepo struct { } func NewUserRepo() biz.UserRepo { - return &userRepo{ - hasher: hash.NewArgon2id(), - } + return do.MustInvoke[biz.UserRepo](injector) } func (r *userRepo) Create(username, password string) (*biz.User, error) { diff --git a/internal/data/website.go b/internal/data/website.go index e60b238f..9318fcb0 100644 --- a/internal/data/website.go +++ b/internal/data/website.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/samber/do/v2" "github.com/samber/lo" "github.com/spf13/cast" @@ -30,7 +31,7 @@ import ( type websiteRepo struct{} func NewWebsiteRepo() biz.WebsiteRepo { - return &websiteRepo{} + return do.MustInvoke[biz.WebsiteRepo](injector) } func (r *websiteRepo) UpdateDefaultConfig(req *request.WebsiteDefaultConfig) error { diff --git a/internal/route/http.go b/internal/route/http.go index b6b7ef34..c4f3e0d9 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -76,6 +76,7 @@ func Http(r chi.Router) { r.Post("/", database.Create) r.Put("/{id}", database.Update) r.Delete("/{id}", database.Delete) + r.Post("/{id}/sync", database.Sync) }) r.Route("/backup", func(r chi.Router) { diff --git a/pkg/db/mysql.go b/pkg/db/mysql.go index edf564e3..6cf7a546 100644 --- a/pkg/db/mysql.go +++ b/pkg/db/mysql.go @@ -156,14 +156,14 @@ func (m *MySQL) Users() ([]types.MySQLUser, error) { return users, nil } -func (m *MySQL) Databases() ([]types.MySQLDatabase, error) { +func (m *MySQL) Databases() ([]string, error) { rows, err := m.Query("SHOW DATABASES") if err != nil { return nil, err } defer rows.Close() - var databases []types.MySQLDatabase + var databases []string for rows.Next() { var database string if err := rows.Scan(&database); err != nil { @@ -172,9 +172,7 @@ func (m *MySQL) Databases() ([]types.MySQLDatabase, error) { if slices.Contains([]string{"information_schema", "performance_schema", "mysql", "sys"}, database) { continue } - databases = append(databases, types.MySQLDatabase{ - Name: database, - }) + databases = append(databases, database) } return databases, nil } diff --git a/pkg/firewall/consts.go b/pkg/firewall/consts.go index 8fa19716..9130360f 100644 --- a/pkg/firewall/consts.go +++ b/pkg/firewall/consts.go @@ -28,6 +28,7 @@ var ( StrategyAccept Strategy = "accept" // 接受 StrategyDrop Strategy = "drop" // 丢弃 StrategyReject Strategy = "reject" // 拒绝 + StrategyMark Strategy = "mark" // 标记 ) type Direction string @@ -44,7 +45,7 @@ type FireInfo struct { PortStart uint `json:"port_start"` // 1-65535 PortEnd uint `json:"port_end"` // 1-65535 Protocol Protocol `json:"protocol"` // tcp udp tcp/udp - Strategy Strategy `json:"strategy"` // accept drop reject + Strategy Strategy `json:"strategy"` // accept drop reject mark Direction Direction `json:"direction"` // in out 入站或出站 } diff --git a/pkg/firewall/firewall.go b/pkg/firewall/firewall.go index 80ae1b82..a5df0e15 100644 --- a/pkg/firewall/firewall.go +++ b/pkg/firewall/firewall.go @@ -23,7 +23,7 @@ type Firewall struct { func NewFirewall() *Firewall { firewall := &Firewall{ forwardListRegex: regexp.MustCompile(`^port=(\d{1,5}):proto=(.+?):toport=(\d{1,5}):toaddr=(.*)$`), - richRuleRegex: regexp.MustCompile(`^rule family="([^"]+)"(?: .*?(source|destination) address="([^"]+)")?(?: .*?port port="([^"]+)")?(?: .*?protocol(?: value)?="([^"]+)")?.*?(accept|drop|reject)$`), + richRuleRegex: regexp.MustCompile(`^rule family="([^"]+)"(?: .*?(source|destination) address="([^"]+)")?(?: .*?port port="([^"]+)")?(?: .*?protocol(?: value)?="([^"]+)")?.*?(accept|drop|reject|mark).*?$`), } return firewall diff --git a/pkg/systemctl/service.go b/pkg/systemctl/service.go index 557cf288..0b1cd49f 100644 --- a/pkg/systemctl/service.go +++ b/pkg/systemctl/service.go @@ -71,3 +71,22 @@ func Disable(name string) error { _, err := shell.Execf("systemctl disable %s", name) return err } + +// Logs 获取服务日志 +func Logs(name string) (string, error) { + return shell.Execf("journalctl -u %s", name) +} + +// LogsTail 获取服务日志 +func LogsTail(name string, lines int) (string, error) { + return shell.Execf("journalctl -u %s --lines %d", name, lines) +} + +// LogsClear 清空服务日志 +func LogsClear(name string) error { + if _, err := shell.Execf("journalctl --rotate -u %s", name); err != nil { + return err + } + _, err := shell.Execf("journalctl --vacuum-time=1s -u %s", name) + return err +} diff --git a/pkg/types/mysql.go b/pkg/types/mysql.go index a5381dbf..4f38c08f 100644 --- a/pkg/types/mysql.go +++ b/pkg/types/mysql.go @@ -5,7 +5,3 @@ type MySQLUser struct { Host string `json:"host"` Grants []string `json:"grants"` } - -type MySQLDatabase struct { - Name string `json:"name"` -} diff --git a/web/src/components/common/RealtimeLog.vue b/web/src/components/common/RealtimeLog.vue index 4efbd5fc..4aeecd81 100644 --- a/web/src/components/common/RealtimeLog.vue +++ b/web/src/components/common/RealtimeLog.vue @@ -5,7 +5,11 @@ import type { LogInst } from 'naive-ui' const props = defineProps({ path: { type: String, - required: true + required: false + }, + service: { + type: String, + required: false } }) @@ -14,7 +18,15 @@ const logRef = ref(null) let logWs: WebSocket | null = null const init = async () => { - const cmd = `tail -n 100 -f '${props.path}'` + let cmd = '' + if (props.path) { + cmd = `tail -n 100 -f '${props.path}'` + } else if (props.service) { + cmd = `journalctl -u '${props.service}' -f` + } else { + window.$message.error('path 或 service 不能为空') + return + } ws.exec(cmd) .then((ws: WebSocket) => { logWs = ws diff --git a/web/src/views/apps/mysql/IndexView.vue b/web/src/views/apps/mysql/IndexView.vue index 0e27aa13..96c95a2b 100644 --- a/web/src/views/apps/mysql/IndexView.vue +++ b/web/src/views/apps/mysql/IndexView.vue @@ -13,7 +13,6 @@ const currentTab = ref('status') const status = ref(false) const isEnabled = ref(false) const config = ref('') -const errorLog = ref('') const slowLog = ref('') const rootPassword = ref('') @@ -65,11 +64,6 @@ const getRootPassword = async () => { }) } -const getErrorLog = async () => { - const { data } = await mysql.errorLog() - return data -} - const getSlowLog = async () => { const { data } = await mysql.slowLog() return data @@ -142,9 +136,6 @@ onMounted(() => { getLoad().then((res) => { load.value = res }) - getErrorLog().then((res) => { - errorLog.value = res - }) getSlowLog().then((res) => { slowLog.value = res }) @@ -266,7 +257,7 @@ onMounted(() => { /> - + diff --git a/web/src/views/firewall/IpRuleView.vue b/web/src/views/firewall/IpRuleView.vue index e20b60dc..56b8babc 100644 --- a/web/src/views/firewall/IpRuleView.vue +++ b/web/src/views/firewall/IpRuleView.vue @@ -53,7 +53,13 @@ const columns: any = [ NTag, { type: - row.strategy === 'accept' ? 'success' : row.strategy === 'drop' ? 'warning' : 'error' + row.strategy === 'accept' + ? 'success' + : row.strategy === 'drop' + ? 'warning' + : row.strategy === 'reject' + ? 'error' + : 'default' }, { default: () => { @@ -64,6 +70,8 @@ const columns: any = [ return '丢弃' case 'reject': return '拒绝' + case 'mark': + return '标记' default: return '未知' } diff --git a/web/src/views/firewall/RuleView.vue b/web/src/views/firewall/RuleView.vue index 4eb6caf8..959e8fad 100644 --- a/web/src/views/firewall/RuleView.vue +++ b/web/src/views/firewall/RuleView.vue @@ -87,7 +87,13 @@ const columns: any = [ NTag, { type: - row.strategy === 'accept' ? 'success' : row.strategy === 'drop' ? 'warning' : 'error' + row.strategy === 'accept' + ? 'success' + : row.strategy === 'drop' + ? 'warning' + : row.strategy === 'reject' + ? 'error' + : 'default' }, { default: () => { @@ -98,6 +104,8 @@ const columns: any = [ return '丢弃' case 'reject': return '拒绝' + case 'mark': + return '标记' default: return '未知' }