diff --git a/cmd/cli/main.go b/cmd/cli/main.go
index 76ae199a..e8257ca5 100644
--- a/cmd/cli/main.go
+++ b/cmd/cli/main.go
@@ -17,11 +17,21 @@ along with this program. If not, see .
package main
import (
+ "os"
_ "time/tzdata"
-
- "github.com/TheTNB/panel/internal/bootstrap"
)
func main() {
- bootstrap.BootCli()
+ if os.Geteuid() != 0 {
+ panic("panel must run as root")
+ }
+
+ cli, err := initCli()
+ if err != nil {
+ panic(err)
+ }
+
+ if err = cli.Run(); err != nil {
+ panic(err)
+ }
}
diff --git a/cmd/cli/wire.go b/cmd/cli/wire.go
new file mode 100644
index 00000000..ffd2ef61
--- /dev/null
+++ b/cmd/cli/wire.go
@@ -0,0 +1,18 @@
+//go:build wireinject
+
+package main
+
+import (
+ "github.com/google/wire"
+
+ "github.com/TheTNB/panel/internal/app"
+ "github.com/TheTNB/panel/internal/bootstrap"
+ "github.com/TheTNB/panel/internal/data"
+ "github.com/TheTNB/panel/internal/route"
+ "github.com/TheTNB/panel/internal/service"
+)
+
+// initCli init command line.
+func initCli() (*app.Cli, error) {
+ panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, app.NewCli))
+}
diff --git a/cmd/cli/wire_gen.go b/cmd/cli/wire_gen.go
new file mode 100644
index 00000000..bc040803
--- /dev/null
+++ b/cmd/cli/wire_gen.go
@@ -0,0 +1,52 @@
+// Code generated by Wire. DO NOT EDIT.
+
+//go:generate go run -mod=mod github.com/google/wire/cmd/wire
+//go:build !wireinject
+// +build !wireinject
+
+package main
+
+import (
+ "github.com/TheTNB/panel/internal/app"
+ "github.com/TheTNB/panel/internal/bootstrap"
+ "github.com/TheTNB/panel/internal/data"
+ "github.com/TheTNB/panel/internal/route"
+ "github.com/TheTNB/panel/internal/service"
+)
+
+import (
+ _ "time/tzdata"
+)
+
+// Injectors from wire.go:
+
+// initCli init command line.
+func initCli() (*app.Cli, error) {
+ koanf, err := bootstrap.NewConf()
+ if err != nil {
+ return nil, err
+ }
+ logger := bootstrap.NewLog(koanf)
+ db, err := bootstrap.NewDB(koanf, logger)
+ if err != nil {
+ return nil, err
+ }
+ cacheRepo := data.NewCacheRepo(db)
+ queue := bootstrap.NewQueue()
+ taskRepo := data.NewTaskRepo(db, logger, queue)
+ appRepo := data.NewAppRepo(db, cacheRepo, taskRepo)
+ userRepo := data.NewUserRepo(db)
+ settingRepo := data.NewSettingRepo(db, koanf, taskRepo)
+ databaseServerRepo := data.NewDatabaseServerRepo(db, logger)
+ databaseUserRepo := data.NewDatabaseUserRepo(databaseServerRepo)
+ databaseRepo := data.NewDatabaseRepo(databaseServerRepo, databaseUserRepo)
+ certRepo := data.NewCertRepo(db)
+ certAccountRepo := data.NewCertAccountRepo(db, userRepo)
+ websiteRepo := data.NewWebsiteRepo(db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo)
+ backupRepo := data.NewBackupRepo(db, settingRepo, websiteRepo)
+ cliService := service.NewCliService(koanf, appRepo, cacheRepo, userRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo)
+ cli := route.NewCli(cliService)
+ command := bootstrap.NewCli(cli)
+ appCli := app.NewCli(command)
+ return appCli, nil
+}
diff --git a/cmd/web/main.go b/cmd/web/main.go
index 96b58e19..2ade59b5 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -17,11 +17,21 @@ along with this program. If not, see .
package main
import (
+ "os"
_ "time/tzdata"
-
- "github.com/TheTNB/panel/internal/bootstrap"
)
func main() {
- bootstrap.BootWeb()
+ if os.Geteuid() != 0 {
+ panic("panel must run as root")
+ }
+
+ web, err := initWeb()
+ if err != nil {
+ panic(err)
+ }
+
+ if err = web.Run(); err != nil {
+ panic(err)
+ }
}
diff --git a/cmd/web/wire.go b/cmd/web/wire.go
new file mode 100644
index 00000000..675ba564
--- /dev/null
+++ b/cmd/web/wire.go
@@ -0,0 +1,18 @@
+//go:build wireinject
+
+package main
+
+import (
+ "github.com/google/wire"
+
+ "github.com/TheTNB/panel/internal/app"
+ "github.com/TheTNB/panel/internal/bootstrap"
+ "github.com/TheTNB/panel/internal/data"
+ "github.com/TheTNB/panel/internal/route"
+ "github.com/TheTNB/panel/internal/service"
+)
+
+// initWeb init application.
+func initWeb() (*app.Web, error) {
+ panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, app.NewWeb))
+}
diff --git a/cmd/web/wire_gen.go b/cmd/web/wire_gen.go
new file mode 100644
index 00000000..6a92b743
--- /dev/null
+++ b/cmd/web/wire_gen.go
@@ -0,0 +1,101 @@
+// Code generated by Wire. DO NOT EDIT.
+
+//go:generate go run -mod=mod github.com/google/wire/cmd/wire
+//go:build !wireinject
+// +build !wireinject
+
+package main
+
+import (
+ "github.com/TheTNB/panel/internal/app"
+ "github.com/TheTNB/panel/internal/bootstrap"
+ "github.com/TheTNB/panel/internal/data"
+ "github.com/TheTNB/panel/internal/route"
+ "github.com/TheTNB/panel/internal/service"
+)
+
+import (
+ _ "time/tzdata"
+)
+
+// Injectors from wire.go:
+
+// initWeb init application.
+func initWeb() (*app.Web, error) {
+ koanf, err := bootstrap.NewConf()
+ if err != nil {
+ return nil, err
+ }
+ logger := bootstrap.NewLog(koanf)
+ db, err := bootstrap.NewDB(koanf, logger)
+ if err != nil {
+ return nil, err
+ }
+ manager, err := bootstrap.NewSession(koanf, db)
+ if err != nil {
+ return nil, err
+ }
+ userRepo := data.NewUserRepo(db)
+ userService := service.NewUserService(koanf, manager, userRepo)
+ queue := bootstrap.NewQueue()
+ taskRepo := data.NewTaskRepo(db, logger, queue)
+ cacheRepo := data.NewCacheRepo(db)
+ databaseServerRepo := data.NewDatabaseServerRepo(db, logger)
+ databaseUserRepo := data.NewDatabaseUserRepo(databaseServerRepo)
+ databaseRepo := data.NewDatabaseRepo(databaseServerRepo, databaseUserRepo)
+ certRepo := data.NewCertRepo(db)
+ certAccountRepo := data.NewCertAccountRepo(db, userRepo)
+ websiteRepo := data.NewWebsiteRepo(db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo)
+ appRepo := data.NewAppRepo(db, cacheRepo, taskRepo)
+ settingRepo := data.NewSettingRepo(db, koanf, taskRepo)
+ cronRepo := data.NewCronRepo(db)
+ backupRepo := data.NewBackupRepo(db, settingRepo, websiteRepo)
+ dashboardService := service.NewDashboardService(koanf, taskRepo, websiteRepo, appRepo, settingRepo, cronRepo, backupRepo)
+ taskService := service.NewTaskService(taskRepo)
+ websiteService := service.NewWebsiteService(websiteRepo, settingRepo)
+ databaseService := service.NewDatabaseService(databaseRepo)
+ databaseServerService := service.NewDatabaseServerService(databaseServerRepo)
+ databaseUserService := service.NewDatabaseUserService(databaseUserRepo)
+ backupService := service.NewBackupService(backupRepo)
+ certService := service.NewCertService(certRepo)
+ certDNSRepo := data.NewCertDNSRepo(db)
+ certDNSService := service.NewCertDNSService(certDNSRepo)
+ certAccountService := service.NewCertAccountService(certAccountRepo)
+ appService := service.NewAppService(appRepo, cacheRepo, settingRepo)
+ cronService := service.NewCronService(cronRepo)
+ processService := service.NewProcessService()
+ safeRepo := data.NewSafeRepo()
+ safeService := service.NewSafeService(safeRepo)
+ firewallService := service.NewFirewallService()
+ sshRepo := data.NewSSHRepo(db)
+ sshService := service.NewSSHService(sshRepo)
+ containerRepo := data.NewContainerRepo()
+ containerService := service.NewContainerService(containerRepo)
+ containerNetworkRepo := data.NewContainerNetworkRepo()
+ containerNetworkService := service.NewContainerNetworkService(containerNetworkRepo)
+ containerImageRepo := data.NewContainerImageRepo()
+ containerImageService := service.NewContainerImageService(containerImageRepo)
+ containerVolumeRepo := data.NewContainerVolumeRepo()
+ containerVolumeService := service.NewContainerVolumeService(containerVolumeRepo)
+ fileService := service.NewFileService(taskRepo)
+ monitorRepo := data.NewMonitorRepo(db, settingRepo)
+ monitorService := service.NewMonitorService(settingRepo, monitorRepo)
+ settingService := service.NewSettingService(settingRepo)
+ systemctlService := service.NewSystemctlService()
+ http := route.NewHttp(userService, dashboardService, taskService, websiteService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, cronService, processService, safeService, firewallService, sshService, containerService, containerNetworkService, containerImageService, containerVolumeService, fileService, monitorService, settingService, systemctlService)
+ wsService := service.NewWsService(koanf, sshRepo)
+ ws := route.NewWs(wsService)
+ mux, err := bootstrap.NewRouter(koanf, db, logger, manager, http, ws)
+ if err != nil {
+ return nil, err
+ }
+ server, err := bootstrap.NewHttp(koanf, mux)
+ if err != nil {
+ return nil, err
+ }
+ gormigrate := bootstrap.NewMigrate(db)
+ cron := bootstrap.NewCron(koanf, logger)
+ validation := bootstrap.NewValidator(db)
+ web := app.NewWeb(koanf, mux, server, gormigrate, cron, validation)
+ return web, nil
+}
diff --git a/go.mod b/go.mod
index b1aa3ea5..b8e7d4eb 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.23
require (
github.com/bddjr/hlfhr v1.3.5
github.com/beevik/ntp v1.4.3
+ github.com/cloudflare/tableflip v1.2.3
github.com/creack/pty v1.1.24
github.com/expr-lang/expr v1.16.9
github.com/glebarez/sqlite v1.11.0
@@ -18,6 +19,7 @@ require (
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a
github.com/gomodule/redigo v1.9.2
+ github.com/google/wire v0.6.0
github.com/gookit/validate v1.5.3
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-version v1.7.0
@@ -33,7 +35,6 @@ require (
github.com/mholt/acmez/v3 v3.0.0-20241214053340-45433dfc1161
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
@@ -73,12 +74,10 @@ 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.1051 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
- go.uber.org/goleak v1.3.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
diff --git a/go.sum b/go.sum
index f279c340..a1446083 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,8 @@ github.com/bddjr/hlfhr v1.3.5 h1:nBbye1k7XQ+4KJIGKQADk6lIuDUV+fcXG+TUUsFihPk=
github.com/bddjr/hlfhr v1.3.5/go.mod h1:oyIv4Q9JpCgZFdtH3KyTNWp7YYRWl4zl8k4ozrMAB4g=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
+github.com/cloudflare/tableflip v1.2.3 h1:8I+B99QnnEWPHOY3fWipwVKxS70LGgUsslG7CSfmHMw=
+github.com/cloudflare/tableflip v1.2.3/go.mod h1:P4gRehmV6Z2bY5ao5ml9Pd8u6kuEnlB37pUFMmv7j2E=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -54,14 +56,18 @@ github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a h1:BAyyIK6rc6Tq9
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a/go.mod h1:bgk4Ij/0OQ89UeoFFAQrSNhbbr4rKJ0fwWfo7wc+TCc=
github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s=
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
+github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4=
@@ -125,10 +131,6 @@ 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=
@@ -151,32 +153,81 @@ github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjc
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
-go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/app/cli.go b/internal/app/cli.go
new file mode 100644
index 00000000..e243af37
--- /dev/null
+++ b/internal/app/cli.go
@@ -0,0 +1,23 @@
+package app
+
+import (
+ "context"
+ "os"
+
+ "github.com/urfave/cli/v3"
+)
+
+type Cli struct {
+ cmd *cli.Command
+}
+
+func NewCli(cmd *cli.Command) *Cli {
+ IsCli = true
+ return &Cli{
+ cmd: cmd,
+ }
+}
+
+func (r *Cli) Run() error {
+ return r.cmd.Run(context.Background(), os.Args)
+}
diff --git a/internal/app/global.go b/internal/app/global.go
index 21eb7f10..70d54cbe 100644
--- a/internal/app/global.go
+++ b/internal/app/global.go
@@ -1,27 +1,11 @@
package app
import (
- "log/slog"
-
- "github.com/go-chi/chi/v5"
- "github.com/go-rat/sessions"
- "github.com/go-rat/utils/crypt"
- "github.com/knadh/koanf/v2"
- "github.com/robfig/cron/v3"
"gorm.io/gorm"
-
- "github.com/TheTNB/panel/pkg/queue"
)
var (
- Conf *koanf.Koanf
- Http *chi.Mux
- Orm *gorm.DB
- Session *sessions.Manager
- Cron *cron.Cron
- Queue *queue.Queue
- Logger *slog.Logger
- Crypter crypt.Crypter
+ Orm *gorm.DB
)
// 面板状态常量
diff --git a/internal/app/web.go b/internal/app/web.go
new file mode 100644
index 00000000..80d76a4b
--- /dev/null
+++ b/internal/app/web.go
@@ -0,0 +1,124 @@
+package app
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "runtime"
+ "syscall"
+ "time"
+
+ "github.com/bddjr/hlfhr"
+ "github.com/cloudflare/tableflip"
+ "github.com/go-chi/chi/v5"
+ "github.com/go-gormigrate/gormigrate/v2"
+ "github.com/gookit/validate"
+ "github.com/knadh/koanf/v2"
+ "github.com/robfig/cron/v3"
+)
+
+type Web struct {
+ conf *koanf.Koanf
+ router *chi.Mux
+ server *hlfhr.Server
+ migrator *gormigrate.Gormigrate
+ cron *cron.Cron
+}
+
+func NewWeb(conf *koanf.Koanf, router *chi.Mux, server *hlfhr.Server, migrator *gormigrate.Gormigrate, cron *cron.Cron, _ *validate.Validation) *Web {
+ return &Web{
+ conf: conf,
+ router: router,
+ server: server,
+ migrator: migrator,
+ cron: cron,
+ }
+}
+
+func (r *Web) Run() error {
+ // migrate database
+ if err := r.migrator.Migrate(); err != nil {
+ return err
+ }
+ fmt.Println("[DB] database migrated")
+
+ // start cron scheduler
+ r.cron.Start()
+ fmt.Println("[CRON] cron scheduler started")
+
+ // run http server
+ if runtime.GOOS != "windows" {
+ return r.runServer()
+ }
+
+ return r.runServerFallback()
+}
+
+// runServer graceful run server
+func (r *Web) runServer() error {
+ upg, err := tableflip.New(tableflip.Options{})
+ if err != nil {
+ return err
+ }
+ defer upg.Stop()
+
+ // By prefixing PID to log, easy to interrupt from another process.
+ log.SetPrefix(fmt.Sprintf("[PID %d]", os.Getpid()))
+
+ // Listen for the process signal to trigger the tableflip upgrade.
+ go func() {
+ sig := make(chan os.Signal, 1)
+ signal.Notify(sig, syscall.SIGHUP)
+ for range sig {
+ if err = upg.Upgrade(); err != nil {
+ log.Println("[Graceful] upgrade failed:", err)
+ }
+ }
+ }()
+
+ ln, err := upg.Listen("tcp", r.conf.MustString("http.address"))
+ if err != nil {
+ return err
+ }
+ defer ln.Close()
+
+ fmt.Println("[HTTP] listening and serving on", r.conf.MustString("http.address"))
+ go func() {
+ if err = r.server.Serve(ln); !errors.Is(err, http.ErrServerClosed) {
+ log.Println("[HTTP] server error:", err)
+ }
+ }()
+
+ // tableflip ready
+ if err = upg.Ready(); err != nil {
+ return err
+ }
+
+ fmt.Println("[Graceful] ready for upgrade")
+ <-upg.Exit()
+
+ // Make sure to set a deadline on exiting the process
+ // after upg.Exit() is closed. No new upgrades can be
+ // performed if the parent doesn't exit.
+ time.AfterFunc(60*time.Second, func() {
+ log.Println("[Graceful] shutdown timeout, force exit")
+ os.Exit(1)
+ })
+
+ // Wait for connections to drain.
+ return r.server.Shutdown(context.Background())
+}
+
+// runServerFallback fallback for windows
+func (r *Web) runServerFallback() error {
+ fmt.Println("[HTTP] listening and serving on", r.conf.MustString("http.address"))
+ if err := r.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+
+ return nil
+}
diff --git a/internal/apps/fail2ban/service.go b/internal/apps/fail2ban/service.go
index cecefbc9..b439a1e8 100644
--- a/internal/apps/fail2ban/service.go
+++ b/internal/apps/fail2ban/service.go
@@ -12,7 +12,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
@@ -24,7 +23,7 @@ type Service struct {
func NewService() *Service {
return &Service{
- websiteRepo: data.NewWebsiteRepo(),
+ websiteRepo: nil, // TODO fixme
}
}
diff --git a/internal/apps/mysql/service.go b/internal/apps/mysql/service.go
index 0b3003c2..e46a21b3 100644
--- a/internal/apps/mysql/service.go
+++ b/internal/apps/mysql/service.go
@@ -10,7 +10,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/db"
"github.com/TheTNB/panel/pkg/io"
@@ -26,7 +25,7 @@ type Service struct {
func NewService() *Service {
return &Service{
- settingRepo: data.NewSettingRepo(),
+ settingRepo: nil, // TODO fixme
}
}
diff --git a/internal/apps/php/service.go b/internal/apps/php/service.go
index e2799a74..59e4f450 100644
--- a/internal/apps/php/service.go
+++ b/internal/apps/php/service.go
@@ -13,7 +13,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
@@ -28,7 +27,7 @@ type Service struct {
func NewService(version uint) *Service {
return &Service{
version: version,
- taskRepo: data.NewTaskRepo(),
+ taskRepo: nil, // TODO fixme
}
}
diff --git a/internal/apps/s3fs/service.go b/internal/apps/s3fs/service.go
index 98a5030a..8d0aec22 100644
--- a/internal/apps/s3fs/service.go
+++ b/internal/apps/s3fs/service.go
@@ -10,7 +10,6 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
@@ -22,7 +21,7 @@ type Service struct {
func NewService() *Service {
return &Service{
- settingRepo: data.NewSettingRepo(),
+ settingRepo: nil, // TODO fixme
}
}
diff --git a/internal/biz/backup.go b/internal/biz/backup.go
index 04d327cb..e4f80643 100644
--- a/internal/biz/backup.go
+++ b/internal/biz/backup.go
@@ -21,4 +21,6 @@ type BackupRepo interface {
ClearExpired(path, prefix string, save int) error
CutoffLog(path, target string) error
GetPath(typ BackupType) (string, error)
+ FixPanel() error
+ UpdatePanel(version, url, checksum string) error
}
diff --git a/internal/biz/database_server.go b/internal/biz/database_server.go
index 67cec7b1..8b7d6b41 100644
--- a/internal/biz/database_server.go
+++ b/internal/biz/database_server.go
@@ -5,7 +5,6 @@ import (
"gorm.io/gorm"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -31,21 +30,23 @@ type DatabaseServer struct {
}
func (r *DatabaseServer) BeforeSave(tx *gorm.DB) error {
- var err error
+ // TODO fix
+ /*var err error
r.Password, err = app.Crypter.Encrypt([]byte(r.Password))
if err != nil {
return err
- }
+ }*/
return nil
}
func (r *DatabaseServer) AfterFind(tx *gorm.DB) error {
- password, err := app.Crypter.Decrypt(r.Password)
+ // TODO fix
+ /*password, err := app.Crypter.Decrypt(r.Password)
if err == nil {
r.Password = string(password)
- }
+ }*/
return nil
}
@@ -59,5 +60,6 @@ type DatabaseServerRepo interface {
Update(req *request.DatabaseServerUpdate) error
UpdateRemark(req *request.DatabaseServerUpdateRemark) error
Delete(id uint) error
+ ClearUsers(id uint) error
Sync(id uint) error
}
diff --git a/internal/biz/database_user.go b/internal/biz/database_user.go
index b80ddd7e..ddccb152 100644
--- a/internal/biz/database_user.go
+++ b/internal/biz/database_user.go
@@ -5,7 +5,6 @@ import (
"gorm.io/gorm"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -32,21 +31,23 @@ type DatabaseUser struct {
}
func (r *DatabaseUser) BeforeSave(tx *gorm.DB) error {
- var err error
+ // TODO fix
+ /*var err error
r.Password, err = app.Crypter.Encrypt([]byte(r.Password))
if err != nil {
return err
- }
+ }*/
return nil
}
func (r *DatabaseUser) AfterFind(tx *gorm.DB) error {
- password, err := app.Crypter.Decrypt(r.Password)
+ // TODO fix
+ /*password, err := app.Crypter.Decrypt(r.Password)
if err == nil {
r.Password = string(password)
- }
+ }*/
return nil
}
@@ -60,5 +61,4 @@ type DatabaseUserRepo interface {
UpdateRemark(req *request.DatabaseUserUpdateRemark) error
Delete(id uint) error
DeleteByNames(serverID uint, names []string) error
- DeleteByServerID(serverID uint) error
}
diff --git a/internal/biz/setting.go b/internal/biz/setting.go
index 72253956..bd4fa5c6 100644
--- a/internal/biz/setting.go
+++ b/internal/biz/setting.go
@@ -35,6 +35,4 @@ type SettingRepo interface {
Delete(key SettingKey) error
GetPanelSetting(ctx context.Context) (*request.PanelSetting, error)
UpdatePanelSetting(ctx context.Context, setting *request.PanelSetting) (bool, error)
- UpdatePanel(version, url, checksum string) error
- FixPanel() error
}
diff --git a/internal/biz/ssh.go b/internal/biz/ssh.go
index c944d3a8..e9e2422a 100644
--- a/internal/biz/ssh.go
+++ b/internal/biz/ssh.go
@@ -5,7 +5,6 @@ import (
"gorm.io/gorm"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/ssh"
)
@@ -22,7 +21,8 @@ type SSH struct {
}
func (r *SSH) BeforeSave(tx *gorm.DB) error {
- var err error
+ // TODO fix
+ /*var err error
r.Config.Key, err = app.Crypter.Encrypt([]byte(r.Config.Key))
if err != nil {
return err
@@ -30,21 +30,22 @@ func (r *SSH) BeforeSave(tx *gorm.DB) error {
r.Config.Password, err = app.Crypter.Encrypt([]byte(r.Config.Password))
if err != nil {
return err
- }
+ }*/
return nil
}
func (r *SSH) AfterFind(tx *gorm.DB) error {
- key, err := app.Crypter.Decrypt(r.Config.Key)
+ // TODO fix
+ /*key, err := app.Crypter.Decrypt(r.Config.Key)
if err == nil {
r.Config.Key = string(key)
}
password, err := app.Crypter.Decrypt(r.Config.Password)
if err == nil {
r.Config.Password = string(password)
- }
+ }*/
return nil
}
diff --git a/internal/bootstrap/app.go b/internal/bootstrap/app.go
deleted file mode 100644
index 79286242..00000000
--- a/internal/bootstrap/app.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package bootstrap
-
-import (
- "os"
-)
-
-func boot() {
- if os.Geteuid() != 0 {
- panic("panel must run as root")
- }
-
- initConf()
- initGlobal()
- initLogger()
- initOrm()
- runMigrate()
- bootCrypter()
-}
-
-func BootWeb() {
- boot()
- initSession()
- initQueue()
- initCron()
- initHttp()
-
- select {}
-}
-
-func BootCli() {
- boot()
- initCli()
-}
diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go
new file mode 100644
index 00000000..372c3140
--- /dev/null
+++ b/internal/bootstrap/bootstrap.go
@@ -0,0 +1,6 @@
+package bootstrap
+
+import "github.com/google/wire"
+
+// ProviderSet is bootstrap providers.
+var ProviderSet = wire.NewSet(NewConf, NewLog, NewCli, NewValidator, NewRouter, NewHttp, NewDB, NewMigrate, NewSession, NewCron, NewQueue, NewCrypter)
diff --git a/internal/bootstrap/cli.go b/internal/bootstrap/cli.go
index 59cd3ef9..9c538c5d 100644
--- a/internal/bootstrap/cli.go
+++ b/internal/bootstrap/cli.go
@@ -1,9 +1,6 @@
package bootstrap
import (
- "context"
- "fmt"
- "os"
"strings"
"github.com/urfave/cli/v3"
@@ -12,9 +9,7 @@ import (
"github.com/TheTNB/panel/internal/route"
)
-func initCli() {
- app.IsCli = true
-
+func NewCli(cmd *route.Cli) *cli.Command {
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "NAME", "名称")
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "USAGE", "用法")
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "VERSION", "版本")
@@ -38,13 +33,10 @@ func initCli() {
cli.RootCommandHelpTemplate += "\n论坛:https://bbs.haozi.net"
cli.RootCommandHelpTemplate += "\nQ群:12370907\n"
- cmd := &cli.Command{
+ return &cli.Command{
Name: "panel-cli",
Usage: "耗子面板命令行工具",
Version: app.Version,
- Commands: route.Cli(),
- }
- if err := cmd.Run(context.Background(), os.Args); err != nil {
- fmt.Printf("|-%v\n", err)
+ Commands: cmd.Commands(),
}
}
diff --git a/internal/bootstrap/conf.go b/internal/bootstrap/conf.go
index 740d0604..599e670a 100644
--- a/internal/bootstrap/conf.go
+++ b/internal/bootstrap/conf.go
@@ -12,29 +12,32 @@ import (
"github.com/TheTNB/panel/pkg/io"
)
-func initConf() {
+func NewConf() (*koanf.Koanf, error) {
config := "/usr/local/etc/panel/config.yml"
if !io.Exists(config) {
config = "config.yml"
}
- app.Conf = koanf.New(".")
- if err := app.Conf.Load(file.Provider(config), yaml.Parser()); err != nil {
- log.Fatalf("failed to load config: %v", err)
+ conf := koanf.New(".")
+ if err := conf.Load(file.Provider(config), yaml.Parser()); err != nil {
+ return nil, err
}
+
+ initGlobal(conf)
+ return conf, nil
}
-func initGlobal() {
- app.Key = app.Conf.MustString("app.key")
+func initGlobal(conf *koanf.Koanf) {
+ app.Key = conf.MustString("app.key")
if len(app.Key) != 32 {
log.Fatalf("app key must be 32 characters")
}
- app.Root = app.Conf.MustString("app.root")
- app.Locale = app.Conf.MustString("app.locale")
+ app.Root = conf.MustString("app.root")
+ app.Locale = conf.MustString("app.locale")
// 初始化时区
- loc, err := time.LoadLocation(app.Conf.MustString("app.timezone"))
+ loc, err := time.LoadLocation(conf.MustString("app.timezone"))
if err != nil {
log.Fatalf("failed to load timezone: %v", err)
}
diff --git a/internal/bootstrap/cron.go b/internal/bootstrap/cron.go
index 7b31d306..945da3a8 100644
--- a/internal/bootstrap/cron.go
+++ b/internal/bootstrap/cron.go
@@ -1,29 +1,22 @@
package bootstrap
import (
- "log"
+ "log/slog"
+ "github.com/knadh/koanf/v2"
"github.com/robfig/cron/v3"
- "github.com/TheTNB/panel/internal/app"
- "github.com/TheTNB/panel/internal/job"
pkgcron "github.com/TheTNB/panel/pkg/cron"
)
-func initCron() {
- logger := pkgcron.NewLogger(app.Logger, app.Conf.Bool("app.debug"))
- c := cron.New(
+func NewCron(conf *koanf.Koanf, log *slog.Logger) *cron.Cron {
+ logger := pkgcron.NewLogger(log, conf.Bool("app.debug"))
+
+ return cron.New(
cron.WithParser(cron.NewParser(
cron.SecondOptional|cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.Dow|cron.Descriptor,
)),
cron.WithLogger(logger),
cron.WithChain(cron.Recover(logger), cron.SkipIfStillRunning(logger)),
)
- app.Cron = c
-
- if err := job.Boot(app.Cron); err != nil {
- log.Fatalf("failed to boot cron jobs: %v", err)
- }
-
- c.Start()
}
diff --git a/internal/bootstrap/crypter.go b/internal/bootstrap/crypter.go
index 9aab50e2..a1be4526 100644
--- a/internal/bootstrap/crypter.go
+++ b/internal/bootstrap/crypter.go
@@ -1,18 +1,10 @@
package bootstrap
import (
- "log"
-
"github.com/go-rat/utils/crypt"
-
- "github.com/TheTNB/panel/internal/app"
+ "github.com/knadh/koanf/v2"
)
-func bootCrypter() {
- crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
- if err != nil {
- log.Fatalf("failed to create crypter: %v", err)
- }
-
- app.Crypter = crypter
+func NewCrypter(conf *koanf.Koanf) (crypt.Crypter, error) {
+ return crypt.NewXChacha20Poly1305([]byte(conf.MustString("app.key")))
}
diff --git a/internal/bootstrap/db.go b/internal/bootstrap/db.go
index ba826c84..0f5faacb 100644
--- a/internal/bootstrap/db.go
+++ b/internal/bootstrap/db.go
@@ -1,7 +1,8 @@
package bootstrap
import (
- "log"
+ "github.com/knadh/koanf/v2"
+ "log/slog"
"path/filepath"
"github.com/glebarez/sqlite"
@@ -13,23 +14,17 @@ import (
"github.com/TheTNB/panel/internal/migration"
)
-func initOrm() {
- db, err := gorm.Open(sqlite.Open(filepath.Join(app.Root, "panel/storage/app.db")), &gorm.Config{
- Logger: slogGorm.New(slogGorm.WithHandler(app.Logger.Handler())),
+func NewDB(conf *koanf.Koanf, log *slog.Logger) (*gorm.DB, error) {
+ // You can use any other database, like MySQL or PostgreSQL.
+ return gorm.Open(sqlite.Open(filepath.Join(app.Root, "panel/storage/app.db")), &gorm.Config{
+ Logger: slogGorm.New(slogGorm.WithHandler(log.Handler())),
SkipDefaultTransaction: true,
DisableForeignKeyConstraintWhenMigrating: true,
})
- if err != nil {
- log.Fatalf("failed to connect database: %v", err)
- }
- app.Orm = db
}
-func runMigrate() {
- migrator := gormigrate.New(app.Orm, &gormigrate.Options{
+func NewMigrate(db *gorm.DB) *gormigrate.Gormigrate {
+ return gormigrate.New(db, &gormigrate.Options{
UseTransaction: true, // Note: MySQL not support DDL transaction
}, migration.Migrations)
- if err := migrator.Migrate(); err != nil {
- log.Fatalf("failed to migrate database: %v", err)
- }
}
diff --git a/internal/bootstrap/http.go b/internal/bootstrap/http.go
index d3e3ca19..06a9532e 100644
--- a/internal/bootstrap/http.go
+++ b/internal/bootstrap/http.go
@@ -2,55 +2,46 @@ package bootstrap
import (
"crypto/tls"
- "fmt"
- "log"
- "net/http"
- "path/filepath"
-
"github.com/bddjr/hlfhr"
"github.com/go-chi/chi/v5"
+ "github.com/go-rat/sessions"
+ "github.com/knadh/koanf/v2"
+ "gorm.io/gorm"
+ "log/slog"
+ "net/http"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/http/middleware"
"github.com/TheTNB/panel/internal/route"
)
-func initHttp() {
- app.Http = chi.NewRouter()
+func NewRouter(conf *koanf.Koanf, db *gorm.DB, log *slog.Logger, session *sessions.Manager, http *route.Http, ws *route.Ws) (*chi.Mux, error) {
+ r := chi.NewRouter()
// add middleware
- app.Http.Use(middleware.GlobalMiddleware()...)
+ r.Use(middleware.GlobalMiddleware(r, conf, db, log, session)...)
+ // add http route
+ http.Register(r)
+ // add ws route
+ ws.Register(r)
- // add route
- route.Http(app.Http)
- route.Ws(app.Http)
+ return r, nil
+}
+func NewHttp(conf *koanf.Koanf, r *chi.Mux) (*hlfhr.Server, error) {
srv := hlfhr.New(&http.Server{
- Addr: fmt.Sprintf(":%d", app.Conf.MustInt("http.port")),
- Handler: http.AllowQuerySemicolons(app.Http),
+ Addr: conf.MustString("http.address"),
+ Handler: http.AllowQuerySemicolons(r),
MaxHeaderBytes: 2048 << 20,
})
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hlfhr.RedirectToHttps(w, r, http.StatusTemporaryRedirect)
})
- if app.Conf.Bool("http.tls") {
+ if conf.Bool("http.tls") {
srv.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS13,
}
-
- cert := filepath.Join(app.Root, "panel/storage/cert.pem")
- key := filepath.Join(app.Root, "panel/storage/cert.key")
- go func() {
- if err := srv.ListenAndServeTLS(cert, key); err != nil {
- log.Fatalf("failed to start https server: %v", err)
- }
- }()
- } else {
- go func() {
- if err := srv.ListenAndServe(); err != nil {
- log.Fatalf("failed to start http server: %v", err)
- }
- }()
}
+
+ return srv, nil
}
diff --git a/internal/bootstrap/logger.go b/internal/bootstrap/logger.go
index 83277f7b..98780839 100644
--- a/internal/bootstrap/logger.go
+++ b/internal/bootstrap/logger.go
@@ -1,6 +1,7 @@
package bootstrap
import (
+ "github.com/knadh/koanf/v2"
"log/slog"
"path/filepath"
@@ -8,7 +9,7 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
)
-func initLogger() {
+func NewLog(conf *koanf.Koanf) *slog.Logger {
ljLogger := &lumberjack.Logger{
Filename: filepath.Join(app.Root, "panel/storage/logs/app.log"),
MaxSize: 10,
@@ -17,12 +18,14 @@ func initLogger() {
}
level := slog.LevelInfo
- if app.Conf.Bool("app.debug") {
+ if conf.Bool("app.debug") {
level = slog.LevelDebug
}
- app.Logger = slog.New(slog.NewJSONHandler(ljLogger, &slog.HandlerOptions{
+ log := slog.New(slog.NewJSONHandler(ljLogger, &slog.HandlerOptions{
Level: level,
}))
- slog.SetDefault(app.Logger)
+ slog.SetDefault(log)
+
+ return log
}
diff --git a/internal/bootstrap/queue.go b/internal/bootstrap/queue.go
index 19d7ab06..199a0b77 100644
--- a/internal/bootstrap/queue.go
+++ b/internal/bootstrap/queue.go
@@ -1,13 +1,9 @@
package bootstrap
import (
- "context"
-
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/pkg/queue"
)
-func initQueue() {
- app.Queue = queue.New(100)
- go app.Queue.Run(context.Background())
+func NewQueue() *queue.Queue {
+ return queue.New(100)
}
diff --git a/internal/bootstrap/session.go b/internal/bootstrap/session.go
index 5a867da0..20dcfc20 100644
--- a/internal/bootstrap/session.go
+++ b/internal/bootstrap/session.go
@@ -1,31 +1,29 @@
package bootstrap
import (
- "log"
-
"github.com/go-rat/gormstore"
"github.com/go-rat/sessions"
-
- "github.com/TheTNB/panel/internal/app"
+ "github.com/knadh/koanf/v2"
+ "gorm.io/gorm"
)
-func initSession() {
+func NewSession(conf *koanf.Koanf, db *gorm.DB) (*sessions.Manager, error) {
// initialize session manager
manager, err := sessions.NewManager(&sessions.ManagerOptions{
- Key: app.Key,
+ Key: conf.MustString("app.key"),
Lifetime: 120,
GcInterval: 30,
DisableDefaultDriver: true,
})
if err != nil {
- log.Fatalf("failed to initialize session manager: %v", err)
+ return nil, err
}
// extend gorm store driver
- store := gormstore.New(app.Orm)
+ store := gormstore.New(db)
if err = manager.Extend("default", store); err != nil {
- log.Fatalf("failed to extend session manager: %v", err)
+ return nil, err
}
- app.Session = manager
+ return manager, nil
}
diff --git a/internal/bootstrap/validator.go b/internal/bootstrap/validator.go
index 4d64fe19..d2a9fee4 100644
--- a/internal/bootstrap/validator.go
+++ b/internal/bootstrap/validator.go
@@ -3,13 +3,22 @@ package bootstrap
import (
"github.com/gookit/validate"
"github.com/gookit/validate/locales/zhcn"
+ "gorm.io/gorm"
+
+ "github.com/TheTNB/panel/internal/http/rule"
)
-func init() {
+// NewValidator just for register global rules
+func NewValidator(db *gorm.DB) *validate.Validation {
zhcn.RegisterGlobal()
validate.Config(func(opt *validate.GlobalOption) {
opt.StopOnError = false
opt.SkipOnEmpty = true
opt.FieldTag = "form"
})
+
+ // register global rules
+ rule.GlobalRules(db)
+
+ return validate.NewEmpty()
}
diff --git a/internal/data/app.go b/internal/data/app.go
index 046a0e9e..461d0f3a 100644
--- a/internal/data/app.go
+++ b/internal/data/app.go
@@ -4,12 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
+ "gorm.io/gorm"
"slices"
"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"
@@ -18,14 +18,22 @@ import (
"github.com/TheTNB/panel/pkg/shell"
)
-type appRepo struct{}
+type appRepo struct {
+ db *gorm.DB
+ cache biz.CacheRepo
+ task biz.TaskRepo
+}
-func NewAppRepo() biz.AppRepo {
- return do.MustInvoke[biz.AppRepo](injector)
+func NewAppRepo(db *gorm.DB, cache biz.CacheRepo, task biz.TaskRepo) biz.AppRepo {
+ return &appRepo{
+ db: db,
+ cache: cache,
+ task: task,
+ }
}
func (r *appRepo) All() api.Apps {
- cached, err := NewCacheRepo().Get(biz.CacheKeyApps)
+ cached, err := r.cache.Get(biz.CacheKeyApps)
if err != nil {
return nil
}
@@ -69,7 +77,7 @@ func (r *appRepo) UpdateExist(slug string) bool {
func (r *appRepo) Installed() ([]*biz.App, error) {
var apps []*biz.App
- if err := app.Orm.Find(&apps).Error; err != nil {
+ if err := r.db.Find(&apps).Error; err != nil {
return nil, err
}
@@ -79,7 +87,7 @@ func (r *appRepo) Installed() ([]*biz.App, error) {
func (r *appRepo) GetInstalled(slug string) (*biz.App, error) {
installed := new(biz.App)
- if err := app.Orm.Where("slug = ?", slug).First(installed).Error; err != nil {
+ if err := r.db.Where("slug = ?", slug).First(installed).Error; err != nil {
return nil, err
}
@@ -88,7 +96,7 @@ func (r *appRepo) GetInstalled(slug string) (*biz.App, error) {
func (r *appRepo) GetInstalledAll(query string, cond ...string) ([]*biz.App, error) {
var apps []*biz.App
- if err := app.Orm.Where(query, cond).Find(&apps).Error; err != nil {
+ if err := r.db.Where(query, cond).Find(&apps).Error; err != nil {
return nil, err
}
@@ -97,7 +105,7 @@ func (r *appRepo) GetInstalledAll(query string, cond ...string) ([]*biz.App, err
func (r *appRepo) GetHomeShow() ([]map[string]string, error) {
var apps []*biz.App
- if err := app.Orm.Where("show = ?", true).Order("show_order").Find(&apps).Error; err != nil {
+ if err := r.db.Where("show = ?", true).Order("show_order").Find(&apps).Error; err != nil {
return nil, err
}
@@ -122,11 +130,11 @@ func (r *appRepo) GetHomeShow() ([]map[string]string, error) {
func (r *appRepo) IsInstalled(query string, cond ...string) (bool, error) {
var count int64
if len(cond) == 0 {
- if err := app.Orm.Model(&biz.App{}).Where("slug = ?", query).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.App{}).Where("slug = ?", query).Count(&count).Error; err != nil {
return false, err
}
} else {
- if err := app.Orm.Model(&biz.App{}).Where(query, cond).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.App{}).Where(query, cond).Count(&count).Error; err != nil {
return false, err
}
}
@@ -182,7 +190,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 NewTaskRepo().Push(task)
+ return r.task.Push(task)
}
func (r *appRepo) UnInstall(slug string) error {
@@ -237,7 +245,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 NewTaskRepo().Push(task)
+ return r.task.Push(task)
}
func (r *appRepo) Update(slug string) error {
@@ -292,7 +300,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 NewTaskRepo().Push(task)
+ return r.task.Push(task)
}
func (r *appRepo) UpdateShow(slug string, show bool) error {
@@ -303,7 +311,7 @@ func (r *appRepo) UpdateShow(slug string, show bool) error {
item.Show = show
- return app.Orm.Save(item).Error
+ return r.db.Save(item).Error
}
func (r *appRepo) preCheck(app *api.App) error {
diff --git a/internal/data/backup.go b/internal/data/backup.go
index 0c34401d..b0d5cb6d 100644
--- a/internal/data/backup.go
+++ b/internal/data/backup.go
@@ -3,13 +3,13 @@ package data
import (
"errors"
"fmt"
+ "gorm.io/gorm"
"os"
"path/filepath"
"slices"
"strings"
"time"
- "github.com/samber/do/v2"
"github.com/shirou/gopsutil/disk"
"github.com/TheTNB/panel/internal/app"
@@ -21,10 +21,18 @@ import (
"github.com/TheTNB/panel/pkg/types"
)
-type backupRepo struct{}
+type backupRepo struct {
+ db *gorm.DB
+ setting biz.SettingRepo
+ website biz.WebsiteRepo
+}
-func NewBackupRepo() biz.BackupRepo {
- return do.MustInvoke[biz.BackupRepo](injector)
+func NewBackupRepo(db *gorm.DB, setting biz.SettingRepo, website biz.WebsiteRepo) biz.BackupRepo {
+ return &backupRepo{
+ db: db,
+ setting: setting,
+ website: website,
+ }
}
// List 备份列表
@@ -192,7 +200,7 @@ func (r *backupRepo) ClearExpired(path, prefix string, save int) error {
// GetPath 获取备份路径
func (r *backupRepo) GetPath(typ biz.BackupType) (string, error) {
- backupPath, err := NewSettingRepo().Get(biz.SettingKeyBackupPath)
+ backupPath, err := r.setting.Get(biz.SettingKeyBackupPath)
if err != nil {
return "", err
}
@@ -212,7 +220,7 @@ func (r *backupRepo) GetPath(typ biz.BackupType) (string, error) {
// createWebsite 创建网站备份
func (r *backupRepo) createWebsite(to string, name string) error {
- website, err := NewWebsiteRepo().GetByName(name)
+ website, err := r.website.GetByName(name)
if err != nil {
return err
}
@@ -236,7 +244,7 @@ func (r *backupRepo) createWebsite(to string, name string) error {
// createMySQL 创建 MySQL 备份
func (r *backupRepo) createMySQL(to string, name string) error {
- rootPassword, err := NewSettingRepo().Get(biz.SettingKeyMySQLRootPassword)
+ rootPassword, err := r.setting.Get(biz.SettingKeyMySQLRootPassword)
if err != nil {
return err
}
@@ -367,7 +375,7 @@ func (r *backupRepo) restoreWebsite(backup, target string) error {
return errors.New("备份文件不存在")
}
- website, err := NewWebsiteRepo().GetByName(target)
+ website, err := r.website.GetByName(target)
if err != nil {
return err
}
@@ -394,7 +402,7 @@ func (r *backupRepo) restoreMySQL(backup, target string) error {
return errors.New("备份文件不存在")
}
- rootPassword, err := NewSettingRepo().Get(biz.SettingKeyMySQLRootPassword)
+ rootPassword, err := r.setting.Get(biz.SettingKeyMySQLRootPassword)
if err != nil {
return err
}
@@ -542,3 +550,265 @@ func (r *backupRepo) autoUnCompressSQL(backup string) (string, error) {
return backup, nil
}
+
+func (r *backupRepo) FixPanel() error {
+ if app.IsCli {
+ fmt.Println("|-开始修复面板...")
+ }
+
+ // 检查关键文件是否正常
+ flag := false
+ if !io.Exists(filepath.Join(app.Root, "panel", "web")) {
+ flag = true
+ }
+ if !io.Exists(filepath.Join(app.Root, "panel", "storage", "app.db")) {
+ flag = true
+ }
+ if io.Exists("/tmp/panel-storage.zip") {
+ flag = true
+ }
+ if !flag {
+ return fmt.Errorf("文件正常无需修复,请运行 panel-cli update 更新面板")
+ }
+
+ // 再次确认是否需要修复
+ if io.Exists("/tmp/panel-storage.zip") {
+ // 文件齐全情况下只移除临时文件
+ if io.Exists(filepath.Join(app.Root, "panel", "web")) &&
+ io.Exists(filepath.Join(app.Root, "panel", "storage", "app.db")) &&
+ io.Exists("/usr/local/etc/panel/config.yml") {
+ if err := io.Remove("/tmp/panel-storage.zip"); err != nil {
+ return fmt.Errorf("清理临时文件失败:%w", err)
+ }
+ if app.IsCli {
+ fmt.Println("|-已清理临时文件,请运行 panel-cli update 更新面板")
+ }
+ return nil
+ }
+ }
+
+ // 从备份目录中找最新的备份文件
+ list, err := r.List(biz.BackupTypePanel)
+ if err != nil {
+ return err
+ }
+ slices.SortFunc(list, func(a *types.BackupFile, b *types.BackupFile) int {
+ return int(b.Time.Unix() - a.Time.Unix())
+ })
+ if len(list) == 0 {
+ return fmt.Errorf("未找到备份文件,无法自动修复")
+ }
+ latest := list[0]
+ if app.IsCli {
+ fmt.Printf("|-使用备份文件:%s\n", latest.Name)
+ }
+
+ // 解压备份文件
+ if app.IsCli {
+ fmt.Println("|-解压备份文件...")
+ }
+ if err = io.Remove("/tmp/panel-fix"); err != nil {
+ return fmt.Errorf("清理临时目录失败:%w", err)
+ }
+ if err = io.UnCompress(latest.Path, "/tmp/panel-fix"); err != nil {
+ return fmt.Errorf("解压备份文件失败:%w", err)
+ }
+
+ // 移动文件到对应位置
+ if app.IsCli {
+ fmt.Println("|-移动备份文件...")
+ }
+ if io.Exists(filepath.Join("/tmp/panel-fix", "panel")) && io.IsDir(filepath.Join("/tmp/panel-fix", "panel")) {
+ if err = io.Remove(filepath.Join(app.Root, "panel")); err != nil {
+ return fmt.Errorf("删除目录失败:%w", err)
+ }
+ if err = io.Mv(filepath.Join("/tmp/panel-fix", "panel"), filepath.Join(app.Root)); err != nil {
+ return fmt.Errorf("移动目录失败:%w", err)
+ }
+ }
+ if io.Exists(filepath.Join("/tmp/panel-fix", "config.yml")) {
+ if err = io.Mv(filepath.Join("/tmp/panel-fix", "config.yml"), "/usr/local/etc/panel/config.yml"); err != nil {
+ return fmt.Errorf("移动文件失败:%w", err)
+ }
+ }
+ if io.Exists(filepath.Join("/tmp/panel-fix", "panel-cli")) {
+ if err = io.Mv(filepath.Join("/tmp/panel-fix", "panel-cli"), "/usr/local/sbin/panel-cli"); err != nil {
+ return fmt.Errorf("移动文件失败:%w", err)
+ }
+ }
+
+ // tmp 目录下如果有 storage 备份,则解压回去
+ if app.IsCli {
+ fmt.Println("|-恢复面板数据...")
+ }
+ if io.Exists("/tmp/panel-storage.zip") {
+ if err = io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel")); err != nil {
+ return fmt.Errorf("恢复面板数据失败:%w", err)
+ }
+ if err = io.Remove("/tmp/panel-storage.zip"); err != nil {
+ return fmt.Errorf("清理临时文件失败:%w", err)
+ }
+ }
+
+ // 下载服务文件
+ if !io.Exists("/etc/systemd/system/panel.service") {
+ if _, err = shell.Execf(`wget -O /etc/systemd/system/panel.service https://dl.cdn.haozi.net/panel/panel.service && sed -i "s|/www|%s|g" /etc/systemd/system/panel.service`, app.Root); err != nil {
+ return err
+ }
+ }
+
+ // 处理权限
+ if app.IsCli {
+ fmt.Println("|-设置关键文件权限...")
+ }
+ if err = io.Chmod("/usr/local/etc/panel/config.yml", 0600); err != nil {
+ return err
+ }
+ if err = io.Chmod("/etc/systemd/system/panel.service", 0700); err != nil {
+ return err
+ }
+ if err = io.Chmod("/usr/local/sbin/panel-cli", 0700); err != nil {
+ return err
+ }
+ if err = io.Chmod(filepath.Join(app.Root, "panel"), 0700); err != nil {
+ return err
+ }
+
+ if app.IsCli {
+ fmt.Println("|-修复完成")
+ }
+
+ tools.RestartPanel()
+ return nil
+}
+
+func (r *backupRepo) UpdatePanel(version, url, checksum string) error {
+ // 预先优化数据库
+ if err := r.db.Exec("VACUUM").Error; err != nil {
+ return err
+ }
+ if err := r.db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error; err != nil {
+ return err
+ }
+
+ name := filepath.Base(url)
+ if app.IsCli {
+ fmt.Printf("|-目标版本:%s\n", version)
+ fmt.Printf("|-下载链接:%s\n", url)
+ fmt.Printf("|-文件名:%s\n", name)
+ }
+
+ if app.IsCli {
+ fmt.Println("|-正在下载...")
+ }
+ if _, err := shell.Execf("wget -T 120 -t 3 -O /tmp/%s %s", name, url); err != nil {
+ return fmt.Errorf("下载失败:%w", err)
+ }
+ if _, err := shell.Execf("wget -T 20 -t 3 -O /tmp/%s %s", name+".sha256", checksum); err != nil {
+ return fmt.Errorf("下载失败:%w", err)
+ }
+ if !io.Exists(filepath.Join("/tmp", name)) || !io.Exists(filepath.Join("/tmp", name+".sha256")) {
+ return errors.New("下载文件检查失败")
+ }
+
+ if app.IsCli {
+ fmt.Println("|-校验下载文件...")
+ }
+ if check, err := shell.Execf("cd /tmp && sha256sum -c %s --ignore-missing", name+".sha256"); check != name+": OK" || err != nil {
+ return errors.New("下载文件校验失败")
+ }
+ if err := io.Remove(filepath.Join("/tmp", name+".sha256")); err != nil {
+ if app.IsCli {
+ fmt.Println("|-清理校验文件失败:", err)
+ }
+ return fmt.Errorf("清理校验文件失败:%w", err)
+ }
+
+ if app.IsCli {
+ fmt.Println("|-前置检查...")
+ }
+ if io.Exists("/tmp/panel-storage.zip") {
+ return errors.New("检测到 /tmp 存在临时文件,可能是上次更新失败所致,请运行 panel-cli fix 修复后重试")
+ }
+
+ if app.IsCli {
+ fmt.Println("|-备份面板数据...")
+ }
+ // 备份面板
+ if err := r.Create(biz.BackupTypePanel, ""); err != nil {
+ if app.IsCli {
+ fmt.Println("|-备份面板失败:", err)
+ }
+ return fmt.Errorf("备份面板失败:%w", err)
+ }
+ if err := io.Compress(filepath.Join(app.Root, "panel/storage"), nil, "/tmp/panel-storage.zip"); err != nil {
+ if app.IsCli {
+ fmt.Println("|-备份面板数据失败:", err)
+ }
+ return fmt.Errorf("备份面板数据失败:%w", err)
+ }
+ if !io.Exists("/tmp/panel-storage.zip") {
+ return errors.New("已备份面板数据检查失败")
+ }
+
+ if app.IsCli {
+ fmt.Println("|-清理旧版本...")
+ }
+ if _, err := shell.Execf("rm -rf %s/panel/*", app.Root); err != nil {
+ return fmt.Errorf("清理旧版本失败:%w", err)
+ }
+
+ if app.IsCli {
+ fmt.Println("|-解压新版本...")
+ }
+ if err := io.UnCompress(filepath.Join("/tmp", name), filepath.Join(app.Root, "panel")); err != nil {
+ return fmt.Errorf("解压失败:%w", err)
+ }
+ if !io.Exists(filepath.Join(app.Root, "panel", "web")) {
+ return errors.New("解压失败,缺失文件")
+ }
+
+ if app.IsCli {
+ fmt.Println("|-恢复面板数据...")
+ }
+ if err := io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel", "storage")); err != nil {
+ return fmt.Errorf("恢复面板数据失败:%w", err)
+ }
+ if !io.Exists(filepath.Join(app.Root, "panel/storage/app.db")) {
+ return errors.New("恢复面板数据失败")
+ }
+
+ if app.IsCli {
+ fmt.Println("|-运行更新后脚本...")
+ }
+ if _, err := shell.Execf("curl -fsLm 10 https://dl.cdn.haozi.net/panel/auto_update.sh | bash"); err != nil {
+ return fmt.Errorf("运行面板更新后脚本失败:%w", err)
+ }
+ if _, err := shell.Execf(`wget -O /etc/systemd/system/panel.service https://dl.cdn.haozi.net/panel/panel.service && sed -i "s|/www|%s|g" /etc/systemd/system/panel.service`, app.Root); err != nil {
+ return fmt.Errorf("下载面板服务文件失败:%w", err)
+ }
+ if _, err := shell.Execf("panel-cli setting write version %s", version); err != nil {
+ return fmt.Errorf("写入面板版本号失败:%w", err)
+ }
+ if err := io.Mv(filepath.Join(app.Root, "panel/cli"), "/usr/local/sbin/panel-cli"); err != nil {
+ return fmt.Errorf("移动面板命令行工具失败:%w", err)
+ }
+
+ if app.IsCli {
+ fmt.Println("|-设置关键文件权限...")
+ }
+ _ = io.Chmod("/usr/local/sbin/panel-cli", 0700)
+ _ = io.Chmod("/etc/systemd/system/panel.service", 0700)
+ _ = io.Chmod(filepath.Join(app.Root, "panel"), 0700)
+
+ if app.IsCli {
+ fmt.Println("|-更新完成")
+ }
+
+ _, _ = shell.Execf("systemctl daemon-reload")
+ _ = io.Remove("/tmp/panel-storage.zip")
+ _ = io.Remove(filepath.Join(app.Root, "panel/config.example.yml"))
+ tools.RestartPanel()
+
+ return nil
+}
diff --git a/internal/data/cache.go b/internal/data/cache.go
index 962442d3..72ae99af 100644
--- a/internal/data/cache.go
+++ b/internal/data/cache.go
@@ -5,7 +5,6 @@ import (
"errors"
"slices"
- "github.com/samber/do/v2"
"gorm.io/gorm"
"github.com/TheTNB/panel/internal/app"
@@ -16,15 +15,19 @@ import (
type cacheRepo struct {
api *api.API
+ db *gorm.DB
}
-func NewCacheRepo() biz.CacheRepo {
- return do.MustInvoke[biz.CacheRepo](injector)
+func NewCacheRepo(db *gorm.DB) biz.CacheRepo {
+ return &cacheRepo{
+ api: api.NewAPI(app.Version),
+ db: db,
+ }
}
func (r *cacheRepo) Get(key biz.CacheKey, defaultValue ...string) (string, error) {
cache := new(biz.Cache)
- if err := app.Orm.Where("key = ?", key).First(cache).Error; err != nil {
+ if err := r.db.Where("key = ?", key).First(cache).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return "", err
}
@@ -39,12 +42,12 @@ func (r *cacheRepo) Get(key biz.CacheKey, defaultValue ...string) (string, error
func (r *cacheRepo) Set(key biz.CacheKey, value string) error {
cache := new(biz.Cache)
- if err := app.Orm.Where(biz.Cache{Key: key}).FirstOrInit(cache).Error; err != nil {
+ if err := r.db.Where(biz.Cache{Key: key}).FirstOrInit(cache).Error; err != nil {
return err
}
cache.Value = value
- return app.Orm.Save(cache).Error
+ return r.db.Save(cache).Error
}
func (r *cacheRepo) UpdateApps() error {
diff --git a/internal/data/cert.go b/internal/data/cert.go
index 5b78d753..946a45f9 100644
--- a/internal/data/cert.go
+++ b/internal/data/cert.go
@@ -4,12 +4,11 @@ import (
"context"
"errors"
"fmt"
+ "gorm.io/gorm"
"slices"
"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"
@@ -22,17 +21,20 @@ import (
)
type certRepo struct {
+ db *gorm.DB
client *acme.Client
}
-func NewCertRepo() biz.CertRepo {
- return do.MustInvoke[biz.CertRepo](injector)
+func NewCertRepo(db *gorm.DB) biz.CertRepo {
+ return &certRepo{
+ db: db,
+ }
}
func (r *certRepo) List(page, limit uint) ([]*types.CertList, int64, error) {
var certs []*biz.Cert
var total int64
- err := app.Orm.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&certs).Error
+ err := r.db.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&certs).Error
list := make([]*types.CertList, 0)
for cert := range slices.Values(certs) {
@@ -64,13 +66,13 @@ func (r *certRepo) List(page, limit uint) ([]*types.CertList, int64, error) {
func (r *certRepo) Get(id uint) (*biz.Cert, error) {
cert := new(biz.Cert)
- err := app.Orm.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Where("id = ?", id).First(cert).Error
+ err := r.db.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Where("id = ?", id).First(cert).Error
return cert, err
}
func (r *certRepo) GetByWebsite(WebsiteID uint) (*biz.Cert, error) {
cert := new(biz.Cert)
- err := app.Orm.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Where("website_id = ?", WebsiteID).First(cert).Error
+ err := r.db.Model(&biz.Cert{}).Preload("Website").Preload("Account").Preload("DNS").Where("website_id = ?", WebsiteID).First(cert).Error
return cert, err
}
@@ -89,7 +91,7 @@ func (r *certRepo) Upload(req *request.CertUpload) (*biz.Cert, error) {
Cert: req.Cert,
Key: req.Key,
}
- if err = app.Orm.Create(cert).Error; err != nil {
+ if err = r.db.Create(cert).Error; err != nil {
return nil, err
}
@@ -105,7 +107,7 @@ func (r *certRepo) Create(req *request.CertCreate) (*biz.Cert, error) {
Domains: req.Domains,
AutoRenew: req.AutoRenew,
}
- if err := app.Orm.Create(cert).Error; err != nil {
+ if err := r.db.Create(cert).Error; err != nil {
return nil, err
}
return cert, nil
@@ -117,7 +119,7 @@ func (r *certRepo) Update(req *request.CertUpdate) error {
req.Domains = info.DNSNames
}
- return app.Orm.Model(&biz.Cert{}).Where("id = ?", req.ID).Select("*").Updates(&biz.Cert{
+ return r.db.Model(&biz.Cert{}).Where("id = ?", req.ID).Select("*").Updates(&biz.Cert{
ID: req.ID,
AccountID: req.AccountID,
WebsiteID: req.WebsiteID,
@@ -131,7 +133,7 @@ func (r *certRepo) Update(req *request.CertUpdate) error {
}
func (r *certRepo) Delete(id uint) error {
- return app.Orm.Model(&biz.Cert{}).Where("id = ?", id).Delete(&biz.Cert{}).Error
+ return r.db.Model(&biz.Cert{}).Where("id = ?", id).Delete(&biz.Cert{}).Error
}
func (r *certRepo) ObtainAuto(id uint) (*acme.Certificate, error) {
@@ -169,7 +171,7 @@ func (r *certRepo) ObtainAuto(id uint) (*acme.Certificate, error) {
cert.CertURL = ssl.URL
cert.Cert = string(ssl.ChainPEM)
cert.Key = string(ssl.PrivateKey)
- if err = app.Orm.Save(cert).Error; err != nil {
+ if err = r.db.Save(cert).Error; err != nil {
return nil, err
}
@@ -198,7 +200,7 @@ func (r *certRepo) ObtainManual(id uint) (*acme.Certificate, error) {
cert.CertURL = ssl.URL
cert.Cert = string(ssl.ChainPEM)
cert.Key = string(ssl.PrivateKey)
- if err = app.Orm.Save(cert).Error; err != nil {
+ if err = r.db.Save(cert).Error; err != nil {
return nil, err
}
@@ -222,7 +224,7 @@ func (r *certRepo) ObtainSelfSigned(id uint) error {
cert.Cert = string(crt)
cert.Key = string(key)
- if err = app.Orm.Save(cert).Error; err != nil {
+ if err = r.db.Save(cert).Error; err != nil {
return err
}
@@ -272,7 +274,7 @@ func (r *certRepo) Renew(id uint) (*acme.Certificate, error) {
cert.CertURL = ssl.URL
cert.Cert = string(ssl.ChainPEM)
cert.Key = string(ssl.PrivateKey)
- if err = app.Orm.Save(cert).Error; err != nil {
+ if err = r.db.Save(cert).Error; err != nil {
return nil, err
}
@@ -319,8 +321,8 @@ func (r *certRepo) Deploy(ID, WebsiteID uint) error {
return errors.New("this certificate has not been signed successfully and cannot be deployed")
}
- website, err := NewWebsiteRepo().Get(WebsiteID)
- if err != nil {
+ website := new(biz.Website)
+ if err = r.db.Where("id", WebsiteID).First(website).Error; err != nil {
return err
}
diff --git a/internal/data/cert_account.go b/internal/data/cert_account.go
index 1a616564..83ae4bb7 100644
--- a/internal/data/cert_account.go
+++ b/internal/data/cert_account.go
@@ -4,39 +4,43 @@ import (
"context"
"errors"
"fmt"
+ "gorm.io/gorm"
"time"
- "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/internal/http/request"
"github.com/TheTNB/panel/pkg/acme"
"github.com/TheTNB/panel/pkg/cert"
+ "github.com/go-resty/resty/v2"
)
-type certAccountRepo struct{}
+type certAccountRepo struct {
+ db *gorm.DB
+ user biz.UserRepo
+}
-func NewCertAccountRepo() biz.CertAccountRepo {
- return do.MustInvoke[biz.CertAccountRepo](injector)
+func NewCertAccountRepo(db *gorm.DB, user biz.UserRepo) biz.CertAccountRepo {
+ return &certAccountRepo{
+ db: db,
+ user: user,
+ }
}
func (r certAccountRepo) List(page, limit uint) ([]*biz.CertAccount, int64, error) {
var accounts []*biz.CertAccount
var total int64
- err := app.Orm.Model(&biz.CertAccount{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&accounts).Error
+ err := r.db.Model(&biz.CertAccount{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&accounts).Error
return accounts, total, err
}
func (r certAccountRepo) GetDefault(userID uint) (*biz.CertAccount, error) {
- user, err := NewUserRepo().Get(userID)
+ user, err := r.user.Get(userID)
if err != nil {
return nil, err
}
account := new(biz.CertAccount)
- if err = app.Orm.Model(&biz.CertAccount{}).Where("ca = ?", "googlecn").Where("email = ?", user.Email).First(account).Error; err == nil {
+ if err = r.db.Model(&biz.CertAccount{}).Where("ca = ?", "googlecn").Where("email = ?", user.Email).First(account).Error; err == nil {
return account, nil
}
@@ -51,7 +55,7 @@ func (r certAccountRepo) GetDefault(userID uint) (*biz.CertAccount, error) {
func (r certAccountRepo) Get(id uint) (*biz.CertAccount, error) {
account := new(biz.CertAccount)
- err := app.Orm.Model(&biz.CertAccount{}).Where("id = ?", id).First(account).Error
+ err := r.db.Model(&biz.CertAccount{}).Where("id = ?", id).First(account).Error
return account, err
}
@@ -104,7 +108,7 @@ func (r certAccountRepo) Create(req *request.CertAccountCreate) (*biz.CertAccoun
}
account.PrivateKey = string(privateKey)
- if err = app.Orm.Create(account).Error; err != nil {
+ if err = r.db.Create(account).Error; err != nil {
return nil, err
}
@@ -163,11 +167,11 @@ func (r certAccountRepo) Update(req *request.CertAccountUpdate) error {
}
account.PrivateKey = string(privateKey)
- return app.Orm.Save(account).Error
+ return r.db.Save(account).Error
}
func (r certAccountRepo) Delete(id uint) error {
- return app.Orm.Model(&biz.CertAccount{}).Where("id = ?", id).Delete(&biz.CertAccount{}).Error
+ return r.db.Model(&biz.CertAccount{}).Where("id = ?", id).Delete(&biz.CertAccount{}).Error
}
// getGoogleEAB 获取 Google EAB
diff --git a/internal/data/cert_dns.go b/internal/data/cert_dns.go
index 2bcf8a52..60f11ab2 100644
--- a/internal/data/cert_dns.go
+++ b/internal/data/cert_dns.go
@@ -1,29 +1,32 @@
package data
import (
- "github.com/samber/do/v2"
+ "gorm.io/gorm"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/http/request"
)
-type certDNSRepo struct{}
+type certDNSRepo struct {
+ db *gorm.DB
+}
-func NewCertDNSRepo() biz.CertDNSRepo {
- return do.MustInvoke[biz.CertDNSRepo](injector)
+func NewCertDNSRepo(db *gorm.DB) biz.CertDNSRepo {
+ return &certDNSRepo{
+ db: db,
+ }
}
func (r certDNSRepo) List(page, limit uint) ([]*biz.CertDNS, int64, error) {
var certDNS []*biz.CertDNS
var total int64
- err := app.Orm.Model(&biz.CertDNS{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&certDNS).Error
+ err := r.db.Model(&biz.CertDNS{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&certDNS).Error
return certDNS, total, err
}
func (r certDNSRepo) Get(id uint) (*biz.CertDNS, error) {
certDNS := new(biz.CertDNS)
- err := app.Orm.Model(&biz.CertDNS{}).Where("id = ?", id).First(certDNS).Error
+ err := r.db.Model(&biz.CertDNS{}).Where("id = ?", id).First(certDNS).Error
return certDNS, err
}
@@ -34,7 +37,7 @@ func (r certDNSRepo) Create(req *request.CertDNSCreate) (*biz.CertDNS, error) {
Data: req.Data,
}
- if err := app.Orm.Create(certDNS).Error; err != nil {
+ if err := r.db.Create(certDNS).Error; err != nil {
return nil, err
}
@@ -51,9 +54,9 @@ func (r certDNSRepo) Update(req *request.CertDNSUpdate) error {
cert.Type = req.Type
cert.Data = req.Data
- return app.Orm.Save(cert).Error
+ return r.db.Save(cert).Error
}
func (r certDNSRepo) Delete(id uint) error {
- return app.Orm.Model(&biz.CertDNS{}).Where("id = ?", id).Delete(&biz.CertDNS{}).Error
+ return r.db.Model(&biz.CertDNS{}).Where("id = ?", id).Delete(&biz.CertDNS{}).Error
}
diff --git a/internal/data/container.go b/internal/data/container.go
index 8a25e232..320a1187 100644
--- a/internal/data/container.go
+++ b/internal/data/container.go
@@ -6,14 +6,12 @@ import (
"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"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/types"
"github.com/TheTNB/panel/pkg/types/docker/container"
+ "github.com/go-resty/resty/v2"
)
type containerRepo struct {
@@ -21,7 +19,9 @@ type containerRepo struct {
}
func NewContainerRepo() biz.ContainerRepo {
- return do.MustInvoke[biz.ContainerRepo](injector)
+ return &containerRepo{
+ client: getDockerClient("/var/run/docker.sock"),
+ }
}
// ListAll 列出所有容器
diff --git a/internal/data/container_image.go b/internal/data/container_image.go
index 1a1010ac..959eea47 100644
--- a/internal/data/container_image.go
+++ b/internal/data/container_image.go
@@ -6,15 +6,13 @@ import (
"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"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/pkg/types"
"github.com/TheTNB/panel/pkg/types/docker/image"
+ "github.com/go-resty/resty/v2"
)
type containerImageRepo struct {
@@ -22,7 +20,9 @@ type containerImageRepo struct {
}
func NewContainerImageRepo() biz.ContainerImageRepo {
- return do.MustInvoke[biz.ContainerImageRepo](injector)
+ return &containerImageRepo{
+ client: getDockerClient("/var/run/docker.sock"),
+ }
}
// List 列出镜像
diff --git a/internal/data/container_network.go b/internal/data/container_network.go
index 195eaf1e..f6f7057d 100644
--- a/internal/data/container_network.go
+++ b/internal/data/container_network.go
@@ -6,14 +6,12 @@ import (
"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"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/types"
"github.com/TheTNB/panel/pkg/types/docker/network"
+ "github.com/go-resty/resty/v2"
)
type containerNetworkRepo struct {
@@ -21,7 +19,9 @@ type containerNetworkRepo struct {
}
func NewContainerNetworkRepo() biz.ContainerNetworkRepo {
- return do.MustInvoke[biz.ContainerNetworkRepo](injector)
+ return &containerNetworkRepo{
+ client: getDockerClient("/var/run/docker.sock"),
+ }
}
// List 列出网络
diff --git a/internal/data/container_volume.go b/internal/data/container_volume.go
index d2615a95..7084d0da 100644
--- a/internal/data/container_volume.go
+++ b/internal/data/container_volume.go
@@ -6,15 +6,13 @@ import (
"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"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/pkg/types"
"github.com/TheTNB/panel/pkg/types/docker/volume"
+ "github.com/go-resty/resty/v2"
)
type containerVolumeRepo struct {
@@ -22,7 +20,9 @@ type containerVolumeRepo struct {
}
func NewContainerVolumeRepo() biz.ContainerVolumeRepo {
- return do.MustInvoke[biz.ContainerVolumeRepo](injector)
+ return &containerVolumeRepo{
+ client: getDockerClient("/var/run/docker.sock"),
+ }
}
// List 列出存储卷
diff --git a/internal/data/cron.go b/internal/data/cron.go
index 62237411..c54068ae 100644
--- a/internal/data/cron.go
+++ b/internal/data/cron.go
@@ -3,13 +3,11 @@ package data
import (
"errors"
"fmt"
+ "gorm.io/gorm"
"path/filepath"
"strconv"
"time"
- "github.com/go-rat/utils/str"
- "github.com/samber/do/v2"
-
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/http/request"
@@ -17,17 +15,22 @@ import (
"github.com/TheTNB/panel/pkg/os"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
+ "github.com/go-rat/utils/str"
)
-type cronRepo struct{}
+type cronRepo struct {
+ db *gorm.DB
+}
-func NewCronRepo() biz.CronRepo {
- return do.MustInvoke[biz.CronRepo](injector)
+func NewCronRepo(db *gorm.DB) biz.CronRepo {
+ return &cronRepo{
+ db: db,
+ }
}
func (r *cronRepo) Count() (int64, error) {
var count int64
- if err := app.Orm.Model(&biz.Cron{}).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.Cron{}).Count(&count).Error; err != nil {
return 0, err
}
@@ -37,13 +40,13 @@ func (r *cronRepo) Count() (int64, error) {
func (r *cronRepo) List(page, limit uint) ([]*biz.Cron, int64, error) {
var cron []*biz.Cron
var total int64
- err := app.Orm.Model(&biz.Cron{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&cron).Error
+ err := r.db.Model(&biz.Cron{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&cron).Error
return cron, total, err
}
func (r *cronRepo) Get(id uint) (*biz.Cron, error) {
cron := new(biz.Cron)
- if err := app.Orm.Where("id = ?", id).First(cron).Error; err != nil {
+ if err := r.db.Where("id = ?", id).First(cron).Error; err != nil {
return nil, err
}
@@ -113,7 +116,7 @@ panel-cli cutoff clear -t website -f %s -s %d -p %s
cron.Shell = shellDir + shellFile + ".sh"
cron.Log = shellLogDir + shellFile + ".log"
- if err := app.Orm.Create(cron).Error; err != nil {
+ if err := r.db.Create(cron).Error; err != nil {
return err
}
if err := r.addToSystem(cron); err != nil {
@@ -135,7 +138,7 @@ func (r *cronRepo) Update(req *request.CronUpdate) error {
cron.Time = req.Time
cron.Name = req.Name
- if err = app.Orm.Save(cron).Error; err != nil {
+ if err = r.db.Save(cron).Error; err != nil {
return err
}
@@ -171,7 +174,7 @@ func (r *cronRepo) Delete(id uint) error {
return err
}
- return app.Orm.Delete(cron).Error
+ return r.db.Delete(cron).Error
}
func (r *cronRepo) Status(id uint, status bool) error {
@@ -189,7 +192,7 @@ func (r *cronRepo) Status(id uint, status bool) error {
cron.Status = status
- return app.Orm.Save(cron).Error
+ return r.db.Save(cron).Error
}
// addToSystem 添加到系统
diff --git a/internal/data/data.go b/internal/data/data.go
new file mode 100644
index 00000000..03895ed0
--- /dev/null
+++ b/internal/data/data.go
@@ -0,0 +1,28 @@
+package data
+
+import "github.com/google/wire"
+
+// ProviderSet is data providers.
+var ProviderSet = wire.NewSet(
+ NewAppRepo,
+ NewBackupRepo,
+ NewCacheRepo,
+ NewCertRepo,
+ NewCertAccountRepo,
+ NewCertDNSRepo,
+ NewContainerRepo,
+ NewContainerImageRepo,
+ NewContainerNetworkRepo,
+ NewContainerVolumeRepo,
+ NewCronRepo,
+ NewDatabaseRepo,
+ NewDatabaseServerRepo,
+ NewDatabaseUserRepo,
+ NewMonitorRepo,
+ NewSafeRepo,
+ NewSettingRepo,
+ NewSSHRepo,
+ NewTaskRepo,
+ NewUserRepo,
+ NewWebsiteRepo,
+)
diff --git a/internal/data/database.go b/internal/data/database.go
index 74ba8a11..8161ada2 100644
--- a/internal/data/database.go
+++ b/internal/data/database.go
@@ -5,18 +5,19 @@ import (
"fmt"
"slices"
- "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{}
+type databaseRepo struct {
+ server biz.DatabaseServerRepo
+ user biz.DatabaseUserRepo
+}
-func NewDatabaseRepo() biz.DatabaseRepo {
- return do.MustInvoke[biz.DatabaseRepo](injector)
+func NewDatabaseRepo(server biz.DatabaseServerRepo, user biz.DatabaseUserRepo) biz.DatabaseRepo {
+ return &databaseRepo{server: server, user: user}
}
func (r databaseRepo) List(page, limit uint) ([]*biz.Database, int64, error) {
@@ -68,7 +69,7 @@ func (r databaseRepo) List(page, limit uint) ([]*biz.Database, int64, error) {
}
func (r databaseRepo) Create(req *request.DatabaseCreate) error {
- server, err := NewDatabaseServerRepo().Get(req.ServerID)
+ server, err := r.server.Get(req.ServerID)
if err != nil {
return err
}
@@ -81,7 +82,7 @@ func (r databaseRepo) Create(req *request.DatabaseCreate) error {
}
defer mysql.Close()
if req.CreateUser {
- if err = NewDatabaseUserRepo().Create(&request.DatabaseUserCreate{
+ if err = r.user.Create(&request.DatabaseUserCreate{
ServerID: req.ServerID,
Username: req.Username,
Password: req.Password,
@@ -105,7 +106,7 @@ func (r databaseRepo) Create(req *request.DatabaseCreate) error {
}
defer postgres.Close()
if req.CreateUser {
- if err = NewDatabaseUserRepo().Create(&request.DatabaseUserCreate{
+ if err = r.user.Create(&request.DatabaseUserCreate{
ServerID: req.ServerID,
Username: req.Username,
Password: req.Password,
@@ -131,7 +132,7 @@ func (r databaseRepo) Create(req *request.DatabaseCreate) error {
}
func (r databaseRepo) Delete(serverID uint, name string) error {
- server, err := NewDatabaseServerRepo().Get(serverID)
+ server, err := r.server.Get(serverID)
if err != nil {
return err
}
@@ -157,7 +158,7 @@ func (r databaseRepo) Delete(serverID uint, name string) error {
}
func (r databaseRepo) Comment(req *request.DatabaseComment) error {
- server, err := NewDatabaseServerRepo().Get(req.ServerID)
+ server, err := r.server.Get(req.ServerID)
if err != nil {
return err
}
diff --git a/internal/data/database_server.go b/internal/data/database_server.go
index cd6f563d..c183bb66 100644
--- a/internal/data/database_server.go
+++ b/internal/data/database_server.go
@@ -2,26 +2,31 @@ package data
import (
"fmt"
+ "github.com/TheTNB/panel/internal/app"
+ "gorm.io/gorm"
"log/slog"
"slices"
- "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 {
+ db *gorm.DB
+ log *slog.Logger
+}
-func NewDatabaseServerRepo() biz.DatabaseServerRepo {
- return do.MustInvoke[biz.DatabaseServerRepo](injector)
+func NewDatabaseServerRepo(db *gorm.DB, log *slog.Logger) biz.DatabaseServerRepo {
+ return &databaseServerRepo{
+ db: db,
+ log: log,
+ }
}
func (r databaseServerRepo) Count() (int64, error) {
var count int64
- if err := app.Orm.Model(&biz.DatabaseServer{}).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.DatabaseServer{}).Count(&count).Error; err != nil {
return 0, err
}
@@ -31,7 +36,7 @@ func (r databaseServerRepo) Count() (int64, error) {
func (r databaseServerRepo) List(page, limit uint) ([]*biz.DatabaseServer, int64, error) {
var databaseServer []*biz.DatabaseServer
var total int64
- err := app.Orm.Model(&biz.DatabaseServer{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&databaseServer).Error
+ err := r.db.Model(&biz.DatabaseServer{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&databaseServer).Error
for server := range slices.Values(databaseServer) {
r.checkServer(server)
@@ -42,7 +47,7 @@ func (r databaseServerRepo) List(page, limit uint) ([]*biz.DatabaseServer, int64
func (r databaseServerRepo) Get(id uint) (*biz.DatabaseServer, error) {
databaseServer := new(biz.DatabaseServer)
- if err := app.Orm.Where("id = ?", id).First(databaseServer).Error; err != nil {
+ if err := r.db.Where("id = ?", id).First(databaseServer).Error; err != nil {
return nil, err
}
@@ -53,7 +58,7 @@ func (r databaseServerRepo) Get(id uint) (*biz.DatabaseServer, error) {
func (r databaseServerRepo) GetByName(name string) (*biz.DatabaseServer, error) {
databaseServer := new(biz.DatabaseServer)
- if err := app.Orm.Where("name = ?", name).First(databaseServer).Error; err != nil {
+ if err := r.db.Where("name = ?", name).First(databaseServer).Error; err != nil {
return nil, err
}
@@ -77,7 +82,7 @@ func (r databaseServerRepo) Create(req *request.DatabaseServerCreate) error {
return fmt.Errorf("check server connection failed")
}
- return app.Orm.Create(databaseServer).Error
+ return r.db.Create(databaseServer).Error
}
func (r databaseServerRepo) Update(req *request.DatabaseServerUpdate) error {
@@ -97,20 +102,24 @@ func (r databaseServerRepo) Update(req *request.DatabaseServerUpdate) error {
return fmt.Errorf("check server connection failed")
}
- return app.Orm.Save(server).Error
+ return r.db.Save(server).Error
}
func (r databaseServerRepo) UpdateRemark(req *request.DatabaseServerUpdateRemark) error {
- return app.Orm.Model(&biz.DatabaseServer{}).Where("id = ?", req.ID).Update("remark", req.Remark).Error
+ return r.db.Model(&biz.DatabaseServer{}).Where("id = ?", req.ID).Update("remark", req.Remark).Error
}
func (r databaseServerRepo) Delete(id uint) error {
- // 删除服务器下的所有用户
- if err := NewDatabaseUserRepo().DeleteByServerID(id); err != nil {
+ if err := r.ClearUsers(id); err != nil {
return err
}
- return app.Orm.Where("id = ?", id).Delete(&biz.DatabaseServer{}).Error
+ return r.db.Where("id = ?", id).Delete(&biz.DatabaseServer{}).Error
+}
+
+// ClearUsers 删除指定服务器的所有用户,只是删除面板记录,不会实际删除
+func (r databaseServerRepo) ClearUsers(serverID uint) error {
+ return app.Orm.Where("server_id = ?", serverID).Delete(&biz.DatabaseUser{}).Error
}
func (r databaseServerRepo) Sync(id uint) error {
@@ -120,7 +129,7 @@ func (r databaseServerRepo) Sync(id uint) error {
}
users := make([]*biz.DatabaseUser, 0)
- if err = app.Orm.Where("server_id = ?", id).Find(&users).Error; err != nil {
+ if err = r.db.Where("server_id = ?", id).Find(&users).Error; err != nil {
return err
}
@@ -145,8 +154,8 @@ func (r databaseServerRepo) Sync(id uint) error {
Host: user.Host,
Remark: fmt.Sprintf("sync from server %s", server.Name),
}
- if err = app.Orm.Create(newUser).Error; err != nil {
- app.Logger.Warn("sync database user failed", slog.Any("err", err))
+ if err = r.db.Create(newUser).Error; err != nil {
+ r.log.Warn("sync database user failed", slog.Any("err", err))
}
}
}
@@ -169,7 +178,7 @@ func (r databaseServerRepo) Sync(id uint) error {
Username: user.Role,
Remark: fmt.Sprintf("sync from server %s", server.Name),
}
- app.Orm.Create(newUser)
+ r.db.Create(newUser)
}
}
}
diff --git a/internal/data/database_user.go b/internal/data/database_user.go
index 333f1d33..93417eff 100644
--- a/internal/data/database_user.go
+++ b/internal/data/database_user.go
@@ -4,18 +4,18 @@ import (
"fmt"
"slices"
- "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 databaseUserRepo struct{}
+type databaseUserRepo struct {
+ server biz.DatabaseServerRepo
+}
-func NewDatabaseUserRepo() biz.DatabaseUserRepo {
- return do.MustInvoke[biz.DatabaseUserRepo](injector)
+func NewDatabaseUserRepo(server biz.DatabaseServerRepo) biz.DatabaseUserRepo {
+ return &databaseUserRepo{server: server}
}
func (r databaseUserRepo) Count() (int64, error) {
@@ -51,7 +51,7 @@ func (r databaseUserRepo) Get(id uint) (*biz.DatabaseUser, error) {
}
func (r databaseUserRepo) Create(req *request.DatabaseUserCreate) error {
- server, err := NewDatabaseServerRepo().Get(req.ServerID)
+ server, err := r.server.Get(req.ServerID)
if err != nil {
return err
}
@@ -113,7 +113,7 @@ func (r databaseUserRepo) Update(req *request.DatabaseUserUpdate) error {
return err
}
- server, err := NewDatabaseServerRepo().Get(user.ServerID)
+ server, err := r.server.Get(user.ServerID)
if err != nil {
return err
}
@@ -176,7 +176,7 @@ func (r databaseUserRepo) Delete(id uint) error {
return err
}
- server, err := NewDatabaseServerRepo().Get(user.ServerID)
+ server, err := r.server.Get(user.ServerID)
if err != nil {
return err
}
@@ -202,7 +202,7 @@ func (r databaseUserRepo) Delete(id uint) error {
}
func (r databaseUserRepo) DeleteByNames(serverID uint, names []string) error {
- server, err := NewDatabaseServerRepo().Get(serverID)
+ server, err := r.server.Get(serverID)
if err != nil {
return err
}
@@ -242,13 +242,8 @@ func (r databaseUserRepo) DeleteByNames(serverID uint, names []string) error {
return app.Orm.Where("server_id = ? AND username IN ?", serverID, names).Delete(&biz.DatabaseUser{}).Error
}
-// DeleteByServerID 删除指定服务器的所有用户,只是删除面板记录,不会实际删除
-func (r databaseUserRepo) DeleteByServerID(serverID uint) error {
- return app.Orm.Where("server_id = ?", serverID).Delete(&biz.DatabaseUser{}).Error
-}
-
func (r databaseUserRepo) fillUser(user *biz.DatabaseUser) {
- server, err := NewDatabaseServerRepo().Get(user.ServerID)
+ server, err := r.server.Get(user.ServerID)
if err == nil {
switch server.Type {
case biz.DatabaseTypeMysql:
diff --git a/internal/data/helper.go b/internal/data/helper.go
new file mode 100644
index 00000000..fb9f4fb3
--- /dev/null
+++ b/internal/data/helper.go
@@ -0,0 +1,23 @@
+package data
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+)
+
+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/init.go b/internal/data/init.go
deleted file mode 100644
index ac56e759..00000000
--- a/internal/data/init.go
+++ /dev/null
@@ -1,120 +0,0 @@
-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{}, 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{
- api: api.NewAPI(app.Version),
- }, 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.DatabaseUserRepo, error) {
- return &databaseUserRepo{}, 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 edf31904..1410c3a2 100644
--- a/internal/data/monitor.go
+++ b/internal/data/monitor.go
@@ -2,9 +2,9 @@ package data
import (
"errors"
+ "gorm.io/gorm"
"time"
- "github.com/samber/do/v2"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
@@ -12,19 +12,24 @@ import (
"github.com/TheTNB/panel/internal/http/request"
)
-type monitorRepo struct{}
+type monitorRepo struct {
+ db *gorm.DB
+ setting biz.SettingRepo
+}
-func NewMonitorRepo() biz.MonitorRepo {
- return do.MustInvoke[biz.MonitorRepo](injector)
+func NewMonitorRepo(db *gorm.DB, setting biz.SettingRepo) biz.MonitorRepo {
+ return &monitorRepo{
+ db: db,
+ setting: setting,
+ }
}
func (r monitorRepo) GetSetting() (*request.MonitorSetting, error) {
- repo := NewSettingRepo()
- monitor, err := repo.Get(biz.SettingKeyMonitor)
+ monitor, err := r.setting.Get(biz.SettingKeyMonitor)
if err != nil {
return nil, err
}
- monitorDays, err := repo.Get(biz.SettingKeyMonitorDays)
+ monitorDays, err := r.setting.Get(biz.SettingKeyMonitorDays)
if err != nil {
return nil, err
}
@@ -37,11 +42,10 @@ func (r monitorRepo) GetSetting() (*request.MonitorSetting, error) {
}
func (r monitorRepo) UpdateSetting(setting *request.MonitorSetting) error {
- repo := NewSettingRepo()
- if err := repo.Set(biz.SettingKeyMonitor, cast.ToString(setting.Enabled)); err != nil {
+ if err := r.setting.Set(biz.SettingKeyMonitor, cast.ToString(setting.Enabled)); err != nil {
return err
}
- if err := repo.Set(biz.SettingKeyMonitorDays, cast.ToString(setting.Days)); err != nil {
+ if err := r.setting.Set(biz.SettingKeyMonitorDays, cast.ToString(setting.Days)); err != nil {
return err
}
diff --git a/internal/data/safe.go b/internal/data/safe.go
index 3c4ef66b..ba4f5a21 100644
--- a/internal/data/safe.go
+++ b/internal/data/safe.go
@@ -2,9 +2,9 @@ package data
import (
"fmt"
+ "github.com/TheTNB/panel/pkg/os"
"strings"
- "github.com/samber/do/v2"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/biz"
@@ -18,7 +18,15 @@ type safeRepo struct {
}
func NewSafeRepo() biz.SafeRepo {
- return do.MustInvoke[biz.SafeRepo](injector)
+ var ssh string
+ if os.IsRHEL() {
+ ssh = "sshd"
+ } else {
+ ssh = "ssh"
+ }
+ return &safeRepo{
+ ssh: ssh,
+ }
}
func (r *safeRepo) GetSSH() (uint, bool, error) {
diff --git a/internal/data/setting.go b/internal/data/setting.go
index 36fa56e0..533999ef 100644
--- a/internal/data/setting.go
+++ b/internal/data/setting.go
@@ -4,14 +4,12 @@ import (
"context"
"errors"
"fmt"
- "path/filepath"
- "slices"
-
"github.com/go-rat/utils/hash"
- "github.com/samber/do/v2"
+ "github.com/knadh/koanf/v2"
"github.com/spf13/cast"
"gopkg.in/yaml.v3"
"gorm.io/gorm"
+ "path/filepath"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
@@ -20,20 +18,26 @@ import (
"github.com/TheTNB/panel/pkg/firewall"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/os"
- "github.com/TheTNB/panel/pkg/shell"
- "github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/pkg/types"
)
-type settingRepo struct{}
+type settingRepo struct {
+ db *gorm.DB
+ conf *koanf.Koanf
+ task biz.TaskRepo
+}
-func NewSettingRepo() biz.SettingRepo {
- return do.MustInvoke[biz.SettingRepo](injector)
+func NewSettingRepo(db *gorm.DB, conf *koanf.Koanf, task biz.TaskRepo) biz.SettingRepo {
+ return &settingRepo{
+ db: db,
+ conf: conf,
+ task: task,
+ }
}
func (r *settingRepo) Get(key biz.SettingKey, defaultValue ...string) (string, error) {
setting := new(biz.Setting)
- if err := app.Orm.Where("key = ?", key).First(setting).Error; err != nil {
+ if err := r.db.Where("key = ?", key).First(setting).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return "", err
}
@@ -48,7 +52,7 @@ func (r *settingRepo) Get(key biz.SettingKey, defaultValue ...string) (string, e
func (r *settingRepo) GetBool(key biz.SettingKey, defaultValue ...bool) (bool, error) {
setting := new(biz.Setting)
- if err := app.Orm.Where("key = ?", key).First(setting).Error; err != nil {
+ if err := r.db.Where("key = ?", key).First(setting).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return false, err
}
@@ -63,7 +67,7 @@ func (r *settingRepo) GetBool(key biz.SettingKey, defaultValue ...bool) (bool, e
func (r *settingRepo) Set(key biz.SettingKey, value string) error {
setting := new(biz.Setting)
- if err := app.Orm.Where("key = ?", key).First(setting).Error; err != nil {
+ if err := r.db.Where("key = ?", key).First(setting).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
@@ -71,12 +75,12 @@ func (r *settingRepo) Set(key biz.SettingKey, value string) error {
setting.Key = key
setting.Value = value
- return app.Orm.Save(setting).Error
+ return r.db.Save(setting).Error
}
func (r *settingRepo) Delete(key biz.SettingKey) error {
setting := new(biz.Setting)
- if err := app.Orm.Where("key = ?", key).Delete(setting).Error; err != nil {
+ if err := r.db.Where("key = ?", key).Delete(setting).Error; err != nil {
return err
}
@@ -103,7 +107,7 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin
userID := cast.ToUint(ctx.Value("user_id"))
user := new(biz.User)
- if err := app.Orm.Where("id = ?", userID).First(user).Error; err != nil {
+ if err := r.db.Where("id = ?", userID).First(user).Error; err != nil {
return nil, err
}
@@ -118,15 +122,15 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin
return &request.PanelSetting{
Name: name,
- Locale: app.Conf.String("app.locale"),
- Entrance: app.Conf.String("http.entrance"),
+ Locale: r.conf.String("app.locale"),
+ Entrance: r.conf.String("http.entrance"),
OfflineMode: cast.ToBool(offlineMode),
WebsitePath: websitePath,
BackupPath: backupPath,
Username: user.Username,
Email: user.Email,
- Port: uint(app.Conf.Int("http.port")),
- HTTPS: app.Conf.Bool("http.tls"),
+ Port: uint(r.conf.Int("http.port")),
+ HTTPS: r.conf.Bool("http.tls"),
Cert: crt,
Key: key,
}, nil
@@ -149,7 +153,7 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
// 用户
user := new(biz.User)
userID := cast.ToUint(ctx.Value("user_id"))
- if err := app.Orm.Where("id = ?", userID).First(user).Error; err != nil {
+ if err := r.db.Where("id = ?", userID).First(user).Error; err != nil {
return false, err
}
@@ -162,18 +166,17 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
}
user.Password = value
}
- if err := app.Orm.Save(user).Error; err != nil {
+ if err := r.db.Save(user).Error; err != nil {
return false, err
}
// 下面是需要需要重启的设置
- 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 task.HasRunningTask() {
+ if r.task.HasRunningTask() {
return false, errors.New("后台任务正在运行,禁止修改部分设置,请稍后再试")
}
restartFlag = true
@@ -216,8 +219,8 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
- PortStart: uint(config.HTTP.Port),
- PortEnd: uint(config.HTTP.Port),
+ PortStart: config.HTTP.Port,
+ PortEnd: config.HTTP.Port,
Direction: firewall.DirectionIn,
Strategy: firewall.StrategyAccept,
}, firewall.OperationAdd)
@@ -230,7 +233,7 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
return false, err
}
if raw != string(encoded) {
- if task.HasRunningTask() {
+ if r.task.HasRunningTask() {
return false, errors.New("后台任务正在运行,禁止修改部分设置,请稍后再试")
}
restartFlag = true
@@ -241,267 +244,3 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
return restartFlag, nil
}
-
-func (r *settingRepo) UpdatePanel(version, url, checksum string) error {
- // 预先优化数据库
- if err := app.Orm.Exec("VACUUM").Error; err != nil {
- return err
- }
- if err := app.Orm.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error; err != nil {
- return err
- }
-
- name := filepath.Base(url)
- if app.IsCli {
- fmt.Printf("|-目标版本:%s\n", version)
- fmt.Printf("|-下载链接:%s\n", url)
- fmt.Printf("|-文件名:%s\n", name)
- }
-
- if app.IsCli {
- fmt.Println("|-正在下载...")
- }
- if _, err := shell.Execf("wget -T 120 -t 3 -O /tmp/%s %s", name, url); err != nil {
- return fmt.Errorf("下载失败:%w", err)
- }
- if _, err := shell.Execf("wget -T 20 -t 3 -O /tmp/%s %s", name+".sha256", checksum); err != nil {
- return fmt.Errorf("下载失败:%w", err)
- }
- if !io.Exists(filepath.Join("/tmp", name)) || !io.Exists(filepath.Join("/tmp", name+".sha256")) {
- return errors.New("下载文件检查失败")
- }
-
- if app.IsCli {
- fmt.Println("|-校验下载文件...")
- }
- if check, err := shell.Execf("cd /tmp && sha256sum -c %s --ignore-missing", name+".sha256"); check != name+": OK" || err != nil {
- return errors.New("下载文件校验失败")
- }
- if err := io.Remove(filepath.Join("/tmp", name+".sha256")); err != nil {
- if app.IsCli {
- fmt.Println("|-清理校验文件失败:", err)
- }
- return fmt.Errorf("清理校验文件失败:%w", err)
- }
-
- if app.IsCli {
- fmt.Println("|-前置检查...")
- }
- if io.Exists("/tmp/panel-storage.zip") {
- return errors.New("检测到 /tmp 存在临时文件,可能是上次更新失败所致,请运行 panel-cli fix 修复后重试")
- }
-
- if app.IsCli {
- fmt.Println("|-备份面板数据...")
- }
- // 备份面板
- backup := NewBackupRepo()
- if err := backup.Create(biz.BackupTypePanel, ""); err != nil {
- if app.IsCli {
- fmt.Println("|-备份面板失败:", err)
- }
- return fmt.Errorf("备份面板失败:%w", err)
- }
- if err := io.Compress(filepath.Join(app.Root, "panel/storage"), nil, "/tmp/panel-storage.zip"); err != nil {
- if app.IsCli {
- fmt.Println("|-备份面板数据失败:", err)
- }
- return fmt.Errorf("备份面板数据失败:%w", err)
- }
- if !io.Exists("/tmp/panel-storage.zip") {
- return errors.New("已备份面板数据检查失败")
- }
-
- if app.IsCli {
- fmt.Println("|-清理旧版本...")
- }
- if _, err := shell.Execf("rm -rf %s/panel/*", app.Root); err != nil {
- return fmt.Errorf("清理旧版本失败:%w", err)
- }
-
- if app.IsCli {
- fmt.Println("|-解压新版本...")
- }
- if err := io.UnCompress(filepath.Join("/tmp", name), filepath.Join(app.Root, "panel")); err != nil {
- return fmt.Errorf("解压失败:%w", err)
- }
- if !io.Exists(filepath.Join(app.Root, "panel", "web")) {
- return errors.New("解压失败,缺失文件")
- }
-
- if app.IsCli {
- fmt.Println("|-恢复面板数据...")
- }
- if err := io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel", "storage")); err != nil {
- return fmt.Errorf("恢复面板数据失败:%w", err)
- }
- if !io.Exists(filepath.Join(app.Root, "panel/storage/app.db")) {
- return errors.New("恢复面板数据失败")
- }
-
- if app.IsCli {
- fmt.Println("|-运行更新后脚本...")
- }
- if _, err := shell.Execf("curl -fsLm 10 https://dl.cdn.haozi.net/panel/auto_update.sh | bash"); err != nil {
- return fmt.Errorf("运行面板更新后脚本失败:%w", err)
- }
- if _, err := shell.Execf(`wget -O /etc/systemd/system/panel.service https://dl.cdn.haozi.net/panel/panel.service && sed -i "s|/www|%s|g" /etc/systemd/system/panel.service`, app.Root); err != nil {
- return fmt.Errorf("下载面板服务文件失败:%w", err)
- }
- if _, err := shell.Execf("panel-cli setting write version %s", version); err != nil {
- return fmt.Errorf("写入面板版本号失败:%w", err)
- }
- if err := io.Mv(filepath.Join(app.Root, "panel/cli"), "/usr/local/sbin/panel-cli"); err != nil {
- return fmt.Errorf("移动面板命令行工具失败:%w", err)
- }
-
- if app.IsCli {
- fmt.Println("|-设置关键文件权限...")
- }
- _ = io.Chmod("/usr/local/sbin/panel-cli", 0700)
- _ = io.Chmod("/etc/systemd/system/panel.service", 0700)
- _ = io.Chmod(filepath.Join(app.Root, "panel"), 0700)
-
- if app.IsCli {
- fmt.Println("|-更新完成")
- }
-
- _, _ = shell.Execf("systemctl daemon-reload")
- _ = io.Remove("/tmp/panel-storage.zip")
- _ = io.Remove(filepath.Join(app.Root, "panel/config.example.yml"))
- tools.RestartPanel()
-
- return nil
-}
-
-func (r *settingRepo) FixPanel() error {
- if app.IsCli {
- fmt.Println("|-开始修复面板...")
- }
-
- // 检查关键文件是否正常
- flag := false
- if !io.Exists(filepath.Join(app.Root, "panel", "web")) {
- flag = true
- }
- if !io.Exists(filepath.Join(app.Root, "panel", "storage", "app.db")) {
- flag = true
- }
- if io.Exists("/tmp/panel-storage.zip") {
- flag = true
- }
- if !flag {
- return fmt.Errorf("文件正常无需修复,请运行 panel-cli update 更新面板")
- }
-
- // 再次确认是否需要修复
- if io.Exists("/tmp/panel-storage.zip") {
- // 文件齐全情况下只移除临时文件
- if io.Exists(filepath.Join(app.Root, "panel", "web")) &&
- io.Exists(filepath.Join(app.Root, "panel", "storage", "app.db")) &&
- io.Exists("/usr/local/etc/panel/config.yml") {
- if err := io.Remove("/tmp/panel-storage.zip"); err != nil {
- return fmt.Errorf("清理临时文件失败:%w", err)
- }
- if app.IsCli {
- fmt.Println("|-已清理临时文件,请运行 panel-cli update 更新面板")
- }
- return nil
- }
- }
-
- // 从备份目录中找最新的备份文件
- backup := NewBackupRepo()
- list, err := backup.List(biz.BackupTypePanel)
- if err != nil {
- return err
- }
- slices.SortFunc(list, func(a *types.BackupFile, b *types.BackupFile) int {
- return int(b.Time.Unix() - a.Time.Unix())
- })
- if len(list) == 0 {
- return fmt.Errorf("未找到备份文件,无法自动修复")
- }
- latest := list[0]
- if app.IsCli {
- fmt.Printf("|-使用备份文件:%s\n", latest.Name)
- }
-
- // 解压备份文件
- if app.IsCli {
- fmt.Println("|-解压备份文件...")
- }
- if err = io.Remove("/tmp/panel-fix"); err != nil {
- return fmt.Errorf("清理临时目录失败:%w", err)
- }
- if err = io.UnCompress(latest.Path, "/tmp/panel-fix"); err != nil {
- return fmt.Errorf("解压备份文件失败:%w", err)
- }
-
- // 移动文件到对应位置
- if app.IsCli {
- fmt.Println("|-移动备份文件...")
- }
- if io.Exists(filepath.Join("/tmp/panel-fix", "panel")) && io.IsDir(filepath.Join("/tmp/panel-fix", "panel")) {
- if err = io.Remove(filepath.Join(app.Root, "panel")); err != nil {
- return fmt.Errorf("删除目录失败:%w", err)
- }
- if err = io.Mv(filepath.Join("/tmp/panel-fix", "panel"), filepath.Join(app.Root)); err != nil {
- return fmt.Errorf("移动目录失败:%w", err)
- }
- }
- if io.Exists(filepath.Join("/tmp/panel-fix", "config.yml")) {
- if err = io.Mv(filepath.Join("/tmp/panel-fix", "config.yml"), "/usr/local/etc/panel/config.yml"); err != nil {
- return fmt.Errorf("移动文件失败:%w", err)
- }
- }
- if io.Exists(filepath.Join("/tmp/panel-fix", "panel-cli")) {
- if err = io.Mv(filepath.Join("/tmp/panel-fix", "panel-cli"), "/usr/local/sbin/panel-cli"); err != nil {
- return fmt.Errorf("移动文件失败:%w", err)
- }
- }
-
- // tmp 目录下如果有 storage 备份,则解压回去
- if app.IsCli {
- fmt.Println("|-恢复面板数据...")
- }
- if io.Exists("/tmp/panel-storage.zip") {
- if err = io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel")); err != nil {
- return fmt.Errorf("恢复面板数据失败:%w", err)
- }
- if err = io.Remove("/tmp/panel-storage.zip"); err != nil {
- return fmt.Errorf("清理临时文件失败:%w", err)
- }
- }
-
- // 下载服务文件
- if !io.Exists("/etc/systemd/system/panel.service") {
- if _, err = shell.Execf(`wget -O /etc/systemd/system/panel.service https://dl.cdn.haozi.net/panel/panel.service && sed -i "s|/www|%s|g" /etc/systemd/system/panel.service`, app.Root); err != nil {
- return err
- }
- }
-
- // 处理权限
- if app.IsCli {
- fmt.Println("|-设置关键文件权限...")
- }
- if err = io.Chmod("/usr/local/etc/panel/config.yml", 0600); err != nil {
- return err
- }
- if err = io.Chmod("/etc/systemd/system/panel.service", 0700); err != nil {
- return err
- }
- if err = io.Chmod("/usr/local/sbin/panel-cli", 0700); err != nil {
- return err
- }
- if err = io.Chmod(filepath.Join(app.Root, "panel"), 0700); err != nil {
- return err
- }
-
- if app.IsCli {
- fmt.Println("|-修复完成")
- }
-
- tools.RestartPanel()
- return nil
-}
diff --git a/internal/data/ssh.go b/internal/data/ssh.go
index 27b05dc2..d0792b55 100644
--- a/internal/data/ssh.go
+++ b/internal/data/ssh.go
@@ -2,31 +2,33 @@ package data
import (
"fmt"
+ "gorm.io/gorm"
- "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{}
+type sshRepo struct {
+ db *gorm.DB
+}
-func NewSSHRepo() biz.SSHRepo {
- return do.MustInvoke[biz.SSHRepo](injector)
+func NewSSHRepo(db *gorm.DB) biz.SSHRepo {
+ return &sshRepo{
+ db: db,
+ }
}
func (r *sshRepo) List(page, limit uint) ([]*biz.SSH, int64, error) {
var ssh []*biz.SSH
var total int64
- err := app.Orm.Model(&biz.SSH{}).Omit("Hosts").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&ssh).Error
+ err := r.db.Model(&biz.SSH{}).Omit("Hosts").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&ssh).Error
return ssh, total, err
}
func (r *sshRepo) Get(id uint) (*biz.SSH, error) {
ssh := new(biz.SSH)
- if err := app.Orm.Where("id = ?", id).First(ssh).Error; err != nil {
+ if err := r.db.Where("id = ?", id).First(ssh).Error; err != nil {
return nil, err
}
@@ -54,7 +56,7 @@ func (r *sshRepo) Create(req *request.SSHCreate) error {
Remark: req.Remark,
}
- return app.Orm.Create(ssh).Error
+ return r.db.Create(ssh).Error
}
func (r *sshRepo) Update(req *request.SSHUpdate) error {
@@ -79,9 +81,9 @@ func (r *sshRepo) Update(req *request.SSHUpdate) error {
Remark: req.Remark,
}
- return app.Orm.Model(ssh).Where("id = ?", req.ID).Select("*").Updates(ssh).Error
+ return r.db.Model(ssh).Where("id = ?", req.ID).Select("*").Updates(ssh).Error
}
func (r *sshRepo) Delete(id uint) error {
- return app.Orm.Delete(&biz.SSH{}, id).Error
+ return r.db.Delete(&biz.SSH{}, id).Error
}
diff --git a/internal/data/task.go b/internal/data/task.go
index 3e5a4c68..1c6e1fcc 100644
--- a/internal/data/task.go
+++ b/internal/data/task.go
@@ -2,88 +2,97 @@ package data
import (
"fmt"
+ "github.com/TheTNB/panel/pkg/queue"
+ "gorm.io/gorm"
"log/slog"
- "github.com/samber/do/v2"
-
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/queuejob"
)
-type taskRepo struct{}
+type taskRepo struct {
+ db *gorm.DB
+ log *slog.Logger
+ queue *queue.Queue
+}
-func NewTaskRepo() biz.TaskRepo {
- return do.MustInvoke[biz.TaskRepo](injector)
+func NewTaskRepo(db *gorm.DB, log *slog.Logger, queue *queue.Queue) biz.TaskRepo {
+ return &taskRepo{
+ db: db,
+ log: log,
+ queue: queue,
+ }
}
func (r *taskRepo) HasRunningTask() bool {
var count int64
- app.Orm.Model(&biz.Task{}).Where("status = ?", biz.TaskStatusRunning).Or("status = ?", biz.TaskStatusWaiting).Count(&count)
+ r.db.Model(&biz.Task{}).Where("status = ?", biz.TaskStatusRunning).Or("status = ?", biz.TaskStatusWaiting).Count(&count)
return count > 0
}
func (r *taskRepo) List(page, limit uint) ([]*biz.Task, int64, error) {
var tasks []*biz.Task
var total int64
- err := app.Orm.Model(&biz.Task{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&tasks).Error
+ err := r.db.Model(&biz.Task{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&tasks).Error
return tasks, total, err
}
func (r *taskRepo) Get(id uint) (*biz.Task, error) {
task := new(biz.Task)
- err := app.Orm.Model(&biz.Task{}).Where("id = ?", id).First(task).Error
+ err := r.db.Model(&biz.Task{}).Where("id = ?", id).First(task).Error
return task, err
}
func (r *taskRepo) Delete(id uint) error {
- return app.Orm.Model(&biz.Task{}).Where("id = ?", id).Delete(&biz.Task{}).Error
+ return r.db.Model(&biz.Task{}).Where("id = ?", id).Delete(&biz.Task{}).Error
}
func (r *taskRepo) UpdateStatus(id uint, status biz.TaskStatus) error {
- return app.Orm.Model(&biz.Task{}).Where("id = ?", id).Update("status", status).Error
+ return r.db.Model(&biz.Task{}).Where("id = ?", id).Update("status", status).Error
}
func (r *taskRepo) Push(task *biz.Task) error {
var count int64
- if err := app.Orm.Model(&biz.Task{}).Where("shell = ? and (status = ? or status = ?)", task.Shell, biz.TaskStatusWaiting, biz.TaskStatusRunning).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.Task{}).Where("shell = ? and (status = ? or status = ?)", task.Shell, biz.TaskStatusWaiting, biz.TaskStatusRunning).Count(&count).Error; err != nil {
return err
}
if count > 0 {
return fmt.Errorf("duplicate submission, please wait for the previous task to end")
}
- if err := app.Orm.Create(task).Error; err != nil {
+ if err := r.db.Create(task).Error; err != nil {
return err
}
- return app.Queue.Push(queuejob.NewProcessTask(r), []any{
+ return r.queue.Push(queuejob.NewProcessTask(r.log, r), []any{
task.ID,
})
}
+// TODO fix
func (r *taskRepo) DispatchWaiting() {
// cli下不处理
if app.IsCli {
return
}
- if err := app.Orm.Model(&biz.Task{}).Where("status = ?", biz.TaskStatusRunning).Update("status", biz.TaskStatusFailed).Error; err != nil {
- app.Logger.Warn("failed to mark running tasks as failed", slog.Any("err", err))
+ if err := r.db.Model(&biz.Task{}).Where("status = ?", biz.TaskStatusRunning).Update("status", biz.TaskStatusFailed).Error; err != nil {
+ r.log.Warn("failed to mark running tasks as failed", slog.Any("err", err))
return
}
var tasks []biz.Task
- if err := app.Orm.Where("status = ?", biz.TaskStatusWaiting).Find(&tasks).Error; err != nil {
- app.Logger.Warn("failed to get pending tasks", slog.Any("err", err))
+ if err := r.db.Where("status = ?", biz.TaskStatusWaiting).Find(&tasks).Error; err != nil {
+ r.log.Warn("failed to get pending tasks", slog.Any("err", err))
return
}
for _, task := range tasks {
- if err := app.Queue.Push(queuejob.NewProcessTask(r), []any{
+ if err := r.queue.Push(queuejob.NewProcessTask(r.log, r), []any{
task.ID,
}); err != nil {
- app.Logger.Warn("failed to push task", slog.Any("err", err))
+ r.log.Warn("failed to push task", slog.Any("err", err))
return
}
}
diff --git a/internal/data/user.go b/internal/data/user.go
index e2419978..65d5e572 100644
--- a/internal/data/user.go
+++ b/internal/data/user.go
@@ -4,19 +4,21 @@ import (
"errors"
"github.com/go-rat/utils/hash"
- "github.com/samber/do/v2"
"gorm.io/gorm"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
)
type userRepo struct {
+ db *gorm.DB
hasher hash.Hasher
}
-func NewUserRepo() biz.UserRepo {
- return do.MustInvoke[biz.UserRepo](injector)
+func NewUserRepo(db *gorm.DB) biz.UserRepo {
+ return &userRepo{
+ db: db,
+ hasher: hash.NewArgon2id(),
+ }
}
func (r *userRepo) Create(username, password string) (*biz.User, error) {
@@ -29,7 +31,7 @@ func (r *userRepo) Create(username, password string) (*biz.User, error) {
Username: username,
Password: value,
}
- if err = app.Orm.Create(user).Error; err != nil {
+ if err = r.db.Create(user).Error; err != nil {
return nil, err
}
@@ -38,7 +40,7 @@ func (r *userRepo) Create(username, password string) (*biz.User, error) {
func (r *userRepo) CheckPassword(username, password string) (*biz.User, error) {
user := new(biz.User)
- if err := app.Orm.Where("username = ?", username).First(user).Error; err != nil {
+ if err := r.db.Where("username = ?", username).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("用户名或密码错误")
} else {
@@ -55,7 +57,7 @@ func (r *userRepo) CheckPassword(username, password string) (*biz.User, error) {
func (r *userRepo) Get(id uint) (*biz.User, error) {
user := new(biz.User)
- if err := app.Orm.First(user, id).Error; err != nil {
+ if err := r.db.First(user, id).Error; err != nil {
return nil, err
}
@@ -63,5 +65,5 @@ func (r *userRepo) Get(id uint) (*biz.User, error) {
}
func (r *userRepo) Save(user *biz.User) error {
- return app.Orm.Save(user).Error
+ return r.db.Save(user).Error
}
diff --git a/internal/data/website.go b/internal/data/website.go
index 9f456861..6b7853f6 100644
--- a/internal/data/website.go
+++ b/internal/data/website.go
@@ -5,12 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
+ "gorm.io/gorm"
"path/filepath"
"slices"
"strings"
"time"
- "github.com/samber/do/v2"
"github.com/samber/lo"
"github.com/spf13/cast"
@@ -29,14 +29,30 @@ import (
"github.com/TheTNB/panel/pkg/types"
)
-type websiteRepo struct{}
+type websiteRepo struct {
+ db *gorm.DB
+ cache biz.CacheRepo
+ database biz.DatabaseRepo
+ databaseServer biz.DatabaseServerRepo
+ databaseUser biz.DatabaseUserRepo
+ cert biz.CertRepo
+ certAccount biz.CertAccountRepo
+}
-func NewWebsiteRepo() biz.WebsiteRepo {
- return do.MustInvoke[biz.WebsiteRepo](injector)
+func NewWebsiteRepo(db *gorm.DB, cache biz.CacheRepo, database biz.DatabaseRepo, databaseServer biz.DatabaseServerRepo, databaseUser biz.DatabaseUserRepo, cert biz.CertRepo, certAccount biz.CertAccountRepo) biz.WebsiteRepo {
+ return &websiteRepo{
+ db: db,
+ cache: cache,
+ database: database,
+ databaseServer: databaseServer,
+ databaseUser: databaseUser,
+ cert: cert,
+ certAccount: certAccount,
+ }
}
func (r *websiteRepo) GetRewrites() (map[string]string, error) {
- cached, err := NewCacheRepo().Get(biz.CacheKeyRewrites)
+ cached, err := r.cache.Get(biz.CacheKeyRewrites)
if err != nil {
return nil, err
}
@@ -67,7 +83,7 @@ func (r *websiteRepo) UpdateDefaultConfig(req *request.WebsiteDefaultConfig) err
func (r *websiteRepo) Count() (int64, error) {
var count int64
- if err := app.Orm.Model(&biz.Website{}).Count(&count).Error; err != nil {
+ if err := r.db.Model(&biz.Website{}).Count(&count).Error; err != nil {
return 0, err
}
@@ -76,7 +92,7 @@ func (r *websiteRepo) Count() (int64, error) {
func (r *websiteRepo) Get(id uint) (*types.WebsiteSetting, error) {
website := new(biz.Website)
- if err := app.Orm.Where("id", id).First(website).Error; err != nil {
+ if err := r.db.Where("id", id).First(website).Error; err != nil {
return nil, err
}
// 解析nginx配置
@@ -176,7 +192,7 @@ func (r *websiteRepo) Get(id uint) (*types.WebsiteSetting, error) {
func (r *websiteRepo) GetByName(name string) (*types.WebsiteSetting, error) {
website := new(biz.Website)
- if err := app.Orm.Where("name", name).First(website).Error; err != nil {
+ if err := r.db.Where("name", name).First(website).Error; err != nil {
return nil, err
}
@@ -188,11 +204,11 @@ func (r *websiteRepo) List(page, limit uint) ([]*biz.Website, int64, error) {
var websites []*biz.Website
var total int64
- if err := app.Orm.Model(&biz.Website{}).Count(&total).Error; err != nil {
+ if err := r.db.Model(&biz.Website{}).Count(&total).Error; err != nil {
return nil, 0, err
}
- if err := app.Orm.Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&websites).Error; err != nil {
+ if err := r.db.Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&websites).Error; err != nil {
return nil, 0, err
}
@@ -312,7 +328,7 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) {
Https: false,
Remark: req.Remark,
}
- if err = app.Orm.Create(w).Error; err != nil {
+ if err = r.db.Create(w).Error; err != nil {
return nil, err
}
@@ -324,11 +340,11 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) {
// 创建数据库
name := "local_" + req.DBType
if req.DB {
- server, err := NewDatabaseServerRepo().GetByName(name)
+ server, err := r.databaseServer.GetByName(name)
if err != nil {
return nil, fmt.Errorf(`create database: can't find %s database server, please add it first`, name)
}
- if err = NewDatabaseRepo().Create(&request.DatabaseCreate{
+ if err = r.database.Create(&request.DatabaseCreate{
ServerID: server.ID,
Name: req.DBName,
CreateUser: true,
@@ -346,7 +362,7 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) {
func (r *websiteRepo) Update(req *request.WebsiteUpdate) error {
website := new(biz.Website)
- if err := app.Orm.Where("id", req.ID).First(website).Error; err != nil {
+ if err := r.db.Where("id", req.ID).First(website).Error; err != nil {
return err
}
if !website.Status {
@@ -494,7 +510,7 @@ func (r *websiteRepo) Update(req *request.WebsiteUpdate) error {
return err
}
- if err = app.Orm.Save(website).Error; err != nil {
+ if err = r.db.Save(website).Error; err != nil {
return err
}
@@ -508,7 +524,7 @@ func (r *websiteRepo) Update(req *request.WebsiteUpdate) error {
func (r *websiteRepo) Delete(req *request.WebsiteDelete) error {
website := new(biz.Website)
- if err := app.Orm.Preload("Cert").Where("id", req.ID).First(website).Error; err != nil {
+ if err := r.db.Preload("Cert").Where("id", req.ID).First(website).Error; err != nil {
return err
}
if website.Cert != nil {
@@ -527,18 +543,17 @@ func (r *websiteRepo) Delete(req *request.WebsiteDelete) error {
_ = io.Remove(website.Path)
}
if req.DB {
- repo := NewDatabaseServerRepo()
- if mysql, err := repo.GetByName("local_mysql"); err == nil {
- _ = NewDatabaseUserRepo().DeleteByNames(mysql.ID, []string{website.Name})
- _ = NewDatabaseRepo().Delete(mysql.ID, website.Name)
+ if mysql, err := r.databaseServer.GetByName("local_mysql"); err == nil {
+ _ = r.databaseUser.DeleteByNames(mysql.ID, []string{website.Name})
+ _ = r.database.Delete(mysql.ID, website.Name)
}
- if postgres, err := repo.GetByName("local_postgresql"); err == nil {
- _ = NewDatabaseUserRepo().DeleteByNames(postgres.ID, []string{website.Name})
- _ = NewDatabaseRepo().Delete(postgres.ID, website.Name)
+ if postgres, err := r.databaseServer.GetByName("local_postgresql"); err == nil {
+ _ = r.databaseUser.DeleteByNames(postgres.ID, []string{website.Name})
+ _ = r.database.Delete(postgres.ID, website.Name)
}
}
- if err := app.Orm.Delete(website).Error; err != nil {
+ if err := r.db.Delete(website).Error; err != nil {
return err
}
@@ -552,7 +567,7 @@ func (r *websiteRepo) Delete(req *request.WebsiteDelete) error {
func (r *websiteRepo) ClearLog(id uint) error {
website := new(biz.Website)
- if err := app.Orm.Where("id", id).First(website).Error; err != nil {
+ if err := r.db.Where("id", id).First(website).Error; err != nil {
return err
}
@@ -562,17 +577,17 @@ func (r *websiteRepo) ClearLog(id uint) error {
func (r *websiteRepo) UpdateRemark(id uint, remark string) error {
website := new(biz.Website)
- if err := app.Orm.Where("id", id).First(website).Error; err != nil {
+ if err := r.db.Where("id", id).First(website).Error; err != nil {
return err
}
website.Remark = remark
- return app.Orm.Save(website).Error
+ return r.db.Save(website).Error
}
func (r *websiteRepo) ResetConfig(id uint) error {
website := new(biz.Website)
- if err := app.Orm.Where("id", id).First(&website).Error; err != nil {
+ if err := r.db.Where("id", id).First(&website).Error; err != nil {
return err
}
@@ -617,7 +632,7 @@ func (r *websiteRepo) ResetConfig(id uint) error {
website.Status = true
website.Https = false
- if err = app.Orm.Save(website).Error; err != nil {
+ if err = r.db.Save(website).Error; err != nil {
return err
}
@@ -631,7 +646,7 @@ func (r *websiteRepo) ResetConfig(id uint) error {
func (r *websiteRepo) UpdateStatus(id uint, status bool) error {
website := new(biz.Website)
- if err := app.Orm.Where("id", id).First(&website).Error; err != nil {
+ if err := r.db.Where("id", id).First(&website).Error; err != nil {
return err
}
@@ -694,7 +709,7 @@ func (r *websiteRepo) UpdateStatus(id uint, status bool) error {
}
website.Status = status
- if err = app.Orm.Save(website).Error; err != nil {
+ if err = r.db.Save(website).Error; err != nil {
return err
}
@@ -715,15 +730,14 @@ func (r *websiteRepo) ObtainCert(ctx context.Context, id uint) error {
return errors.New("cannot one-key obtain wildcard certificate")
}
- account, err := NewCertAccountRepo().GetDefault(cast.ToUint(ctx.Value("user_id")))
+ account, err := r.certAccount.GetDefault(cast.ToUint(ctx.Value("user_id")))
if err != nil {
return err
}
- cRepo := NewCertRepo()
- newCert, err := cRepo.GetByWebsite(website.ID)
+ newCert, err := r.cert.GetByWebsite(website.ID)
if err != nil {
- newCert, err = cRepo.Create(&request.CertCreate{
+ newCert, err = r.cert.Create(&request.CertCreate{
Type: string(acme.KeyEC256),
Domains: website.Domains,
AutoRenew: true,
@@ -735,14 +749,14 @@ func (r *websiteRepo) ObtainCert(ctx context.Context, id uint) error {
}
}
newCert.Domains = website.Domains
- if err = app.Orm.Save(newCert).Error; err != nil {
+ if err = r.db.Save(newCert).Error; err != nil {
return err
}
- _, err = cRepo.ObtainAuto(newCert.ID)
+ _, err = r.cert.ObtainAuto(newCert.ID)
if err != nil {
return err
}
- return cRepo.Deploy(newCert.ID, website.ID)
+ return r.cert.Deploy(newCert.ID, website.ID)
}
diff --git a/internal/http/middleware/entrance.go b/internal/http/middleware/entrance.go
index 8748f066..110a0876 100644
--- a/internal/http/middleware/entrance.go
+++ b/internal/http/middleware/entrance.go
@@ -1,46 +1,48 @@
package middleware
import (
+ "github.com/go-rat/sessions"
+ "github.com/knadh/koanf/v2"
"net/http"
"strings"
"github.com/go-rat/chix"
"github.com/spf13/cast"
-
- "github.com/TheTNB/panel/internal/app"
)
// Entrance 确保通过正确的入口访问
-func Entrance(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- sess, err := app.Session.GetSession(r)
- if err != nil {
- render := chix.NewRender(w)
- render.Status(http.StatusInternalServerError)
- render.JSON(chix.M{
- "message": err.Error(),
- })
- }
+func Entrance(conf *koanf.Koanf, session *sessions.Manager) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ sess, err := session.GetSession(r)
+ if err != nil {
+ render := chix.NewRender(w)
+ render.Status(http.StatusInternalServerError)
+ render.JSON(chix.M{
+ "message": err.Error(),
+ })
+ }
- entrance := app.Conf.String("http.entrance")
- if strings.TrimSuffix(r.URL.Path, "/") == strings.TrimSuffix(entrance, "/") {
- sess.Put("verify_entrance", true)
- render := chix.NewRender(w, r)
- render.Redirect("/login")
- return
- }
+ entrance := conf.String("http.entrance")
+ if strings.TrimSuffix(r.URL.Path, "/") == strings.TrimSuffix(entrance, "/") {
+ sess.Put("verify_entrance", true)
+ render := chix.NewRender(w, r)
+ render.Redirect("/login")
+ return
+ }
- if !app.Conf.Bool("app.debug") &&
- !cast.ToBool(sess.Get("verify_entrance", false)) &&
- r.URL.Path != "/robots.txt" {
- render := chix.NewRender(w)
- render.Status(http.StatusTeapot)
- render.JSON(chix.M{
- "message": "请通过正确的入口访问",
- })
- return
- }
+ if !conf.Bool("app.debug") &&
+ !cast.ToBool(sess.Get("verify_entrance", false)) &&
+ r.URL.Path != "/robots.txt" {
+ render := chix.NewRender(w)
+ render.Status(http.StatusTeapot)
+ render.JSON(chix.M{
+ "message": "请通过正确的入口访问",
+ })
+ return
+ }
- next.ServeHTTP(w, r)
- })
+ next.ServeHTTP(w, r)
+ })
+ }
}
diff --git a/internal/http/middleware/middleware.go b/internal/http/middleware/middleware.go
index a4242948..3d97ceda 100644
--- a/internal/http/middleware/middleware.go
+++ b/internal/http/middleware/middleware.go
@@ -1,32 +1,34 @@
package middleware
import (
+ "github.com/go-chi/chi/v5"
+ "github.com/go-rat/sessions"
+ "github.com/knadh/koanf/v2"
+ "gorm.io/gorm"
"log/slog"
"net/http"
"github.com/go-chi/chi/v5/middleware"
sessionmiddleware "github.com/go-rat/sessions/middleware"
"github.com/golang-cz/httplog"
-
- "github.com/TheTNB/panel/internal/app"
)
// GlobalMiddleware is a collection of global middleware that will be applied to every request.
-func GlobalMiddleware() []func(http.Handler) http.Handler {
+func GlobalMiddleware(r *chi.Mux, conf *koanf.Koanf, db *gorm.DB, log *slog.Logger, session *sessions.Manager) []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
- sessionmiddleware.StartSession(app.Session),
- //middleware.SupressNotFound(app.Http),// bug https://github.com/go-chi/chi/pull/940
+ sessionmiddleware.StartSession(session),
+ //middleware.SupressNotFound(r),// bug https://github.com/go-chi/chi/pull/940
middleware.CleanPath,
middleware.StripSlashes,
middleware.Compress(5),
- httplog.RequestLogger(app.Logger, &httplog.Options{
+ httplog.RequestLogger(log, &httplog.Options{
Level: slog.LevelInfo,
LogRequestHeaders: []string{"User-Agent"},
}),
middleware.Recoverer,
Status,
- Entrance,
- MustLogin,
- MustInstall,
+ Entrance(conf, session),
+ MustLogin(session),
+ MustInstall(db),
}
}
diff --git a/internal/http/middleware/must_install.go b/internal/http/middleware/must_install.go
index 5767e3b5..9920735e 100644
--- a/internal/http/middleware/must_install.go
+++ b/internal/http/middleware/must_install.go
@@ -2,51 +2,53 @@ package middleware
import (
"fmt"
+ "github.com/TheTNB/panel/internal/data"
+ "gorm.io/gorm"
"net/http"
"strings"
"github.com/go-rat/chix"
-
- "github.com/TheTNB/panel/internal/data"
)
// MustInstall 确保已安装应用
-func MustInstall(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var slugs []string
- if strings.HasPrefix(r.URL.Path, "/api/website") {
- slugs = append(slugs, "nginx")
- } else if strings.HasPrefix(r.URL.Path, "/api/container") {
- slugs = append(slugs, "podman", "docker")
- } else if strings.HasPrefix(r.URL.Path, "/api/apps/") {
- pathArr := strings.Split(r.URL.Path, "/")
- if len(pathArr) < 4 {
+func MustInstall(db *gorm.DB) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var slugs []string
+ if strings.HasPrefix(r.URL.Path, "/api/website") {
+ slugs = append(slugs, "nginx")
+ } else if strings.HasPrefix(r.URL.Path, "/api/container") {
+ slugs = append(slugs, "podman", "docker")
+ } else if strings.HasPrefix(r.URL.Path, "/api/apps/") {
+ pathArr := strings.Split(r.URL.Path, "/")
+ if len(pathArr) < 4 {
+ render := chix.NewRender(w)
+ render.Status(http.StatusForbidden)
+ render.JSON(chix.M{
+ "message": "应用不存在",
+ })
+ return
+ }
+ slugs = append(slugs, pathArr[3])
+ }
+
+ flag := false
+ for _, s := range slugs {
+ if installed, _ := data.NewAppRepo(db, nil, nil).IsInstalled("slug = ?", s); installed { // TODO 优化实现
+ flag = true
+ break
+ }
+ }
+ if !flag && len(slugs) > 0 {
render := chix.NewRender(w)
render.Status(http.StatusForbidden)
render.JSON(chix.M{
- "message": "应用不存在",
+ "message": fmt.Sprintf("应用 %s 未安装", slugs),
})
return
}
- slugs = append(slugs, pathArr[3])
- }
- flag := false
- for _, s := range slugs {
- if installed, _ := data.NewAppRepo().IsInstalled("slug = ?", s); installed {
- flag = true
- break
- }
- }
- if !flag && len(slugs) > 0 {
- render := chix.NewRender(w)
- render.Status(http.StatusForbidden)
- render.JSON(chix.M{
- "message": fmt.Sprintf("应用 %s 未安装", slugs),
- })
- return
- }
-
- next.ServeHTTP(w, r)
- })
+ next.ServeHTTP(w, r)
+ })
+ }
}
diff --git a/internal/http/middleware/must_login.go b/internal/http/middleware/must_login.go
index 473ab21c..02e64257 100644
--- a/internal/http/middleware/must_login.go
+++ b/internal/http/middleware/must_login.go
@@ -4,6 +4,7 @@ import (
"context"
"crypto/sha256"
"fmt"
+ "github.com/go-rat/sessions"
"net"
"net/http"
"slices"
@@ -11,12 +12,10 @@ import (
"github.com/go-rat/chix"
"github.com/spf13/cast"
-
- "github.com/TheTNB/panel/internal/app"
)
// MustLogin 确保已登录
-func MustLogin(next http.Handler) http.Handler {
+func MustLogin(session *sessions.Manager) func(next http.Handler) http.Handler {
// 白名单
whiteList := []string{
"/api/user/key",
@@ -25,58 +24,59 @@ func MustLogin(next http.Handler) http.Handler {
"/api/user/isLogin",
"/api/dashboard/panel",
}
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ sess, err := session.GetSession(r)
+ if err != nil {
+ render := chix.NewRender(w)
+ render.Status(http.StatusInternalServerError)
+ render.JSON(chix.M{
+ "message": err.Error(),
+ })
+ }
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- sess, err := app.Session.GetSession(r)
- if err != nil {
- render := chix.NewRender(w)
- render.Status(http.StatusInternalServerError)
- render.JSON(chix.M{
- "message": err.Error(),
- })
- }
+ // 对白名单和非 API 请求放行
+ if slices.Contains(whiteList, r.URL.Path) || !strings.HasPrefix(r.URL.Path, "/api") {
+ next.ServeHTTP(w, r)
+ return
+ }
- // 对白名单和非 API 请求放行
- if slices.Contains(whiteList, r.URL.Path) || !strings.HasPrefix(r.URL.Path, "/api") {
- next.ServeHTTP(w, r)
- return
- }
-
- if sess.Missing("user_id") {
- render := chix.NewRender(w)
- render.Status(http.StatusUnauthorized)
- render.JSON(chix.M{
- "message": "会话已过期,请重新登录",
- })
- return
- }
-
- userID := cast.ToUint(sess.Get("user_id"))
- if userID == 0 {
- render := chix.NewRender(w)
- render.Status(http.StatusUnauthorized)
- render.JSON(chix.M{
- "message": "会话无效,请重新登录",
- })
- return
- }
-
- safeLogin := cast.ToBool(sess.Get("safe_login"))
- if safeLogin {
- safeClientHash := cast.ToString(sess.Get("safe_client"))
- ip, _, _ := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr))
- clientHash := fmt.Sprintf("%x", sha256.Sum256([]byte(ip)))
- if safeClientHash != clientHash || safeClientHash == "" {
+ if sess.Missing("user_id") {
render := chix.NewRender(w)
render.Status(http.StatusUnauthorized)
render.JSON(chix.M{
- "message": "客户端IP/UA变化,请重新登录",
+ "message": "会话已过期,请重新登录",
})
return
}
- }
- r = r.WithContext(context.WithValue(r.Context(), "user_id", userID)) // nolint:staticcheck
- next.ServeHTTP(w, r)
- })
+ userID := cast.ToUint(sess.Get("user_id"))
+ if userID == 0 {
+ render := chix.NewRender(w)
+ render.Status(http.StatusUnauthorized)
+ render.JSON(chix.M{
+ "message": "会话无效,请重新登录",
+ })
+ return
+ }
+
+ safeLogin := cast.ToBool(sess.Get("safe_login"))
+ if safeLogin {
+ safeClientHash := cast.ToString(sess.Get("safe_client"))
+ ip, _, _ := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr))
+ clientHash := fmt.Sprintf("%x", sha256.Sum256([]byte(ip)))
+ if safeClientHash != clientHash || safeClientHash == "" {
+ render := chix.NewRender(w)
+ render.Status(http.StatusUnauthorized)
+ render.JSON(chix.M{
+ "message": "客户端IP/UA变化,请重新登录",
+ })
+ return
+ }
+ }
+
+ r = r.WithContext(context.WithValue(r.Context(), "user_id", userID)) // nolint:staticcheck
+ next.ServeHTTP(w, r)
+ })
+ }
}
diff --git a/internal/job/cert_renew.go b/internal/job/cert_renew.go
index a5740c2f..21c9dacd 100644
--- a/internal/job/cert_renew.go
+++ b/internal/job/cert_renew.go
@@ -1,23 +1,27 @@
package job
import (
+ "gorm.io/gorm"
"log/slog"
"time"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
pkgcert "github.com/TheTNB/panel/pkg/cert"
)
// CertRenew 证书续签
type CertRenew struct {
+ db *gorm.DB
+ log *slog.Logger
certRepo biz.CertRepo
}
-func NewCertRenew() *CertRenew {
+func NewCertRenew(db *gorm.DB, log *slog.Logger, cert biz.CertRepo) *CertRenew {
return &CertRenew{
- certRepo: data.NewCertRepo(),
+ db: db,
+ log: log,
+ certRepo: cert,
}
}
@@ -27,8 +31,8 @@ func (r *CertRenew) Run() {
}
var certs []biz.Cert
- if err := app.Orm.Preload("Website").Preload("Account").Preload("DNS").Find(&certs).Error; err != nil {
- app.Logger.Warn("获取证书失败", slog.Any("err", err))
+ if err := r.db.Preload("Website").Preload("Account").Preload("DNS").Find(&certs).Error; err != nil {
+ r.log.Warn("获取证书失败", slog.Any("err", err))
return
}
@@ -50,7 +54,7 @@ func (r *CertRenew) Run() {
_, err = r.certRepo.Renew(cert.ID)
if err != nil {
- app.Logger.Warn("续签证书失败", slog.Any("err", err))
+ r.log.Warn("续签证书失败", slog.Any("err", err))
}
}
}
diff --git a/internal/job/init.go b/internal/job/init.go
index b1b812c3..143165d0 100644
--- a/internal/job/init.go
+++ b/internal/job/init.go
@@ -4,16 +4,18 @@ import (
"github.com/robfig/cron/v3"
)
+// TODO fix me
func Boot(c *cron.Cron) error {
- if _, err := c.AddJob("* * * * *", NewMonitoring()); err != nil {
+ /*if _, err := c.AddJob("* * * * *", NewMonitoring()); err != nil {
return err
}
if _, err := c.AddJob("0 4 * * *", NewCertRenew()); err != nil {
return err
}
+
if _, err := c.AddJob("0 2 * * *", NewPanelTask()); err != nil {
return err
- }
+ }*/
return nil
}
diff --git a/internal/job/monitoring.go b/internal/job/monitoring.go
index 8c3ebf6d..5e8e7b3b 100644
--- a/internal/job/monitoring.go
+++ b/internal/job/monitoring.go
@@ -1,6 +1,7 @@
package job
import (
+ "gorm.io/gorm"
"log/slog"
"time"
@@ -8,18 +9,21 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/pkg/tools"
)
// Monitoring 系统监控
type Monitoring struct {
+ db *gorm.DB
+ log *slog.Logger
settingRepo biz.SettingRepo
}
-func NewMonitoring() *Monitoring {
+func NewMonitoring(db *gorm.DB, log *slog.Logger, setting biz.SettingRepo) *Monitoring {
return &Monitoring{
- settingRepo: data.NewSettingRepo(),
+ db: db,
+ log: log,
+ settingRepo: setting,
}
}
@@ -47,8 +51,8 @@ func (r *Monitoring) Run() {
return
}
- if err = app.Orm.Create(&biz.Monitor{Info: info}).Error; err != nil {
- app.Logger.Warn("记录系统监控失败", slog.Any("err", err))
+ if err = r.db.Create(&biz.Monitor{Info: info}).Error; err != nil {
+ r.log.Warn("记录系统监控失败", slog.Any("err", err))
return
}
@@ -61,8 +65,8 @@ func (r *Monitoring) Run() {
if day <= 0 || app.Status != app.StatusNormal {
return
}
- if err = app.Orm.Where("created_at < ?", time.Now().AddDate(0, 0, -day).Format(time.DateTime)).Delete(&biz.Monitor{}).Error; err != nil {
- app.Logger.Warn("删除过期系统监控失败", slog.Any("err", err))
+ if err = r.db.Where("created_at < ?", time.Now().AddDate(0, 0, -day).Format(time.DateTime)).Delete(&biz.Monitor{}).Error; err != nil {
+ r.log.Warn("删除过期系统监控失败", slog.Any("err", err))
return
}
}
diff --git a/internal/job/panel_task.go b/internal/job/panel_task.go
index ddcb4fa8..00213390 100644
--- a/internal/job/panel_task.go
+++ b/internal/job/panel_task.go
@@ -1,6 +1,7 @@
package job
import (
+ "gorm.io/gorm"
"log/slog"
"math/rand/v2"
"runtime"
@@ -9,21 +10,24 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
)
// PanelTask 面板每日任务
type PanelTask struct {
+ db *gorm.DB
+ log *slog.Logger
backupRepo biz.BackupRepo
cacheRepo biz.CacheRepo
settingRepo biz.SettingRepo
}
-func NewPanelTask() *PanelTask {
+func NewPanelTask(db *gorm.DB, log *slog.Logger, backup biz.BackupRepo, cache biz.CacheRepo, setting biz.SettingRepo) *PanelTask {
return &PanelTask{
- backupRepo: data.NewBackupRepo(),
- cacheRepo: data.NewCacheRepo(),
- settingRepo: data.NewSettingRepo(),
+ db: db,
+ log: log,
+ backupRepo: backup,
+ cacheRepo: cache,
+ settingRepo: setting,
}
}
@@ -31,25 +35,25 @@ func (r *PanelTask) Run() {
app.Status = app.StatusMaintain
// 优化数据库
- if err := app.Orm.Exec("VACUUM").Error; err != nil {
+ if err := r.db.Exec("VACUUM").Error; err != nil {
app.Status = app.StatusFailed
- app.Logger.Warn("优化面板数据库失败", slog.Any("err", err))
+ r.log.Warn("优化面板数据库失败", slog.Any("err", err))
}
- if err := app.Orm.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error; err != nil {
+ if err := r.db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error; err != nil {
app.Status = app.StatusFailed
- app.Logger.Warn("优化面板数据库失败", slog.Any("err", err))
+ r.log.Warn("优化面板数据库失败", slog.Any("err", err))
}
// 备份面板
if err := r.backupRepo.Create(biz.BackupTypePanel, ""); err != nil {
- app.Logger.Warn("备份面板失败", slog.Any("err", err))
+ r.log.Warn("备份面板失败", slog.Any("err", err))
}
// 清理备份
path, err := r.backupRepo.GetPath("panel")
if err == nil {
if err = r.backupRepo.ClearExpired(path, "panel_", 10); err != nil {
- app.Logger.Warn("清理面板备份失败", slog.Any("err", err))
+ r.log.Warn("清理面板备份失败", slog.Any("err", err))
}
}
@@ -57,7 +61,7 @@ func (r *PanelTask) Run() {
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
if err = r.cacheRepo.UpdateApps(); err != nil {
- app.Logger.Warn("更新商店缓存失败", slog.Any("err", err))
+ r.log.Warn("更新商店缓存失败", slog.Any("err", err))
}
}
})
@@ -66,7 +70,7 @@ func (r *PanelTask) Run() {
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
if err = r.cacheRepo.UpdateRewrites(); err != nil {
- app.Logger.Warn("更新伪静态缓存失败", slog.Any("err", err))
+ r.log.Warn("更新伪静态缓存失败", slog.Any("err", err))
}
}
})
diff --git a/internal/queuejob/process_task.go b/internal/queuejob/process_task.go
index cd78adfd..7db9a22e 100644
--- a/internal/queuejob/process_task.go
+++ b/internal/queuejob/process_task.go
@@ -4,20 +4,21 @@ import (
"errors"
"log/slog"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/pkg/shell"
)
// ProcessTask 处理面板任务
type ProcessTask struct {
+ log *slog.Logger
taskRepo biz.TaskRepo
taskID uint
}
// NewProcessTask 实例化 ProcessTask
-func NewProcessTask(taskRepo biz.TaskRepo) *ProcessTask {
+func NewProcessTask(log *slog.Logger, taskRepo biz.TaskRepo) *ProcessTask {
return &ProcessTask{
+ log: log,
taskRepo: taskRepo,
}
}
@@ -50,6 +51,6 @@ func (r *ProcessTask) Handle(args ...any) error {
}
func (r *ProcessTask) ErrHandle(err error) {
- app.Logger.Warn("background task failed", slog.Any("task_id", r.taskID), slog.Any("err", err))
+ r.log.Warn("background task failed", slog.Any("task_id", r.taskID), slog.Any("err", err))
_ = r.taskRepo.UpdateStatus(r.taskID, biz.TaskStatusFailed)
}
diff --git a/internal/route/cli.go b/internal/route/cli.go
index db4c72d4..15d8eff4 100644
--- a/internal/route/cli.go
+++ b/internal/route/cli.go
@@ -6,43 +6,52 @@ import (
"github.com/TheTNB/panel/internal/service"
)
-func Cli() []*cli.Command {
- cliService := service.NewCliService()
+type Cli struct {
+ cli *service.CliService
+}
+
+func NewCli(cli *service.CliService) *Cli {
+ return &Cli{
+ cli: cli,
+ }
+}
+
+func (route *Cli) Commands() []*cli.Command {
return []*cli.Command{
{
Name: "restart",
Usage: "重启面板服务",
- Action: cliService.Restart,
+ Action: route.cli.Restart,
},
{
Name: "stop",
Usage: "停止面板服务",
- Action: cliService.Stop,
+ Action: route.cli.Stop,
},
{
Name: "start",
Usage: "启动面板服务",
- Action: cliService.Start,
+ Action: route.cli.Start,
},
{
Name: "update",
Usage: "更新面板",
- Action: cliService.Update,
+ Action: route.cli.Update,
},
{
Name: "sync",
Usage: "同步数据",
- Action: cliService.Sync,
+ Action: route.cli.Sync,
},
{
Name: "fix",
Usage: "修复面板",
- Action: cliService.Fix,
+ Action: route.cli.Fix,
},
{
Name: "info",
Usage: "输出面板基本信息",
- Action: cliService.Info,
+ Action: route.cli.Info,
},
{
Name: "user",
@@ -51,17 +60,17 @@ func Cli() []*cli.Command {
{
Name: "list",
Usage: "列出所有用户",
- Action: cliService.UserList,
+ Action: route.cli.UserList,
},
{
Name: "username",
Usage: "修改用户名",
- Action: cliService.UserName,
+ Action: route.cli.UserName,
},
{
Name: "password",
Usage: "修改用户密码",
- Action: cliService.UserPassword,
+ Action: route.cli.UserPassword,
},
},
},
@@ -72,17 +81,17 @@ func Cli() []*cli.Command {
{
Name: "on",
Usage: "开启HTTPS",
- Action: cliService.HTTPSOn,
+ Action: route.cli.HTTPSOn,
},
{
Name: "off",
Usage: "关闭HTTPS",
- Action: cliService.HTTPSOff,
+ Action: route.cli.HTTPSOff,
},
{
Name: "generate",
Usage: "生成HTTPS证书",
- Action: cliService.HTTPSGenerate,
+ Action: route.cli.HTTPSGenerate,
},
},
},
@@ -93,19 +102,19 @@ func Cli() []*cli.Command {
{
Name: "on",
Usage: "开启访问入口",
- Action: cliService.EntranceOn,
+ Action: route.cli.EntranceOn,
},
{
Name: "off",
Usage: "关闭访问入口",
- Action: cliService.EntranceOff,
+ Action: route.cli.EntranceOff,
},
},
},
{
Name: "port",
Usage: "修改面板端口",
- Action: cliService.Port,
+ Action: route.cli.Port,
},
{
Name: "website",
@@ -114,7 +123,7 @@ func Cli() []*cli.Command {
{
Name: "create",
Usage: "创建新网站",
- Action: cliService.WebsiteCreate,
+ Action: route.cli.WebsiteCreate,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -147,7 +156,7 @@ func Cli() []*cli.Command {
{
Name: "remove",
Usage: "移除网站",
- Action: cliService.WebsiteRemove,
+ Action: route.cli.WebsiteRemove,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -160,7 +169,7 @@ func Cli() []*cli.Command {
{
Name: "delete",
Usage: "删除网站(包括网站目录、同名数据库)",
- Action: cliService.WebsiteDelete,
+ Action: route.cli.WebsiteDelete,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -174,7 +183,7 @@ func Cli() []*cli.Command {
Name: "write",
Usage: "写入网站数据(仅限指导下使用)",
Hidden: true,
- Action: cliService.WebsiteWrite,
+ Action: route.cli.WebsiteWrite,
},
},
},
@@ -185,7 +194,7 @@ func Cli() []*cli.Command {
{
Name: "add-server",
Usage: "添加数据库服务器",
- Action: cliService.DatabaseAddServer,
+ Action: route.cli.DatabaseAddServer,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
@@ -224,7 +233,7 @@ func Cli() []*cli.Command {
{
Name: "delete-server",
Usage: "删除数据库服务器",
- Action: cliService.DatabaseDeleteServer,
+ Action: route.cli.DatabaseDeleteServer,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -243,7 +252,7 @@ func Cli() []*cli.Command {
{
Name: "website",
Usage: "备份网站",
- Action: cliService.BackupWebsite,
+ Action: route.cli.BackupWebsite,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -261,7 +270,7 @@ func Cli() []*cli.Command {
{
Name: "database",
Usage: "备份数据库",
- Action: cliService.BackupDatabase,
+ Action: route.cli.BackupDatabase,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
@@ -285,7 +294,7 @@ func Cli() []*cli.Command {
{
Name: "panel",
Usage: "备份面板",
- Action: cliService.BackupPanel,
+ Action: route.cli.BackupPanel,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
@@ -297,7 +306,7 @@ func Cli() []*cli.Command {
{
Name: "clear",
Usage: "清理备份",
- Action: cliService.BackupClear,
+ Action: route.cli.BackupClear,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
@@ -333,7 +342,7 @@ func Cli() []*cli.Command {
{
Name: "website",
Usage: "网站",
- Action: cliService.CutoffWebsite,
+ Action: route.cli.CutoffWebsite,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
@@ -352,7 +361,7 @@ func Cli() []*cli.Command {
{
Name: "clear",
Usage: "清理切割的日志",
- Action: cliService.CutoffClear,
+ Action: route.cli.CutoffClear,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
@@ -388,29 +397,29 @@ func Cli() []*cli.Command {
{
Name: "install",
Usage: "安装应用",
- Action: cliService.AppInstall,
+ Action: route.cli.AppInstall,
},
{
Name: "uninstall",
Usage: "卸载应用",
- Action: cliService.AppUnInstall,
+ Action: route.cli.AppUnInstall,
},
{
Name: "update",
Usage: "更新应用",
- Action: cliService.AppUpdate,
+ Action: route.cli.AppUpdate,
},
{
Name: "write",
Usage: "添加面板应用标记(仅限指导下使用)",
Hidden: true,
- Action: cliService.AppWrite,
+ Action: route.cli.AppWrite,
},
{
Name: "remove",
Usage: "移除面板应用标记(仅限指导下使用)",
Hidden: true,
- Action: cliService.AppRemove,
+ Action: route.cli.AppRemove,
},
},
},
@@ -423,38 +432,38 @@ func Cli() []*cli.Command {
Name: "get",
Usage: "获取面板设置(仅限指导下使用)",
Hidden: true,
- Action: cliService.GetSetting,
+ Action: route.cli.GetSetting,
},
{
Name: "write",
Usage: "写入面板设置(仅限指导下使用)",
Hidden: true,
- Action: cliService.WriteSetting,
+ Action: route.cli.WriteSetting,
},
{
Name: "remove",
Usage: "移除面板设置(仅限指导下使用)",
Hidden: true,
- Action: cliService.RemoveSetting,
+ Action: route.cli.RemoveSetting,
},
},
},
{
Name: "sync-time",
Usage: "同步系统时间",
- Action: cliService.SyncTime,
+ Action: route.cli.SyncTime,
},
{
Name: "clear-task",
Usage: "清理面板任务队列(仅限指导下使用)",
Hidden: true,
- Action: cliService.ClearTask,
+ Action: route.cli.ClearTask,
},
{
Name: "init",
Usage: "初始化面板(仅限指导下使用)",
Hidden: true,
- Action: cliService.Init,
+ Action: route.cli.Init,
},
}
}
diff --git a/internal/route/http.go b/internal/route/http.go
index e1baa884..3d11f876 100644
--- a/internal/route/http.go
+++ b/internal/route/http.go
@@ -14,274 +14,333 @@ import (
"github.com/TheTNB/panel/internal/service"
)
-func Http(r chi.Router) {
+type Http struct {
+ user *service.UserService
+ dashboard *service.DashboardService
+ task *service.TaskService
+ website *service.WebsiteService
+ database *service.DatabaseService
+ databaseServer *service.DatabaseServerService
+ databaseUser *service.DatabaseUserService
+ backup *service.BackupService
+ cert *service.CertService
+ certDNS *service.CertDNSService
+ certAccount *service.CertAccountService
+ app *service.AppService
+ cron *service.CronService
+ process *service.ProcessService
+ safe *service.SafeService
+ firewall *service.FirewallService
+ ssh *service.SSHService
+ container *service.ContainerService
+ containerNetwork *service.ContainerNetworkService
+ containerImage *service.ContainerImageService
+ containerVolume *service.ContainerVolumeService
+ file *service.FileService
+ monitor *service.MonitorService
+ setting *service.SettingService
+ systemctl *service.SystemctlService
+}
+
+func NewHttp(
+ user *service.UserService,
+ dashboard *service.DashboardService,
+ task *service.TaskService,
+ website *service.WebsiteService,
+ database *service.DatabaseService,
+ databaseServer *service.DatabaseServerService,
+ databaseUser *service.DatabaseUserService,
+ backup *service.BackupService,
+ cert *service.CertService,
+ certDNS *service.CertDNSService,
+ certAccount *service.CertAccountService,
+ app *service.AppService,
+ cron *service.CronService,
+ process *service.ProcessService,
+ safe *service.SafeService,
+ firewall *service.FirewallService,
+ ssh *service.SSHService,
+ container *service.ContainerService,
+ containerNetwork *service.ContainerNetworkService,
+ containerImage *service.ContainerImageService,
+ containerVolume *service.ContainerVolumeService,
+ file *service.FileService,
+ monitor *service.MonitorService,
+ setting *service.SettingService,
+ systemctl *service.SystemctlService,
+) *Http {
+ return &Http{
+ user: user,
+ dashboard: dashboard,
+ task: task,
+ website: website,
+ database: database,
+ databaseServer: databaseServer,
+ databaseUser: databaseUser,
+ backup: backup,
+ cert: cert,
+ certDNS: certDNS,
+ certAccount: certAccount,
+ app: app,
+ cron: cron,
+ process: process,
+ safe: safe,
+ firewall: firewall,
+ ssh: ssh,
+ container: container,
+ containerNetwork: containerNetwork,
+ containerImage: containerImage,
+ containerVolume: containerVolume,
+ file: file,
+ monitor: monitor,
+ setting: setting,
+ systemctl: systemctl,
+ }
+}
+
+func (route *Http) Register(r *chi.Mux) {
r.Route("/api", func(r chi.Router) {
r.Route("/user", func(r chi.Router) {
- user := service.NewUserService()
- r.Get("/key", user.GetKey)
- r.With(middleware.Throttle(5, time.Minute)).Post("/login", user.Login)
- r.Post("/logout", user.Logout)
- r.Get("/isLogin", user.IsLogin)
- r.Get("/info", user.Info)
+ r.Get("/key", route.user.GetKey)
+ r.With(middleware.Throttle(5, time.Minute)).Post("/login", route.user.Login)
+ r.Post("/logout", route.user.Logout)
+ r.Get("/isLogin", route.user.IsLogin)
+ r.Get("/info", route.user.Info)
})
r.Route("/dashboard", func(r chi.Router) {
- dashboard := service.NewDashboardService()
- r.Get("/panel", dashboard.Panel)
- r.Get("/homeApps", dashboard.HomeApps)
- r.Post("/current", dashboard.Current)
- r.Get("/systemInfo", dashboard.SystemInfo)
- r.Get("/countInfo", dashboard.CountInfo)
- r.Get("/installedDbAndPhp", dashboard.InstalledDbAndPhp)
- r.Get("/checkUpdate", dashboard.CheckUpdate)
- r.Get("/updateInfo", dashboard.UpdateInfo)
- r.Post("/update", dashboard.Update)
- r.Post("/restart", dashboard.Restart)
+ r.Get("/panel", route.dashboard.Panel)
+ r.Get("/homeApps", route.dashboard.HomeApps)
+ r.Post("/current", route.dashboard.Current)
+ r.Get("/systemInfo", route.dashboard.SystemInfo)
+ r.Get("/countInfo", route.dashboard.CountInfo)
+ r.Get("/installedDbAndPhp", route.dashboard.InstalledDbAndPhp)
+ r.Get("/checkUpdate", route.dashboard.CheckUpdate)
+ r.Get("/updateInfo", route.dashboard.UpdateInfo)
+ r.Post("/update", route.dashboard.Update)
+ r.Post("/restart", route.dashboard.Restart)
})
r.Route("/task", func(r chi.Router) {
- task := service.NewTaskService()
- r.Get("/status", task.Status)
- r.Get("/", task.List)
- r.Get("/{id}", task.Get)
- r.Delete("/{id}", task.Delete)
+ r.Get("/status", route.task.Status)
+ r.Get("/", route.task.List)
+ r.Get("/{id}", route.task.Get)
+ r.Delete("/{id}", route.task.Delete)
})
r.Route("/website", func(r chi.Router) {
- website := service.NewWebsiteService()
- r.Get("/rewrites", website.GetRewrites)
- r.Get("/defaultConfig", website.GetDefaultConfig)
- r.Post("/defaultConfig", website.UpdateDefaultConfig)
- r.Get("/", website.List)
- r.Post("/", website.Create)
- r.Get("/{id}", website.Get)
- r.Put("/{id}", website.Update)
- r.Delete("/{id}", website.Delete)
- r.Delete("/{id}/log", website.ClearLog)
- r.Post("/{id}/updateRemark", website.UpdateRemark)
- r.Post("/{id}/resetConfig", website.ResetConfig)
- r.Post("/{id}/status", website.UpdateStatus)
- r.Post("/{id}/obtainCert", website.ObtainCert)
+ r.Get("/rewrites", route.website.GetRewrites)
+ r.Get("/defaultConfig", route.website.GetDefaultConfig)
+ r.Post("/defaultConfig", route.website.UpdateDefaultConfig)
+ r.Get("/", route.website.List)
+ r.Post("/", route.website.Create)
+ r.Get("/{id}", route.website.Get)
+ r.Put("/{id}", route.website.Update)
+ r.Delete("/{id}", route.website.Delete)
+ r.Delete("/{id}/log", route.website.ClearLog)
+ r.Post("/{id}/updateRemark", route.website.UpdateRemark)
+ r.Post("/{id}/resetConfig", route.website.ResetConfig)
+ r.Post("/{id}/status", route.website.UpdateStatus)
+ r.Post("/{id}/obtainCert", route.website.ObtainCert)
})
r.Route("/database", func(r chi.Router) {
- database := service.NewDatabaseService()
- r.Get("/", database.List)
- r.Post("/", database.Create)
- r.Delete("/", database.Delete)
- r.Post("/comment", database.Comment)
+ r.Get("/", route.database.List)
+ r.Post("/", route.database.Create)
+ r.Delete("/", route.database.Delete)
+ r.Post("/comment", route.database.Comment)
})
r.Route("/databaseServer", func(r chi.Router) {
- server := service.NewDatabaseServerService()
- r.Get("/", server.List)
- r.Post("/", server.Create)
- r.Get("/{id}", server.Get)
- r.Put("/{id}", server.Update)
- r.Put("/{id}/remark", server.UpdateRemark)
- r.Delete("/{id}", server.Delete)
- r.Post("/{id}/sync", server.Sync)
+ r.Get("/", route.databaseServer.List)
+ r.Post("/", route.databaseServer.Create)
+ r.Get("/{id}", route.databaseServer.Get)
+ r.Put("/{id}", route.databaseServer.Update)
+ r.Put("/{id}/remark", route.databaseServer.UpdateRemark)
+ r.Delete("/{id}", route.databaseServer.Delete)
+ r.Post("/{id}/sync", route.databaseServer.Sync)
})
r.Route("/databaseUser", func(r chi.Router) {
- user := service.NewDatabaseUserService()
- r.Get("/", user.List)
- r.Post("/", user.Create)
- r.Get("/{id}", user.Get)
- r.Put("/{id}", user.Update)
- r.Put("/{id}/remark", user.UpdateRemark)
- r.Delete("/{id}", user.Delete)
+ r.Get("/", route.databaseUser.List)
+ r.Post("/", route.databaseUser.Create)
+ r.Get("/{id}", route.databaseUser.Get)
+ r.Put("/{id}", route.databaseUser.Update)
+ r.Put("/{id}/remark", route.databaseUser.UpdateRemark)
+ r.Delete("/{id}", route.databaseUser.Delete)
})
r.Route("/backup", func(r chi.Router) {
- backup := service.NewBackupService()
- r.Get("/{type}", backup.List)
- r.Post("/{type}", backup.Create)
- r.Post("/{type}/upload", backup.Upload)
- r.Delete("/{type}/delete", backup.Delete)
- r.Post("/{type}/restore", backup.Restore)
+ r.Get("/{type}", route.backup.List)
+ r.Post("/{type}", route.backup.Create)
+ r.Post("/{type}/upload", route.backup.Upload)
+ r.Delete("/{type}/delete", route.backup.Delete)
+ r.Post("/{type}/restore", route.backup.Restore)
})
r.Route("/cert", func(r chi.Router) {
- cert := service.NewCertService()
- r.Get("/caProviders", cert.CAProviders)
- r.Get("/dnsProviders", cert.DNSProviders)
- r.Get("/algorithms", cert.Algorithms)
+ r.Get("/caProviders", route.cert.CAProviders)
+ r.Get("/dnsProviders", route.cert.DNSProviders)
+ r.Get("/algorithms", route.cert.Algorithms)
r.Route("/cert", func(r chi.Router) {
- r.Get("/", cert.List)
- r.Post("/", cert.Create)
- r.Post("/upload", cert.Upload)
- r.Put("/{id}", cert.Update)
- r.Get("/{id}", cert.Get)
- r.Delete("/{id}", cert.Delete)
- r.Post("/{id}/obtainAuto", cert.ObtainAuto)
- r.Post("/{id}/obtainManual", cert.ObtainManual)
- r.Post("/{id}/obtainSelfSigned", cert.ObtainSelfSigned)
- r.Post("/{id}/renew", cert.Renew)
- r.Post("/{id}/manualDNS", cert.ManualDNS)
- r.Post("/{id}/deploy", cert.Deploy)
+ r.Get("/", route.cert.List)
+ r.Post("/", route.cert.Create)
+ r.Post("/upload", route.cert.Upload)
+ r.Put("/{id}", route.cert.Update)
+ r.Get("/{id}", route.cert.Get)
+ r.Delete("/{id}", route.cert.Delete)
+ r.Post("/{id}/obtainAuto", route.cert.ObtainAuto)
+ r.Post("/{id}/obtainManual", route.cert.ObtainManual)
+ r.Post("/{id}/obtainSelfSigned", route.cert.ObtainSelfSigned)
+ r.Post("/{id}/renew", route.cert.Renew)
+ r.Post("/{id}/manualDNS", route.cert.ManualDNS)
+ r.Post("/{id}/deploy", route.cert.Deploy)
})
r.Route("/dns", func(r chi.Router) {
- certDNS := service.NewCertDNSService()
- r.Get("/", certDNS.List)
- r.Post("/", certDNS.Create)
- r.Put("/{id}", certDNS.Update)
- r.Get("/{id}", certDNS.Get)
- r.Delete("/{id}", certDNS.Delete)
+ r.Get("/", route.certDNS.List)
+ r.Post("/", route.certDNS.Create)
+ r.Put("/{id}", route.certDNS.Update)
+ r.Get("/{id}", route.certDNS.Get)
+ r.Delete("/{id}", route.certDNS.Delete)
})
r.Route("/account", func(r chi.Router) {
- certAccount := service.NewCertAccountService()
- r.Get("/", certAccount.List)
- r.Post("/", certAccount.Create)
- r.Put("/{id}", certAccount.Update)
- r.Get("/{id}", certAccount.Get)
- r.Delete("/{id}", certAccount.Delete)
+ r.Get("/", route.certAccount.List)
+ r.Post("/", route.certAccount.Create)
+ r.Put("/{id}", route.certAccount.Update)
+ r.Get("/{id}", route.certAccount.Get)
+ r.Delete("/{id}", route.certAccount.Delete)
})
})
r.Route("/app", func(r chi.Router) {
- app := service.NewAppService()
- r.Get("/list", app.List)
- r.Post("/install", app.Install)
- r.Post("/uninstall", app.Uninstall)
- r.Post("/update", app.Update)
- r.Post("/updateShow", app.UpdateShow)
- r.Get("/isInstalled", app.IsInstalled)
- r.Get("/updateCache", app.UpdateCache)
+ r.Get("/list", route.app.List)
+ r.Post("/install", route.app.Install)
+ r.Post("/uninstall", route.app.Uninstall)
+ r.Post("/update", route.app.Update)
+ r.Post("/updateShow", route.app.UpdateShow)
+ r.Get("/isInstalled", route.app.IsInstalled)
+ r.Get("/updateCache", route.app.UpdateCache)
})
r.Route("/cron", func(r chi.Router) {
- cron := service.NewCronService()
- r.Get("/", cron.List)
- r.Post("/", cron.Create)
- r.Put("/{id}", cron.Update)
- r.Get("/{id}", cron.Get)
- r.Delete("/{id}", cron.Delete)
- r.Post("/{id}/status", cron.Status)
+ r.Get("/", route.cron.List)
+ r.Post("/", route.cron.Create)
+ r.Put("/{id}", route.cron.Update)
+ r.Get("/{id}", route.cron.Get)
+ r.Delete("/{id}", route.cron.Delete)
+ r.Post("/{id}/status", route.cron.Status)
})
r.Route("/process", func(r chi.Router) {
- process := service.NewProcessService()
- r.Get("/", process.List)
- r.Post("/kill", process.Kill)
+ r.Get("/", route.process.List)
+ r.Post("/kill", route.process.Kill)
})
r.Route("/safe", func(r chi.Router) {
- safe := service.NewSafeService()
- r.Get("/ssh", safe.GetSSH)
- r.Post("/ssh", safe.UpdateSSH)
- r.Get("/ping", safe.GetPingStatus)
- r.Post("/ping", safe.UpdatePingStatus)
+ r.Get("/ssh", route.safe.GetSSH)
+ r.Post("/ssh", route.safe.UpdateSSH)
+ r.Get("/ping", route.safe.GetPingStatus)
+ r.Post("/ping", route.safe.UpdatePingStatus)
})
r.Route("/firewall", func(r chi.Router) {
- firewall := service.NewFirewallService()
- r.Get("/status", firewall.GetStatus)
- r.Post("/status", firewall.UpdateStatus)
- r.Get("/rule", firewall.GetRules)
- r.Post("/rule", firewall.CreateRule)
- r.Delete("/rule", firewall.DeleteRule)
- r.Get("/ipRule", firewall.GetIPRules)
- r.Post("/ipRule", firewall.CreateIPRule)
- r.Delete("/ipRule", firewall.DeleteIPRule)
- r.Get("/forward", firewall.GetForwards)
- r.Post("/forward", firewall.CreateForward)
- r.Delete("/forward", firewall.DeleteForward)
+ r.Get("/status", route.firewall.GetStatus)
+ r.Post("/status", route.firewall.UpdateStatus)
+ r.Get("/rule", route.firewall.GetRules)
+ r.Post("/rule", route.firewall.CreateRule)
+ r.Delete("/rule", route.firewall.DeleteRule)
+ r.Get("/ipRule", route.firewall.GetIPRules)
+ r.Post("/ipRule", route.firewall.CreateIPRule)
+ r.Delete("/ipRule", route.firewall.DeleteIPRule)
+ r.Get("/forward", route.firewall.GetForwards)
+ r.Post("/forward", route.firewall.CreateForward)
+ r.Delete("/forward", route.firewall.DeleteForward)
})
r.Route("/ssh", func(r chi.Router) {
- ssh := service.NewSSHService()
- r.Get("/", ssh.List)
- r.Post("/", ssh.Create)
- r.Put("/{id}", ssh.Update)
- r.Get("/{id}", ssh.Get)
- r.Delete("/{id}", ssh.Delete)
+ r.Get("/", route.ssh.List)
+ r.Post("/", route.ssh.Create)
+ r.Put("/{id}", route.ssh.Update)
+ r.Get("/{id}", route.ssh.Get)
+ r.Delete("/{id}", route.ssh.Delete)
})
r.Route("/container", func(r chi.Router) {
r.Route("/container", func(r chi.Router) {
- container := service.NewContainerService()
- r.Get("/", container.List)
- r.Get("/search", container.Search)
- r.Post("/", container.Create)
- r.Delete("/{id}", container.Remove)
- r.Post("/{id}/start", container.Start)
- r.Post("/{id}/stop", container.Stop)
- r.Post("/{id}/restart", container.Restart)
- r.Post("/{id}/pause", container.Pause)
- r.Post("/{id}/unpause", container.Unpause)
- r.Post("/{id}/kill", container.Kill)
- r.Post("/{id}/rename", container.Rename)
- r.Get("/{id}/logs", container.Logs)
- r.Post("/prune", container.Prune)
+ r.Get("/", route.container.List)
+ r.Get("/search", route.container.Search)
+ r.Post("/", route.container.Create)
+ r.Delete("/{id}", route.container.Remove)
+ r.Post("/{id}/start", route.container.Start)
+ r.Post("/{id}/stop", route.container.Stop)
+ r.Post("/{id}/restart", route.container.Restart)
+ r.Post("/{id}/pause", route.container.Pause)
+ r.Post("/{id}/unpause", route.container.Unpause)
+ r.Post("/{id}/kill", route.container.Kill)
+ r.Post("/{id}/rename", route.container.Rename)
+ r.Get("/{id}/logs", route.container.Logs)
+ r.Post("/prune", route.container.Prune)
})
r.Route("/network", func(r chi.Router) {
- containerNetwork := service.NewContainerNetworkService()
- r.Get("/", containerNetwork.List)
- r.Post("/", containerNetwork.Create)
- r.Delete("/{id}", containerNetwork.Remove)
- r.Post("/prune", containerNetwork.Prune)
+ r.Get("/", route.containerNetwork.List)
+ r.Post("/", route.containerNetwork.Create)
+ r.Delete("/{id}", route.containerNetwork.Remove)
+ r.Post("/prune", route.containerNetwork.Prune)
})
r.Route("/image", func(r chi.Router) {
- containerImage := service.NewContainerImageService()
- r.Get("/", containerImage.List)
- r.Post("/", containerImage.Pull)
- r.Delete("/{id}", containerImage.Remove)
- r.Post("/prune", containerImage.Prune)
+ r.Get("/", route.containerImage.List)
+ r.Post("/", route.containerImage.Pull)
+ r.Delete("/{id}", route.containerImage.Remove)
+ r.Post("/prune", route.containerImage.Prune)
})
r.Route("/volume", func(r chi.Router) {
- containerVolume := service.NewContainerVolumeService()
- r.Get("/", containerVolume.List)
- r.Post("/", containerVolume.Create)
- r.Delete("/{id}", containerVolume.Remove)
- r.Post("/prune", containerVolume.Prune)
+ r.Get("/", route.containerVolume.List)
+ r.Post("/", route.containerVolume.Create)
+ r.Delete("/{id}", route.containerVolume.Remove)
+ r.Post("/prune", route.containerVolume.Prune)
})
})
r.Route("/file", func(r chi.Router) {
- file := service.NewFileService()
- r.Post("/create", file.Create)
- r.Get("/content", file.Content)
- r.Post("/save", file.Save)
- r.Post("/delete", file.Delete)
- r.Post("/upload", file.Upload)
- r.Post("/exist", file.Exist)
- r.Post("/move", file.Move)
- r.Post("/copy", file.Copy)
- r.Get("/download", file.Download)
- r.Post("/remoteDownload", file.RemoteDownload)
- r.Get("/info", file.Info)
- r.Post("/permission", file.Permission)
- r.Post("/compress", file.Compress)
- r.Post("/unCompress", file.UnCompress)
- r.Get("/search", file.Search)
- r.Get("/list", file.List)
+ r.Post("/create", route.file.Create)
+ r.Get("/content", route.file.Content)
+ r.Post("/save", route.file.Save)
+ r.Post("/delete", route.file.Delete)
+ r.Post("/upload", route.file.Upload)
+ r.Post("/exist", route.file.Exist)
+ r.Post("/move", route.file.Move)
+ r.Post("/copy", route.file.Copy)
+ r.Get("/download", route.file.Download)
+ r.Post("/remoteDownload", route.file.RemoteDownload)
+ r.Get("/info", route.file.Info)
+ r.Post("/permission", route.file.Permission)
+ r.Post("/compress", route.file.Compress)
+ r.Post("/unCompress", route.file.UnCompress)
+ r.Get("/search", route.file.Search)
+ r.Get("/list", route.file.List)
})
r.Route("/monitor", func(r chi.Router) {
- monitor := service.NewMonitorService()
- r.Get("/setting", monitor.GetSetting)
- r.Post("/setting", monitor.UpdateSetting)
- r.Post("/clear", monitor.Clear)
- r.Get("/list", monitor.List)
+ r.Get("/setting", route.monitor.GetSetting)
+ r.Post("/setting", route.monitor.UpdateSetting)
+ r.Post("/clear", route.monitor.Clear)
+ r.Get("/list", route.monitor.List)
})
r.Route("/setting", func(r chi.Router) {
- setting := service.NewSettingService()
- r.Get("/", setting.Get)
- r.Post("/", setting.Update)
+ r.Get("/", route.setting.Get)
+ r.Post("/", route.setting.Update)
})
r.Route("/systemctl", func(r chi.Router) {
- systemctl := service.NewSystemctlService()
- r.Get("/status", systemctl.Status)
- r.Get("/isEnabled", systemctl.IsEnabled)
- r.Post("/enable", systemctl.Enable)
- r.Post("/disable", systemctl.Disable)
- r.Post("/restart", systemctl.Restart)
- r.Post("/reload", systemctl.Reload)
- r.Post("/start", systemctl.Start)
- r.Post("/stop", systemctl.Stop)
+ r.Get("/status", route.systemctl.Status)
+ r.Get("/isEnabled", route.systemctl.IsEnabled)
+ r.Post("/enable", route.systemctl.Enable)
+ r.Post("/disable", route.systemctl.Disable)
+ r.Post("/restart", route.systemctl.Restart)
+ r.Post("/reload", route.systemctl.Reload)
+ r.Post("/start", route.systemctl.Start)
+ r.Post("/stop", route.systemctl.Stop)
})
r.Route("/apps", func(r chi.Router) {
diff --git a/internal/route/route.go b/internal/route/route.go
new file mode 100644
index 00000000..b639d4a0
--- /dev/null
+++ b/internal/route/route.go
@@ -0,0 +1,6 @@
+package route
+
+import "github.com/google/wire"
+
+// ProviderSet is route providers.
+var ProviderSet = wire.NewSet(NewCli, NewHttp, NewWs)
diff --git a/internal/route/ws.go b/internal/route/ws.go
index 6022a99b..4b1b53e7 100644
--- a/internal/route/ws.go
+++ b/internal/route/ws.go
@@ -3,15 +3,22 @@ package route
import (
"github.com/go-chi/chi/v5"
- "github.com/TheTNB/panel/internal/http/middleware"
"github.com/TheTNB/panel/internal/service"
)
-func Ws(r chi.Router) {
+type Ws struct {
+ ws *service.WsService
+}
+
+func NewWs(ws *service.WsService) *Ws {
+ return &Ws{
+ ws: ws,
+ }
+}
+
+func (route *Ws) Register(r *chi.Mux) {
r.Route("/api/ws", func(r chi.Router) {
- r.Use(middleware.MustLogin)
- ws := service.NewWsService()
- r.Get("/ssh", ws.Session)
- r.Get("/exec", ws.Exec)
+ r.Get("/ssh", route.ws.Session)
+ r.Get("/exec", route.ws.Exec)
})
}
diff --git a/internal/service/app.go b/internal/service/app.go
index d43e205a..88078b1d 100644
--- a/internal/service/app.go
+++ b/internal/service/app.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
)
@@ -17,11 +16,11 @@ type AppService struct {
settingRepo biz.SettingRepo
}
-func NewAppService() *AppService {
+func NewAppService(app biz.AppRepo, cache biz.CacheRepo, setting biz.SettingRepo) *AppService {
return &AppService{
- appRepo: data.NewAppRepo(),
- cacheRepo: data.NewCacheRepo(),
- settingRepo: data.NewSettingRepo(),
+ appRepo: app,
+ cacheRepo: cache,
+ settingRepo: setting,
}
}
diff --git a/internal/service/backup.go b/internal/service/backup.go
index fd5b5d46..07bddcef 100644
--- a/internal/service/backup.go
+++ b/internal/service/backup.go
@@ -9,7 +9,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/io"
)
@@ -18,9 +17,9 @@ type BackupService struct {
backupRepo biz.BackupRepo
}
-func NewBackupService() *BackupService {
+func NewBackupService(backup biz.BackupRepo) *BackupService {
return &BackupService{
- backupRepo: data.NewBackupRepo(),
+ backupRepo: backup,
}
}
diff --git a/internal/service/cert.go b/internal/service/cert.go
index 609b7249..f30d6e78 100644
--- a/internal/service/cert.go
+++ b/internal/service/cert.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/acme"
"github.com/TheTNB/panel/pkg/types"
@@ -16,9 +15,9 @@ type CertService struct {
certRepo biz.CertRepo
}
-func NewCertService() *CertService {
+func NewCertService(cert biz.CertRepo) *CertService {
return &CertService{
- certRepo: data.NewCertRepo(),
+ certRepo: cert,
}
}
diff --git a/internal/service/cert_account.go b/internal/service/cert_account.go
index 41a9ca33..88619a5a 100644
--- a/internal/service/cert_account.go
+++ b/internal/service/cert_account.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type CertAccountService struct {
certAccountRepo biz.CertAccountRepo
}
-func NewCertAccountService() *CertAccountService {
+func NewCertAccountService(certAccount biz.CertAccountRepo) *CertAccountService {
return &CertAccountService{
- certAccountRepo: data.NewCertAccountRepo(),
+ certAccountRepo: certAccount,
}
}
diff --git a/internal/service/cert_dns.go b/internal/service/cert_dns.go
index 43b8f16c..1ac92f61 100644
--- a/internal/service/cert_dns.go
+++ b/internal/service/cert_dns.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type CertDNSService struct {
certDNSRepo biz.CertDNSRepo
}
-func NewCertDNSService() *CertDNSService {
+func NewCertDNSService(certDNS biz.CertDNSRepo) *CertDNSService {
return &CertDNSService{
- certDNSRepo: data.NewCertDNSRepo(),
+ certDNSRepo: certDNS,
}
}
diff --git a/internal/service/cli.go b/internal/service/cli.go
index 5c1257c3..4557538e 100644
--- a/internal/service/cli.go
+++ b/internal/service/cli.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "github.com/knadh/koanf/v2"
"path/filepath"
"time"
@@ -17,7 +18,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/api"
"github.com/TheTNB/panel/pkg/cert"
@@ -33,6 +33,7 @@ import (
type CliService struct {
hr string
api *api.API
+ conf *koanf.Koanf
appRepo biz.AppRepo
cacheRepo biz.CacheRepo
userRepo biz.UserRepo
@@ -43,17 +44,18 @@ type CliService struct {
hash hash.Hasher
}
-func NewCliService() *CliService {
+func NewCliService(conf *koanf.Koanf, appRepo biz.AppRepo, cache biz.CacheRepo, user biz.UserRepo, setting biz.SettingRepo, backup biz.BackupRepo, website biz.WebsiteRepo, databaseServer biz.DatabaseServerRepo) *CliService {
return &CliService{
hr: `+----------------------------------------------------`,
api: api.NewAPI(app.Version),
- appRepo: data.NewAppRepo(),
- cacheRepo: data.NewCacheRepo(),
- userRepo: data.NewUserRepo(),
- settingRepo: data.NewSettingRepo(),
- backupRepo: data.NewBackupRepo(),
- websiteRepo: data.NewWebsiteRepo(),
- databaseServerRepo: data.NewDatabaseServerRepo(),
+ conf: conf,
+ appRepo: appRepo,
+ cacheRepo: cache,
+ userRepo: user,
+ settingRepo: setting,
+ backupRepo: backup,
+ websiteRepo: website,
+ databaseServerRepo: databaseServer,
hash: hash.NewArgon2id(),
}
}
@@ -97,7 +99,7 @@ func (s *CliService) Update(ctx context.Context, cmd *cli.Command) error {
}
ver, url, checksum := panel.Version, download.URL, download.Checksum
- return s.settingRepo.UpdatePanel(ver, url, checksum)
+ return s.backupRepo.UpdatePanel(ver, url, checksum)
}
func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error {
@@ -113,7 +115,7 @@ func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error {
}
func (s *CliService) Fix(ctx context.Context, cmd *cli.Command) error {
- return s.settingRepo.FixPanel()
+ return s.backupRepo.FixPanel()
}
func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error {
@@ -138,15 +140,15 @@ func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error {
}
protocol := "http"
- if app.Conf.Bool("http.tls") {
+ if s.conf.Bool("http.tls") {
protocol = "https"
}
- port := app.Conf.String("http.port")
+ port := s.conf.String("http.port")
if port == "" {
return fmt.Errorf("端口获取失败")
}
- entrance := app.Conf.String("http.entrance")
+ entrance := s.conf.String("http.entrance")
if entrance == "" {
return fmt.Errorf("入口获取失败")
}
@@ -831,8 +833,7 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
return fmt.Errorf("初始化失败:%v", err)
}
- user := data.NewUserRepo()
- _, err = user.Create("admin", value)
+ _, err = s.userRepo.Create("admin", value)
if err != nil {
return fmt.Errorf("初始化失败:%v", err)
}
diff --git a/internal/service/container.go b/internal/service/container.go
index ed5d651b..c11aefe1 100644
--- a/internal/service/container.go
+++ b/internal/service/container.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type ContainerService struct {
containerRepo biz.ContainerRepo
}
-func NewContainerService() *ContainerService {
+func NewContainerService(container biz.ContainerRepo) *ContainerService {
return &ContainerService{
- containerRepo: data.NewContainerRepo(),
+ containerRepo: container,
}
}
diff --git a/internal/service/container_image.go b/internal/service/container_image.go
index bf8f2c87..5daa33a3 100644
--- a/internal/service/container_image.go
+++ b/internal/service/container_image.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type ContainerImageService struct {
containerImageRepo biz.ContainerImageRepo
}
-func NewContainerImageService() *ContainerImageService {
+func NewContainerImageService(containerImage biz.ContainerImageRepo) *ContainerImageService {
return &ContainerImageService{
- containerImageRepo: data.NewContainerImageRepo(),
+ containerImageRepo: containerImage,
}
}
diff --git a/internal/service/container_network.go b/internal/service/container_network.go
index 867c1815..cbee3632 100644
--- a/internal/service/container_network.go
+++ b/internal/service/container_network.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type ContainerNetworkService struct {
containerNetworkRepo biz.ContainerNetworkRepo
}
-func NewContainerNetworkService() *ContainerNetworkService {
+func NewContainerNetworkService(containerNetwork biz.ContainerNetworkRepo) *ContainerNetworkService {
return &ContainerNetworkService{
- containerNetworkRepo: data.NewContainerNetworkRepo(),
+ containerNetworkRepo: containerNetwork,
}
}
diff --git a/internal/service/container_volume.go b/internal/service/container_volume.go
index d361b158..2493b727 100644
--- a/internal/service/container_volume.go
+++ b/internal/service/container_volume.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type ContainerVolumeService struct {
containerVolumeRepo biz.ContainerVolumeRepo
}
-func NewContainerVolumeService() *ContainerVolumeService {
+func NewContainerVolumeService(containerVolume biz.ContainerVolumeRepo) *ContainerVolumeService {
return &ContainerVolumeService{
- containerVolumeRepo: data.NewContainerVolumeRepo(),
+ containerVolumeRepo: containerVolume,
}
}
diff --git a/internal/service/cron.go b/internal/service/cron.go
index 835140ae..8a2be46a 100644
--- a/internal/service/cron.go
+++ b/internal/service/cron.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type CronService struct {
cronRepo biz.CronRepo
}
-func NewCronService() *CronService {
+func NewCronService(cron biz.CronRepo) *CronService {
return &CronService{
- cronRepo: data.NewCronRepo(),
+ cronRepo: cron,
}
}
diff --git a/internal/service/dashboard.go b/internal/service/dashboard.go
index bb02be89..a6bc5660 100644
--- a/internal/service/dashboard.go
+++ b/internal/service/dashboard.go
@@ -2,6 +2,7 @@ package service
import (
"fmt"
+ "github.com/knadh/koanf/v2"
"net"
"net/http"
"regexp"
@@ -16,7 +17,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/api"
"github.com/TheTNB/panel/pkg/db"
@@ -27,21 +27,25 @@ import (
type DashboardService struct {
api *api.API
+ conf *koanf.Koanf
taskRepo biz.TaskRepo
websiteRepo biz.WebsiteRepo
appRepo biz.AppRepo
settingRepo biz.SettingRepo
cronRepo biz.CronRepo
+ backupRepo biz.BackupRepo
}
-func NewDashboardService() *DashboardService {
+func NewDashboardService(conf *koanf.Koanf, task biz.TaskRepo, website biz.WebsiteRepo, appRepo biz.AppRepo, setting biz.SettingRepo, cron biz.CronRepo, backupRepo biz.BackupRepo) *DashboardService {
return &DashboardService{
api: api.NewAPI(app.Version),
- taskRepo: data.NewTaskRepo(),
- websiteRepo: data.NewWebsiteRepo(),
- appRepo: data.NewAppRepo(),
- settingRepo: data.NewSettingRepo(),
- cronRepo: data.NewCronRepo(),
+ conf: conf,
+ taskRepo: task,
+ websiteRepo: website,
+ appRepo: appRepo,
+ settingRepo: setting,
+ cronRepo: cron,
+ backupRepo: backupRepo,
}
}
@@ -53,7 +57,7 @@ func (s *DashboardService) Panel(w http.ResponseWriter, r *http.Request) {
Success(w, chix.M{
"name": name,
- "locale": app.Conf.MustString("app.locale"),
+ "locale": s.conf.String("app.locale"),
})
}
@@ -309,7 +313,7 @@ func (s *DashboardService) Update(w http.ResponseWriter, r *http.Request) {
ver, url, checksum := panel.Version, download.URL, download.Checksum
app.Status = app.StatusUpgrade
- if err = s.settingRepo.UpdatePanel(ver, url, checksum); err != nil {
+ if err = s.backupRepo.UpdatePanel(ver, url, checksum); err != nil {
app.Status = app.StatusFailed
Error(w, http.StatusInternalServerError, "%v", err)
return
diff --git a/internal/service/database.go b/internal/service/database.go
index 2c32c978..87dc6e21 100644
--- a/internal/service/database.go
+++ b/internal/service/database.go
@@ -6,21 +6,20 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
-type Database struct {
+type DatabaseService struct {
databaseRepo biz.DatabaseRepo
}
-func NewDatabaseService() *Database {
- return &Database{
- databaseRepo: data.NewDatabaseRepo(),
+func NewDatabaseService(database biz.DatabaseRepo) *DatabaseService {
+ return &DatabaseService{
+ databaseRepo: database,
}
}
-func (s *Database) List(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseService) List(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.Paginate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -39,7 +38,7 @@ func (s *Database) List(w http.ResponseWriter, r *http.Request) {
})
}
-func (s *Database) Create(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseService) Create(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseCreate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -54,7 +53,7 @@ func (s *Database) Create(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *Database) Delete(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseService) Delete(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseDelete](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -69,7 +68,7 @@ func (s *Database) Delete(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *Database) Comment(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseService) Comment(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseComment](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
diff --git a/internal/service/database_server.go b/internal/service/database_server.go
index 321ae4ef..abb529fb 100644
--- a/internal/service/database_server.go
+++ b/internal/service/database_server.go
@@ -6,21 +6,20 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
-type DatabaseServer struct {
+type DatabaseServerService struct {
databaseServerRepo biz.DatabaseServerRepo
}
-func NewDatabaseServerService() *DatabaseServer {
- return &DatabaseServer{
- databaseServerRepo: data.NewDatabaseServerRepo(),
+func NewDatabaseServerService(databaseServer biz.DatabaseServerRepo) *DatabaseServerService {
+ return &DatabaseServerService{
+ databaseServerRepo: databaseServer,
}
}
-func (s *DatabaseServer) List(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) List(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.Paginate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -39,7 +38,7 @@ func (s *DatabaseServer) List(w http.ResponseWriter, r *http.Request) {
})
}
-func (s *DatabaseServer) Create(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) Create(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseServerCreate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -54,7 +53,7 @@ func (s *DatabaseServer) Create(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseServer) Get(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) Get(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -70,7 +69,7 @@ func (s *DatabaseServer) Get(w http.ResponseWriter, r *http.Request) {
Success(w, server)
}
-func (s *DatabaseServer) Update(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) Update(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseServerUpdate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -85,7 +84,7 @@ func (s *DatabaseServer) Update(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseServer) UpdateRemark(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) UpdateRemark(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseServerUpdateRemark](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -100,7 +99,7 @@ func (s *DatabaseServer) UpdateRemark(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseServer) Delete(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) Delete(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -115,7 +114,7 @@ func (s *DatabaseServer) Delete(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseServer) Sync(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseServerService) Sync(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
diff --git a/internal/service/database_user.go b/internal/service/database_user.go
index c3665ad7..3bcdeebb 100644
--- a/internal/service/database_user.go
+++ b/internal/service/database_user.go
@@ -6,21 +6,20 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
-type DatabaseUser struct {
+type DatabaseUserService struct {
databaseUserRepo biz.DatabaseUserRepo
}
-func NewDatabaseUserService() *DatabaseUser {
- return &DatabaseUser{
- databaseUserRepo: data.NewDatabaseUserRepo(),
+func NewDatabaseUserService(databaseUser biz.DatabaseUserRepo) *DatabaseUserService {
+ return &DatabaseUserService{
+ databaseUserRepo: databaseUser,
}
}
-func (s *DatabaseUser) List(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) List(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.Paginate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -39,7 +38,7 @@ func (s *DatabaseUser) List(w http.ResponseWriter, r *http.Request) {
})
}
-func (s *DatabaseUser) Create(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) Create(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseUserCreate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -54,7 +53,7 @@ func (s *DatabaseUser) Create(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseUser) Get(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) Get(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -70,7 +69,7 @@ func (s *DatabaseUser) Get(w http.ResponseWriter, r *http.Request) {
Success(w, user)
}
-func (s *DatabaseUser) Update(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) Update(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseUserUpdate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -85,7 +84,7 @@ func (s *DatabaseUser) Update(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseUser) UpdateRemark(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) UpdateRemark(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.DatabaseUserUpdateRemark](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -100,7 +99,7 @@ func (s *DatabaseUser) UpdateRemark(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
-func (s *DatabaseUser) Delete(w http.ResponseWriter, r *http.Request) {
+func (s *DatabaseUserService) Delete(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
diff --git a/internal/service/file.go b/internal/service/file.go
index fdf5762d..dfbd018b 100644
--- a/internal/service/file.go
+++ b/internal/service/file.go
@@ -21,7 +21,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/os"
@@ -33,9 +32,9 @@ type FileService struct {
taskRepo biz.TaskRepo
}
-func NewFileService() *FileService {
+func NewFileService(task biz.TaskRepo) *FileService {
return &FileService{
- taskRepo: data.NewTaskRepo(),
+ taskRepo: task,
}
}
diff --git a/internal/service/file_windows.go b/internal/service/file_windows.go
index 835e2111..1045ae87 100644
--- a/internal/service/file_windows.go
+++ b/internal/service/file_windows.go
@@ -18,6 +18,7 @@ import (
"github.com/go-rat/chix"
"github.com/spf13/cast"
+ "github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
@@ -25,10 +26,13 @@ import (
)
type FileService struct {
+ taskRepo biz.TaskRepo
}
-func NewFileService() *FileService {
- return &FileService{}
+func NewFileService(task biz.TaskRepo) *FileService {
+ return &FileService{
+ taskRepo: task,
+ }
}
func (s *FileService) Create(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/service/monitor.go b/internal/service/monitor.go
index c7ee3b0b..e57c8d7d 100644
--- a/internal/service/monitor.go
+++ b/internal/service/monitor.go
@@ -6,7 +6,6 @@ import (
"time"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
)
@@ -16,10 +15,10 @@ type MonitorService struct {
monitorRepo biz.MonitorRepo
}
-func NewMonitorService() *MonitorService {
+func NewMonitorService(setting biz.SettingRepo, monitor biz.MonitorRepo) *MonitorService {
return &MonitorService{
- settingRepo: data.NewSettingRepo(),
- monitorRepo: data.NewMonitorRepo(),
+ settingRepo: setting,
+ monitorRepo: monitor,
}
}
diff --git a/internal/service/safe.go b/internal/service/safe.go
index bbc6692d..12726f3a 100644
--- a/internal/service/safe.go
+++ b/internal/service/safe.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type SafeService struct {
safeRepo biz.SafeRepo
}
-func NewSafeService() *SafeService {
+func NewSafeService(safe biz.SafeRepo) *SafeService {
return &SafeService{
- safeRepo: data.NewSafeRepo(),
+ safeRepo: safe,
}
}
diff --git a/internal/service/service.go b/internal/service/service.go
new file mode 100644
index 00000000..acb0d242
--- /dev/null
+++ b/internal/service/service.go
@@ -0,0 +1,34 @@
+package service
+
+import "github.com/google/wire"
+
+// ProviderSet is service providers.
+var ProviderSet = wire.NewSet(
+ NewAppService,
+ NewBackupService,
+ NewCertService,
+ NewCertAccountService,
+ NewCertDNSService,
+ NewCliService,
+ NewContainerService,
+ NewContainerImageService,
+ NewContainerNetworkService,
+ NewContainerVolumeService,
+ NewCronService,
+ NewDashboardService,
+ NewDatabaseService,
+ NewDatabaseServerService,
+ NewDatabaseUserService,
+ NewFileService,
+ NewFirewallService,
+ NewMonitorService,
+ NewProcessService,
+ NewSafeService,
+ NewSettingService,
+ NewSSHService,
+ NewSystemctlService,
+ NewTaskService,
+ NewUserService,
+ NewWebsiteService,
+ NewWsService,
+)
diff --git a/internal/service/setting.go b/internal/service/setting.go
index 4e4773e7..1580275b 100644
--- a/internal/service/setting.go
+++ b/internal/service/setting.go
@@ -4,7 +4,6 @@ import (
"net/http"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -13,9 +12,9 @@ type SettingService struct {
settingRepo biz.SettingRepo
}
-func NewSettingService() *SettingService {
+func NewSettingService(setting biz.SettingRepo) *SettingService {
return &SettingService{
- settingRepo: data.NewSettingRepo(),
+ settingRepo: setting,
}
}
diff --git a/internal/service/ssh.go b/internal/service/ssh.go
index e1bb12ac..ef3bfae0 100644
--- a/internal/service/ssh.go
+++ b/internal/service/ssh.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type SSHService struct {
sshRepo biz.SSHRepo
}
-func NewSSHService() *SSHService {
+func NewSSHService(ssh biz.SSHRepo) *SSHService {
return &SSHService{
- sshRepo: data.NewSSHRepo(),
+ sshRepo: ssh,
}
}
diff --git a/internal/service/task.go b/internal/service/task.go
index 3792ca47..36b449b1 100644
--- a/internal/service/task.go
+++ b/internal/service/task.go
@@ -6,7 +6,6 @@ import (
"github.com/go-rat/chix"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
)
@@ -14,9 +13,9 @@ type TaskService struct {
taskRepo biz.TaskRepo
}
-func NewTaskService() *TaskService {
+func NewTaskService(task biz.TaskRepo) *TaskService {
return &TaskService{
- taskRepo: data.NewTaskRepo(),
+ taskRepo: task,
}
}
diff --git a/internal/service/user.go b/internal/service/user.go
index 11ab9ce6..29020ecf 100644
--- a/internal/service/user.go
+++ b/internal/service/user.go
@@ -4,6 +4,8 @@ import (
"crypto/rsa"
"encoding/gob"
"fmt"
+ "github.com/go-rat/sessions"
+ "github.com/knadh/koanf/v2"
"net"
"net/http"
"strings"
@@ -12,21 +14,23 @@ import (
"github.com/spf13/cast"
"golang.org/x/crypto/sha3"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/rsacrypto"
)
type UserService struct {
- repo biz.UserRepo
+ conf *koanf.Koanf
+ session *sessions.Manager
+ userRepo biz.UserRepo
}
-func NewUserService() *UserService {
+func NewUserService(conf *koanf.Koanf, session *sessions.Manager, user biz.UserRepo) *UserService {
gob.Register(rsa.PrivateKey{}) // 必须注册 rsa.PrivateKey 类型否则无法反序列化 session 中的 key
return &UserService{
- repo: data.NewUserRepo(),
+ conf: conf,
+ session: session,
+ userRepo: user,
}
}
@@ -37,7 +41,7 @@ func (s *UserService) GetKey(w http.ResponseWriter, r *http.Request) {
return
}
- sess, err := app.Session.GetSession(r)
+ sess, err := s.session.GetSession(r)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -54,7 +58,7 @@ func (s *UserService) GetKey(w http.ResponseWriter, r *http.Request) {
}
func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
- sess, err := app.Session.GetSession(r)
+ sess, err := s.session.GetSession(r)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -74,7 +78,7 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
decryptedUsername, _ := rsacrypto.DecryptData(&key, req.Username)
decryptedPassword, _ := rsacrypto.DecryptData(&key, req.Password)
- user, err := s.repo.CheckPassword(string(decryptedUsername), string(decryptedPassword))
+ user, err := s.userRepo.CheckPassword(string(decryptedUsername), string(decryptedPassword))
if err != nil {
Error(w, http.StatusForbidden, "%v", err)
return
@@ -87,7 +91,7 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
- if req.SafeLogin && !app.Conf.Bool("http.tls") {
+ if req.SafeLogin && !s.conf.Bool("http.tls") {
sess.Put("safe_login", true)
sess.Put("safe_client", fmt.Sprintf("%x", sha3.Sum256([]byte(ip))))
}
@@ -98,7 +102,7 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
}
func (s *UserService) Logout(w http.ResponseWriter, r *http.Request) {
- sess, err := app.Session.GetSession(r)
+ sess, err := s.session.GetSession(r)
if err == nil {
if err = sess.Invalidate(); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
@@ -110,7 +114,7 @@ func (s *UserService) Logout(w http.ResponseWriter, r *http.Request) {
}
func (s *UserService) IsLogin(w http.ResponseWriter, r *http.Request) {
- sess, err := app.Session.GetSession(r)
+ sess, err := s.session.GetSession(r)
if err != nil {
Success(w, false)
return
@@ -125,7 +129,7 @@ func (s *UserService) Info(w http.ResponseWriter, r *http.Request) {
return
}
- user, err := s.repo.Get(userID)
+ user, err := s.userRepo.Get(userID)
if err != nil {
ErrorSystem(w)
return
diff --git a/internal/service/website.go b/internal/service/website.go
index 50909fc1..81278a56 100644
--- a/internal/service/website.go
+++ b/internal/service/website.go
@@ -8,7 +8,6 @@ import (
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/io"
)
@@ -18,10 +17,10 @@ type WebsiteService struct {
settingRepo biz.SettingRepo
}
-func NewWebsiteService() *WebsiteService {
+func NewWebsiteService(website biz.WebsiteRepo, setting biz.SettingRepo) *WebsiteService {
return &WebsiteService{
- websiteRepo: data.NewWebsiteRepo(),
- settingRepo: data.NewSettingRepo(),
+ websiteRepo: website,
+ settingRepo: setting,
}
}
diff --git a/internal/service/ws.go b/internal/service/ws.go
index 4cc413e0..de5e8785 100644
--- a/internal/service/ws.go
+++ b/internal/service/ws.go
@@ -3,26 +3,27 @@ package service
import (
"bufio"
"context"
+ "github.com/knadh/koanf/v2"
"net/http"
"sync"
"github.com/gorilla/websocket"
- "github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
- "github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/ssh"
)
type WsService struct {
+ conf *koanf.Koanf
sshRepo biz.SSHRepo
}
-func NewWsService() *WsService {
+func NewWsService(conf *koanf.Koanf, ssh biz.SSHRepo) *WsService {
return &WsService{
- sshRepo: data.NewSSHRepo(),
+ conf: conf,
+ sshRepo: ssh,
}
}
@@ -121,7 +122,7 @@ func (s *WsService) upgrade(w http.ResponseWriter, r *http.Request) (*websocket.
}
// debug 模式下不校验 origin,方便 vite 代理调试
- if app.Conf.Bool("app.debug") {
+ if s.conf.Bool("app.debug") {
upGrader.CheckOrigin = func(r *http.Request) bool {
return true
}