From a64660d0cb1b8320de9e7e1239c39e540fa939d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Mon, 16 Dec 2024 02:01:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BA=94=E7=94=A8=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=BE=9D=E8=B5=96=E6=B3=A8=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/cli/wire_gen.go | 6 +- cmd/web/wire.go | 3 +- cmd/web/wire_gen.go | 46 ++++- go.mod | 1 - go.sum | 3 - internal/app/global.go | 8 - internal/app/web.go | 84 ++------- internal/apps/apps.go | 170 ++++++++++++++++++ .../apps/benchmark/{service.go => app.go} | 60 ++++--- internal/apps/benchmark/init.go | 18 -- internal/apps/docker/{service.go => app.go} | 17 +- internal/apps/docker/init.go | 19 -- internal/apps/fail2ban/{service.go => app.go} | 33 ++-- internal/apps/fail2ban/init.go | 24 --- internal/apps/frp/{service.go => app.go} | 17 +- internal/apps/frp/init.go | 19 -- internal/apps/gitea/{service.go => app.go} | 17 +- internal/apps/gitea/init.go | 19 -- internal/apps/init.go | 29 --- .../apps/memcached/{service.go => app.go} | 20 ++- internal/apps/memcached/init.go | 20 --- internal/apps/mysql/{service.go => app.go} | 38 ++-- internal/apps/mysql/init.go | 25 --- internal/apps/nginx/{service.go => app.go} | 25 ++- internal/apps/nginx/init.go | 22 --- internal/apps/php/{service.go => app.go} | 61 ++++--- internal/apps/php/init.go | 35 ---- .../apps/phpmyadmin/{service.go => app.go} | 22 ++- internal/apps/phpmyadmin/init.go | 21 --- internal/apps/podman/{service.go => app.go} | 23 ++- internal/apps/podman/init.go | 21 --- .../apps/postgresql/{service.go => app.go} | 32 ++-- internal/apps/postgresql/init.go | 24 --- internal/apps/pureftpd/{service.go => app.go} | 28 ++- internal/apps/pureftpd/init.go | 23 --- internal/apps/redis/{service.go => app.go} | 20 ++- internal/apps/redis/init.go | 20 --- internal/apps/rsync/{service.go => app.go} | 28 ++- internal/apps/rsync/init.go | 23 --- internal/apps/s3fs/{service.go => app.go} | 21 ++- internal/apps/s3fs/init.go | 20 --- .../apps/supervisor/{service.go => app.go} | 52 ++++-- internal/apps/supervisor/init.go | 31 ---- internal/apps/toolbox/{service.go => app.go} | 49 +++-- internal/apps/toolbox/init.go | 30 ---- internal/biz/task.go | 1 - internal/bootstrap/http.go | 8 +- internal/data/cache.go | 5 +- internal/data/database.go | 14 +- internal/data/database_server.go | 3 +- internal/data/database_user.go | 31 ++-- internal/data/monitor.go | 5 +- internal/data/task.go | 29 --- internal/job/monitoring.go | 4 - internal/route/http.go | 5 +- internal/service/cli.go | 38 ++-- pkg/apploader/apploader.go | 54 ------ 57 files changed, 663 insertions(+), 861 deletions(-) create mode 100644 internal/apps/apps.go rename internal/apps/benchmark/{service.go => app.go} (89%) delete mode 100644 internal/apps/benchmark/init.go rename internal/apps/docker/{service.go => app.go} (70%) delete mode 100644 internal/apps/docker/init.go rename internal/apps/fail2ban/{service.go => app.go} (91%) delete mode 100644 internal/apps/fail2ban/init.go rename internal/apps/frp/{service.go => app.go} (75%) delete mode 100644 internal/apps/frp/init.go rename internal/apps/gitea/{service.go => app.go} (70%) delete mode 100644 internal/apps/gitea/init.go delete mode 100644 internal/apps/init.go rename internal/apps/memcached/{service.go => app.go} (82%) delete mode 100644 internal/apps/memcached/init.go rename internal/apps/mysql/{service.go => app.go} (86%) delete mode 100644 internal/apps/mysql/init.go rename internal/apps/nginx/{service.go => app.go} (84%) delete mode 100644 internal/apps/nginx/init.go rename internal/apps/php/{service.go => app.go} (86%) delete mode 100644 internal/apps/php/init.go rename internal/apps/phpmyadmin/{service.go => app.go} (85%) delete mode 100644 internal/apps/phpmyadmin/init.go rename internal/apps/podman/{service.go => app.go} (70%) delete mode 100644 internal/apps/podman/init.go rename internal/apps/postgresql/{service.go => app.go} (83%) delete mode 100644 internal/apps/postgresql/init.go rename internal/apps/pureftpd/{service.go => app.go} (85%) delete mode 100644 internal/apps/pureftpd/init.go rename internal/apps/redis/{service.go => app.go} (86%) delete mode 100644 internal/apps/redis/init.go rename internal/apps/rsync/{service.go => app.go} (90%) delete mode 100644 internal/apps/rsync/init.go rename internal/apps/s3fs/{service.go => app.go} (92%) delete mode 100644 internal/apps/s3fs/init.go rename internal/apps/supervisor/{service.go => app.go} (83%) delete mode 100644 internal/apps/supervisor/init.go rename internal/apps/toolbox/{service.go => app.go} (84%) delete mode 100644 internal/apps/toolbox/init.go delete mode 100644 pkg/apploader/apploader.go diff --git a/cmd/cli/wire_gen.go b/cmd/cli/wire_gen.go index bc04080368..55201ccc25 100644 --- a/cmd/cli/wire_gen.go +++ b/cmd/cli/wire_gen.go @@ -38,13 +38,13 @@ func initCli() (*app.Cli, error) { userRepo := data.NewUserRepo(db) settingRepo := data.NewSettingRepo(db, koanf, taskRepo) databaseServerRepo := data.NewDatabaseServerRepo(db, logger) - databaseUserRepo := data.NewDatabaseUserRepo(databaseServerRepo) - databaseRepo := data.NewDatabaseRepo(databaseServerRepo, databaseUserRepo) + databaseUserRepo := data.NewDatabaseUserRepo(db, databaseServerRepo) + databaseRepo := data.NewDatabaseRepo(db, 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) + cliService := service.NewCliService(koanf, db, appRepo, cacheRepo, userRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo) cli := route.NewCli(cliService) command := bootstrap.NewCli(cli) appCli := app.NewCli(command) diff --git a/cmd/web/wire.go b/cmd/web/wire.go index 71c58776a1..0bc1bd854f 100644 --- a/cmd/web/wire.go +++ b/cmd/web/wire.go @@ -6,6 +6,7 @@ import ( "github.com/google/wire" "github.com/TheTNB/panel/internal/app" + "github.com/TheTNB/panel/internal/apps" "github.com/TheTNB/panel/internal/bootstrap" "github.com/TheTNB/panel/internal/data" "github.com/TheTNB/panel/internal/http/middleware" @@ -16,5 +17,5 @@ import ( // initWeb init application. func initWeb() (*app.Web, error) { - panic(wire.Build(bootstrap.ProviderSet, middleware.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, job.ProviderSet, app.NewWeb)) + panic(wire.Build(bootstrap.ProviderSet, middleware.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, job.ProviderSet, app.NewWeb)) } diff --git a/cmd/web/wire_gen.go b/cmd/web/wire_gen.go index 3023d0b497..2487566358 100644 --- a/cmd/web/wire_gen.go +++ b/cmd/web/wire_gen.go @@ -8,6 +8,25 @@ package main import ( "github.com/TheTNB/panel/internal/app" + "github.com/TheTNB/panel/internal/apps" + "github.com/TheTNB/panel/internal/apps/benchmark" + "github.com/TheTNB/panel/internal/apps/docker" + "github.com/TheTNB/panel/internal/apps/fail2ban" + "github.com/TheTNB/panel/internal/apps/frp" + "github.com/TheTNB/panel/internal/apps/gitea" + "github.com/TheTNB/panel/internal/apps/memcached" + "github.com/TheTNB/panel/internal/apps/mysql" + "github.com/TheTNB/panel/internal/apps/nginx" + "github.com/TheTNB/panel/internal/apps/php" + "github.com/TheTNB/panel/internal/apps/phpmyadmin" + "github.com/TheTNB/panel/internal/apps/podman" + "github.com/TheTNB/panel/internal/apps/postgresql" + "github.com/TheTNB/panel/internal/apps/pureftpd" + "github.com/TheTNB/panel/internal/apps/redis" + "github.com/TheTNB/panel/internal/apps/rsync" + "github.com/TheTNB/panel/internal/apps/s3fs" + "github.com/TheTNB/panel/internal/apps/supervisor" + "github.com/TheTNB/panel/internal/apps/toolbox" "github.com/TheTNB/panel/internal/bootstrap" "github.com/TheTNB/panel/internal/data" "github.com/TheTNB/panel/internal/http/middleware" @@ -45,8 +64,8 @@ func initWeb() (*app.Web, error) { userRepo := data.NewUserRepo(db) userService := service.NewUserService(koanf, manager, userRepo) databaseServerRepo := data.NewDatabaseServerRepo(db, logger) - databaseUserRepo := data.NewDatabaseUserRepo(databaseServerRepo) - databaseRepo := data.NewDatabaseRepo(databaseServerRepo, databaseUserRepo) + databaseUserRepo := data.NewDatabaseUserRepo(db, databaseServerRepo) + databaseRepo := data.NewDatabaseRepo(db, databaseServerRepo, databaseUserRepo) certRepo := data.NewCertRepo(db) certAccountRepo := data.NewCertAccountRepo(db, userRepo) websiteRepo := data.NewWebsiteRepo(db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo) @@ -85,10 +104,29 @@ func initWeb() (*app.Web, error) { 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) + benchmarkApp := benchmark.NewApp() + dockerApp := docker.NewApp() + fail2banApp := fail2ban.NewApp(websiteRepo) + frpApp := frp.NewApp() + giteaApp := gitea.NewApp() + memcachedApp := memcached.NewApp() + mysqlApp := mysql.NewApp(settingRepo) + nginxApp := nginx.NewApp() + phpApp := php.NewApp(taskRepo) + phpmyadminApp := phpmyadmin.NewApp() + podmanApp := podman.NewApp() + postgresqlApp := postgresql.NewApp() + pureftpdApp := pureftpd.NewApp() + redisApp := redis.NewApp() + rsyncApp := rsync.NewApp() + s3fsApp := s3fs.NewApp(settingRepo) + supervisorApp := supervisor.NewApp() + toolboxApp := toolbox.NewApp() + loader := apps.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, phpApp, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp) + 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, loader) wsService := service.NewWsService(koanf, sshRepo) ws := route.NewWs(wsService) - mux, err := bootstrap.NewRouter(koanf, db, logger, manager, middlewares, http, ws) + mux, err := bootstrap.NewRouter(middlewares, http, ws) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index b8e7d4eb72..9aac04a15f 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ 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 diff --git a/go.sum b/go.sum index 8f82a93bf0..58a981b937 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ 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= @@ -190,7 +188,6 @@ 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= diff --git a/internal/app/global.go b/internal/app/global.go index 70d54cbe1e..5f8e35ff82 100644 --- a/internal/app/global.go +++ b/internal/app/global.go @@ -1,13 +1,5 @@ package app -import ( - "gorm.io/gorm" -) - -var ( - Orm *gorm.DB -) - // 面板状态常量 const ( StatusNormal = iota diff --git a/internal/app/web.go b/internal/app/web.go index 80d76a4be4..4d0da6e865 100644 --- a/internal/app/web.go +++ b/internal/app/web.go @@ -1,19 +1,12 @@ package app import ( - "context" "errors" "fmt" - "log" "net/http" - "os" - "os/signal" - "runtime" - "syscall" - "time" + "path/filepath" "github.com/bddjr/hlfhr" - "github.com/cloudflare/tableflip" "github.com/go-chi/chi/v5" "github.com/go-gormigrate/gormigrate/v2" "github.com/gookit/validate" @@ -51,73 +44,18 @@ func (r *Web) Run() error { 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) - } + if r.conf.Bool("http.tls") { + cert := filepath.Join(Root, "panel/storage/cert.pem") + key := filepath.Join(Root, "panel/storage/cert.key") + fmt.Println("[HTTP] listening and serving on port", r.conf.MustInt("http.port"), "with tls") + if err := r.server.ListenAndServeTLS(cert, key); !errors.Is(err, http.ErrServerClosed) { + return 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) + } else { + fmt.Println("[HTTP] listening and serving on port", r.conf.MustInt("http.port")) + if err := r.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { + return 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/apps.go b/internal/apps/apps.go new file mode 100644 index 0000000000..a98f553ea0 --- /dev/null +++ b/internal/apps/apps.go @@ -0,0 +1,170 @@ +package apps + +import ( + "reflect" + "slices" + "strings" + + "github.com/go-chi/chi/v5" + "github.com/google/wire" + + "github.com/TheTNB/panel/internal/apps/benchmark" + "github.com/TheTNB/panel/internal/apps/docker" + "github.com/TheTNB/panel/internal/apps/fail2ban" + "github.com/TheTNB/panel/internal/apps/frp" + "github.com/TheTNB/panel/internal/apps/gitea" + "github.com/TheTNB/panel/internal/apps/memcached" + "github.com/TheTNB/panel/internal/apps/mysql" + "github.com/TheTNB/panel/internal/apps/nginx" + "github.com/TheTNB/panel/internal/apps/php" + "github.com/TheTNB/panel/internal/apps/phpmyadmin" + "github.com/TheTNB/panel/internal/apps/podman" + "github.com/TheTNB/panel/internal/apps/postgresql" + "github.com/TheTNB/panel/internal/apps/pureftpd" + "github.com/TheTNB/panel/internal/apps/redis" + "github.com/TheTNB/panel/internal/apps/rsync" + "github.com/TheTNB/panel/internal/apps/s3fs" + "github.com/TheTNB/panel/internal/apps/supervisor" + "github.com/TheTNB/panel/internal/apps/toolbox" +) + +var ProviderSet = wire.NewSet( + NewLoader, + benchmark.NewApp, + docker.NewApp, + fail2ban.NewApp, + frp.NewApp, + gitea.NewApp, + memcached.NewApp, + mysql.NewApp, + nginx.NewApp, + php.NewApp, + phpmyadmin.NewApp, + podman.NewApp, + postgresql.NewApp, + pureftpd.NewApp, + redis.NewApp, + rsync.NewApp, + s3fs.NewApp, + supervisor.NewApp, + toolbox.NewApp, +) + +var slugs []string + +type Loader struct { + benchmark *benchmark.App + docker *docker.App + fail2ban *fail2ban.App + frp *frp.App + gitea *gitea.App + memcached *memcached.App + mysql *mysql.App + nginx *nginx.App + php *php.App + phpmyadmin *phpmyadmin.App + podman *podman.App + postgresql *postgresql.App + pureftpd *pureftpd.App + redis *redis.App + rsync *rsync.App + s3fs *s3fs.App + supervisor *supervisor.App + toolbox *toolbox.App +} + +func NewLoader( + benchmark *benchmark.App, + docker *docker.App, + fail2ban *fail2ban.App, + frp *frp.App, + gitea *gitea.App, + memcached *memcached.App, + mysql *mysql.App, + nginx *nginx.App, + php *php.App, + phpmyadmin *phpmyadmin.App, + podman *podman.App, + postgresql *postgresql.App, + pureftpd *pureftpd.App, + redis *redis.App, + rsync *rsync.App, + s3fs *s3fs.App, + supervisor *supervisor.App, + toolbox *toolbox.App, +) *Loader { + loader := &Loader{ + benchmark: benchmark, + docker: docker, + fail2ban: fail2ban, + frp: frp, + gitea: gitea, + memcached: memcached, + mysql: mysql, + nginx: nginx, + php: php, + phpmyadmin: phpmyadmin, + podman: podman, + postgresql: postgresql, + pureftpd: pureftpd, + redis: redis, + rsync: rsync, + s3fs: s3fs, + supervisor: supervisor, + toolbox: toolbox, + } + + loader.initSlugs() + return loader +} + +func (r *Loader) Register(mux chi.Router) { + mux.Route("/benchmark", r.benchmark.Route) + mux.Route("/docker", r.docker.Route) + mux.Route("/fail2ban", r.fail2ban.Route) + mux.Route("/frp", r.frp.Route) + mux.Route("/gitea", r.gitea.Route) + mux.Route("/memcached", r.memcached.Route) + mux.Route("/mysql", r.mysql.Route) + mux.Route("/nginx", r.nginx.Route) + mux.Route("/php74", r.php.Route(74)) + mux.Route("/php80", r.php.Route(80)) + mux.Route("/php81", r.php.Route(81)) + mux.Route("/php82", r.php.Route(82)) + mux.Route("/php83", r.php.Route(83)) + mux.Route("/php84", r.php.Route(84)) + mux.Route("/phpmyadmin", r.phpmyadmin.Route) + mux.Route("/podman", r.podman.Route) + mux.Route("/postgresql", r.postgresql.Route) + mux.Route("/pureftpd", r.pureftpd.Route) + mux.Route("/redis", r.redis.Route) + mux.Route("/rsync", r.rsync.Route) + mux.Route("/s3fs", r.s3fs.Route) + mux.Route("/supervisor", r.supervisor.Route) + mux.Route("/toolbox", r.toolbox.Route) +} + +func (r *Loader) initSlugs() []string { + if len(slugs) == 0 { + v := reflect.Indirect(reflect.ValueOf(r)) + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + slug := strings.ToLower(v.Type().Field(i).Name) + if !field.IsNil() { + slugs = append(slugs, slug) + } + } + + // 处理php + slugs = slices.DeleteFunc(slugs, func(slug string) bool { + return slug == "php" + }) + slugs = append(slugs, "php74", "php80", "php81", "php82", "php83", "php84") + } + + return slugs +} + +func Slugs() []string { + return slugs +} diff --git a/internal/apps/benchmark/service.go b/internal/apps/benchmark/app.go similarity index 89% rename from internal/apps/benchmark/service.go rename to internal/apps/benchmark/app.go index a5ac32afd9..fa82f07a66 100644 --- a/internal/apps/benchmark/service.go +++ b/internal/apps/benchmark/app.go @@ -21,18 +21,24 @@ import ( "sync" "time" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/service" ) -type Service struct { +type App struct { +} + +func NewApp() *App { + return &App{} } -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Post("/test", s.Test) } // Test 运行测试 -func (s *Service) Test(w http.ResponseWriter, r *http.Request) { +func (s *App) Test(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Test](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -73,7 +79,7 @@ func (s *Service) Test(w http.ResponseWriter, r *http.Request) { } // calculateCpuScore 计算CPU成绩 -func (s *Service) calculateCpuScore(duration time.Duration) int { +func (s *App) calculateCpuScore(duration time.Duration) int { score := int((10 / duration.Seconds()) * float64(3000)) if score < 0 { @@ -83,7 +89,7 @@ func (s *Service) calculateCpuScore(duration time.Duration) int { } // calculateScore 计算内存/硬盘成绩 -func (s *Service) calculateScore(duration time.Duration) int { +func (s *App) calculateScore(duration time.Duration) int { score := int((20 / duration.Seconds()) * float64(30000)) if score < 0 { @@ -94,7 +100,7 @@ func (s *Service) calculateScore(duration time.Duration) int { // 图像处理 -func (s *Service) imageProcessing(multi bool) int { +func (s *App) imageProcessing(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -107,7 +113,7 @@ func (s *Service) imageProcessing(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) imageProcessingTask(numThreads int) error { +func (s *App) imageProcessingTask(numThreads int) error { img := image.NewRGBA(image.Rect(0, 0, 4000, 4000)) for x := 0; x < 4000; x++ { for y := 0; y < 4000; y++ { @@ -156,7 +162,7 @@ func (s *Service) imageProcessingTask(numThreads int) error { // 机器学习(矩阵乘法) -func (s *Service) machineLearning(multi bool) int { +func (s *App) machineLearning(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -167,7 +173,7 @@ func (s *Service) machineLearning(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) machineLearningTask(numThreads int) { +func (s *App) machineLearningTask(numThreads int) { size := 900 a := make([][]float64, size) b := make([][]float64, size) @@ -214,7 +220,7 @@ func (s *Service) machineLearningTask(numThreads int) { // 数学问题(计算斐波那契数) -func (s *Service) compileSimulationSingle(multi bool) int { +func (s *App) compileSimulationSingle(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -248,7 +254,7 @@ func (s *Service) compileSimulationSingle(multi bool) int { } // 斐波那契函数 -func (s *Service) fib(n int) *big.Int { +func (s *App) fib(n int) *big.Int { if n < 2 { return big.NewInt(int64(n)) } @@ -265,7 +271,7 @@ func (s *Service) fib(n int) *big.Int { // AES加密 -func (s *Service) encryptionTest(multi bool) int { +func (s *App) encryptionTest(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -278,7 +284,7 @@ func (s *Service) encryptionTest(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) encryptionTestTask(numThreads int) error { +func (s *App) encryptionTestTask(numThreads int) error { key := []byte("abcdefghijklmnopqrstuvwxyz123456") dataSize := 1 * 1024 * 1024 * 1024 // 1GB plaintext := []byte(strings.Repeat("A", dataSize)) @@ -320,7 +326,7 @@ func (s *Service) encryptionTestTask(numThreads int) error { // 压缩/解压缩 -func (s *Service) compressionTest(multi bool) int { +func (s *App) compressionTest(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -331,7 +337,7 @@ func (s *Service) compressionTest(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) compressionTestTask(numThreads int) { +func (s *App) compressionTestTask(numThreads int) { data := []byte(strings.Repeat("耗子面板", 50000000)) chunkSize := len(data) / numThreads @@ -381,7 +387,7 @@ func (s *Service) compressionTestTask(numThreads int) { // 物理仿真(N体问题) -func (s *Service) physicsSimulation(multi bool) int { +func (s *App) physicsSimulation(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -392,7 +398,7 @@ func (s *Service) physicsSimulation(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) physicsSimulationTask(numThreads int) { +func (s *App) physicsSimulationTask(numThreads int) { const ( numBodies = 4000 steps = 30 @@ -479,7 +485,7 @@ func (s *Service) physicsSimulationTask(numThreads int) { // JSON解析 -func (s *Service) jsonProcessing(multi bool) int { +func (s *App) jsonProcessing(multi bool) int { n := 1 if multi { n = runtime.NumCPU() @@ -490,7 +496,7 @@ func (s *Service) jsonProcessing(multi bool) int { return s.calculateCpuScore(duration) } -func (s *Service) jsonProcessingTask(numThreads int) { +func (s *App) jsonProcessingTask(numThreads int) { numElements := 1000000 elementsPerThread := numElements / numThreads @@ -531,7 +537,7 @@ func (s *Service) jsonProcessingTask(numThreads int) { // 内存性能 -func (s *Service) memoryTestTask() map[string]any { +func (s *App) memoryTestTask() map[string]any { results := make(map[string]any) dataSize := 500 * 1024 * 1024 // 500 MB data := make([]byte, dataSize) @@ -549,7 +555,7 @@ func (s *Service) memoryTestTask() map[string]any { return results } -func (s *Service) memoryBandwidthTest(data []byte) string { +func (s *App) memoryBandwidthTest(data []byte) string { dataSize := len(data) startTime := time.Now() @@ -566,7 +572,7 @@ func (s *Service) memoryBandwidthTest(data []byte) string { return fmt.Sprintf("%.2f MB/s", speed) } -func (s *Service) memoryLatencyTest(data []byte) string { +func (s *App) memoryLatencyTest(data []byte) string { dataSize := len(data) indices := rand.Perm(dataSize) @@ -585,7 +591,7 @@ func (s *Service) memoryLatencyTest(data []byte) string { // 硬盘IO -func (s *Service) diskTestTask() map[string]any { +func (s *App) diskTestTask() map[string]any { results := make(map[string]any) blockSizes := []int64{4 * 1024, 64 * 1024, 512 * 1024, 1 * 1024 * 1024} // 4K, 64K, 512K, 1M fileSize := int64(100 * 1024 * 1024) // 100MB 文件 @@ -601,7 +607,7 @@ func (s *Service) diskTestTask() map[string]any { return results } -func (s *Service) diskIOTest(blockSize int64, fileSize int64) map[string]any { +func (s *App) diskIOTest(blockSize int64, fileSize int64) map[string]any { result := make(map[string]any) tempFile := fmt.Sprintf("tempfile_%d", blockSize) defer os.Remove(tempFile) @@ -619,7 +625,7 @@ func (s *Service) diskIOTest(blockSize int64, fileSize int64) map[string]any { return result } -func (s *Service) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) { +func (s *App) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) { totalBlocks := fileSize / blockSize data := make([]byte, blockSize) @@ -653,7 +659,7 @@ func (s *Service) diskWriteTest(fileName string, blockSize int64, fileSize int64 return speed, iops } -func (s *Service) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) { +func (s *App) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) { totalBlocks := fileSize / blockSize data := make([]byte, blockSize) diff --git a/internal/apps/benchmark/init.go b/internal/apps/benchmark/init.go deleted file mode 100644 index 46d98a4785..0000000000 --- a/internal/apps/benchmark/init.go +++ /dev/null @@ -1,18 +0,0 @@ -package benchmark - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "benchmark", - Route: func(r chi.Router) { - service := NewService() - r.Post("/test", service.Test) - }, - }) -} diff --git a/internal/apps/docker/service.go b/internal/apps/docker/app.go similarity index 70% rename from internal/apps/docker/service.go rename to internal/apps/docker/app.go index ce3121a8cd..c102e2e711 100644 --- a/internal/apps/docker/service.go +++ b/internal/apps/docker/app.go @@ -3,18 +3,25 @@ package docker import ( "net/http" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/docker/daemon.json") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -24,7 +31,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/docker/init.go b/internal/apps/docker/init.go deleted file mode 100644 index 6b04d9d92c..0000000000 --- a/internal/apps/docker/init.go +++ /dev/null @@ -1,19 +0,0 @@ -package docker - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "docker", - Route: func(r chi.Router) { - service := NewService() - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/fail2ban/service.go b/internal/apps/fail2ban/app.go similarity index 91% rename from internal/apps/fail2ban/service.go rename to internal/apps/fail2ban/app.go index b439a1e8f3..2e1eaa43f5 100644 --- a/internal/apps/fail2ban/service.go +++ b/internal/apps/fail2ban/app.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/go-rat/utils/str" "github.com/spf13/cast" @@ -17,18 +18,28 @@ import ( "github.com/TheTNB/panel/pkg/shell" ) -type Service struct { +type App struct { websiteRepo biz.WebsiteRepo } -func NewService() *Service { - return &Service{ - websiteRepo: nil, // TODO fixme +func NewApp(website biz.WebsiteRepo) *App { + return &App{ + websiteRepo: website, } } +func (s *App) Route(r chi.Router) { + r.Get("/jails", s.List) + r.Post("/jails", s.Create) + r.Delete("/jails", s.Delete) + r.Get("/jails/{name}", s.BanList) + r.Post("/unban", s.Unban) + r.Post("/whiteList", s.SetWhiteList) + r.Get("/whiteList", s.GetWhiteList) +} + // List 所有规则 -func (s *Service) List(w http.ResponseWriter, r *http.Request) { +func (s *App) List(w http.ResponseWriter, r *http.Request) { raw, err := io.Read("/etc/fail2ban/jail.local") if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -75,7 +86,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { } // Create 添加规则 -func (s *Service) Create(w http.ResponseWriter, r *http.Request) { +func (s *App) Create(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Add](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -202,7 +213,7 @@ bantime = ` + jailBanTime + ` } // Delete 删除规则 -func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { +func (s *App) Delete(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Delete](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -236,7 +247,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { } // BanList 获取封禁列表 -func (s *Service) BanList(w http.ResponseWriter, r *http.Request) { +func (s *App) BanList(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[BanList](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -281,7 +292,7 @@ func (s *Service) BanList(w http.ResponseWriter, r *http.Request) { } // Unban 解封 -func (s *Service) Unban(w http.ResponseWriter, r *http.Request) { +func (s *App) Unban(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Unban](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -297,7 +308,7 @@ func (s *Service) Unban(w http.ResponseWriter, r *http.Request) { } // SetWhiteList 设置白名单 -func (s *Service) SetWhiteList(w http.ResponseWriter, r *http.Request) { +func (s *App) SetWhiteList(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[SetWhiteList](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -331,7 +342,7 @@ func (s *Service) SetWhiteList(w http.ResponseWriter, r *http.Request) { } // GetWhiteList 获取白名单 -func (s *Service) GetWhiteList(w http.ResponseWriter, r *http.Request) { +func (s *App) GetWhiteList(w http.ResponseWriter, r *http.Request) { raw, err := io.Read("/etc/fail2ban/jail.local") if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/fail2ban/init.go b/internal/apps/fail2ban/init.go deleted file mode 100644 index 65902c2fcb..0000000000 --- a/internal/apps/fail2ban/init.go +++ /dev/null @@ -1,24 +0,0 @@ -package fail2ban - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "fail2ban", - Route: func(r chi.Router) { - service := NewService() - r.Get("/jails", service.List) - r.Post("/jails", service.Create) - r.Delete("/jails", service.Delete) - r.Get("/jails/{name}", service.BanList) - r.Post("/unban", service.Unban) - r.Post("/whiteList", service.SetWhiteList) - r.Get("/whiteList", service.GetWhiteList) - }, - }) -} diff --git a/internal/apps/frp/service.go b/internal/apps/frp/app.go similarity index 75% rename from internal/apps/frp/service.go rename to internal/apps/frp/app.go index 748fd24821..147d77555d 100644 --- a/internal/apps/frp/service.go +++ b/internal/apps/frp/app.go @@ -4,19 +4,26 @@ import ( "fmt" "net/http" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Name](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -32,7 +39,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/frp/init.go b/internal/apps/frp/init.go deleted file mode 100644 index 9ce0cef0be..0000000000 --- a/internal/apps/frp/init.go +++ /dev/null @@ -1,19 +0,0 @@ -package frp - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "frp", - Route: func(r chi.Router) { - service := NewService() - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/gitea/service.go b/internal/apps/gitea/app.go similarity index 70% rename from internal/apps/gitea/service.go rename to internal/apps/gitea/app.go index 07a17e3aad..8a0bb81669 100644 --- a/internal/apps/gitea/service.go +++ b/internal/apps/gitea/app.go @@ -4,24 +4,31 @@ import ( "fmt" "net/http" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, _ := io.Read(fmt.Sprintf("%s/server/gitea/app.ini", app.Root)) service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/gitea/init.go b/internal/apps/gitea/init.go deleted file mode 100644 index ab8fb10df4..0000000000 --- a/internal/apps/gitea/init.go +++ /dev/null @@ -1,19 +0,0 @@ -package gitea - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "gitea", - Route: func(r chi.Router) { - service := NewService() - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/init.go b/internal/apps/init.go deleted file mode 100644 index f9cca706ad..0000000000 --- a/internal/apps/init.go +++ /dev/null @@ -1,29 +0,0 @@ -package apps - -import ( - "github.com/go-chi/chi/v5" - - _ "github.com/TheTNB/panel/internal/apps/benchmark" - _ "github.com/TheTNB/panel/internal/apps/docker" - _ "github.com/TheTNB/panel/internal/apps/fail2ban" - _ "github.com/TheTNB/panel/internal/apps/frp" - _ "github.com/TheTNB/panel/internal/apps/gitea" - _ "github.com/TheTNB/panel/internal/apps/memcached" - _ "github.com/TheTNB/panel/internal/apps/mysql" - _ "github.com/TheTNB/panel/internal/apps/nginx" - _ "github.com/TheTNB/panel/internal/apps/php" - _ "github.com/TheTNB/panel/internal/apps/phpmyadmin" - _ "github.com/TheTNB/panel/internal/apps/podman" - _ "github.com/TheTNB/panel/internal/apps/postgresql" - _ "github.com/TheTNB/panel/internal/apps/pureftpd" - _ "github.com/TheTNB/panel/internal/apps/redis" - _ "github.com/TheTNB/panel/internal/apps/rsync" - _ "github.com/TheTNB/panel/internal/apps/s3fs" - _ "github.com/TheTNB/panel/internal/apps/supervisor" - _ "github.com/TheTNB/panel/internal/apps/toolbox" - "github.com/TheTNB/panel/pkg/apploader" -) - -func Boot(r chi.Router) { - apploader.Boot(r) -} diff --git a/internal/apps/memcached/service.go b/internal/apps/memcached/app.go similarity index 82% rename from internal/apps/memcached/service.go rename to internal/apps/memcached/app.go index 02929425c9..1ff54dd684 100644 --- a/internal/apps/memcached/service.go +++ b/internal/apps/memcached/app.go @@ -6,19 +6,27 @@ import ( "net/http" "regexp" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/systemctl" "github.com/TheTNB/panel/pkg/types" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/load", s.Load) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) } -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { status, err := systemctl.Status("memcached") if err != nil { service.Error(w, http.StatusInternalServerError, "failed to get Memcached status: %v", err) @@ -66,7 +74,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { service.Success(w, data) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/systemd/system/memcached.service") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -76,7 +84,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/memcached/init.go b/internal/apps/memcached/init.go deleted file mode 100644 index dc1ecc06fa..0000000000 --- a/internal/apps/memcached/init.go +++ /dev/null @@ -1,20 +0,0 @@ -package memcached - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "memcached", - Route: func(r chi.Router) { - service := NewService() - r.Get("/load", service.Load) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/mysql/service.go b/internal/apps/mysql/app.go similarity index 86% rename from internal/apps/mysql/service.go rename to internal/apps/mysql/app.go index e46a21b3f0..be340819c3 100644 --- a/internal/apps/mysql/service.go +++ b/internal/apps/mysql/app.go @@ -6,6 +6,7 @@ import ( "os" "regexp" + "github.com/go-chi/chi/v5" "github.com/spf13/cast" "github.com/TheTNB/panel/internal/app" @@ -19,18 +20,29 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct { +type App struct { settingRepo biz.SettingRepo } -func NewService() *Service { - return &Service{ - settingRepo: nil, // TODO fixme +func NewApp(setting biz.SettingRepo) *App { + return &App{ + settingRepo: setting, } } +func (s *App) Route(r chi.Router) { + r.Get("/load", s.Load) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) + r.Post("/clearErrorLog", s.ClearErrorLog) + r.Get("/slowLog", s.SlowLog) + r.Post("/clearSlowLog", s.ClearSlowLog) + r.Get("/rootPassword", s.GetRootPassword) + r.Post("/rootPassword", s.SetRootPassword) +} + // GetConfig 获取配置 -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(app.Root + "/server/mysql/conf/my.cnf") if err != nil { service.Error(w, http.StatusInternalServerError, "获取配置失败") @@ -41,7 +53,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { } // UpdateConfig 保存配置 -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -62,7 +74,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { } // Load 获取负载 -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { rootPassword, err := s.settingRepo.Get(biz.SettingKeyMySQLRootPassword) if err != nil { service.Error(w, http.StatusInternalServerError, "获取root密码失败") @@ -142,7 +154,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { } // ClearErrorLog 清空错误日志 -func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) { if err := systemctl.LogsClear("mysqld"); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -152,12 +164,12 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { } // SlowLog 获取慢查询日志 -func (s *Service) SlowLog(w http.ResponseWriter, r *http.Request) { +func (s *App) SlowLog(w http.ResponseWriter, r *http.Request) { service.Success(w, fmt.Sprintf("%s/server/mysql/mysql-slow.log", app.Root)) } // ClearSlowLog 清空慢查询日志 -func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearSlowLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("echo '' > %s/server/mysql/mysql-slow.log", app.Root); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -167,7 +179,7 @@ func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) { } // GetRootPassword 获取root密码 -func (s *Service) GetRootPassword(w http.ResponseWriter, r *http.Request) { +func (s *App) GetRootPassword(w http.ResponseWriter, r *http.Request) { rootPassword, err := s.settingRepo.Get(biz.SettingKeyMySQLRootPassword) if err != nil { service.Error(w, http.StatusInternalServerError, "获取root密码失败") @@ -182,7 +194,7 @@ func (s *Service) GetRootPassword(w http.ResponseWriter, r *http.Request) { } // SetRootPassword 设置root密码 -func (s *Service) SetRootPassword(w http.ResponseWriter, r *http.Request) { +func (s *App) SetRootPassword(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[SetRootPassword](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -212,7 +224,7 @@ func (s *Service) SetRootPassword(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) getSock() string { +func (s *App) getSock() string { if io.Exists("/tmp/mysql.sock") { return "/tmp/mysql.sock" } diff --git a/internal/apps/mysql/init.go b/internal/apps/mysql/init.go deleted file mode 100644 index 1b760ca828..0000000000 --- a/internal/apps/mysql/init.go +++ /dev/null @@ -1,25 +0,0 @@ -package mysql - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "mysql", - Route: func(r chi.Router) { - service := NewService() - r.Get("/load", service.Load) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - r.Post("/clearErrorLog", service.ClearErrorLog) - r.Get("/slowLog", service.SlowLog) - r.Post("/clearSlowLog", service.ClearSlowLog) - r.Get("/rootPassword", service.GetRootPassword) - r.Post("/rootPassword", service.SetRootPassword) - }, - }) -} diff --git a/internal/apps/nginx/service.go b/internal/apps/nginx/app.go similarity index 84% rename from internal/apps/nginx/service.go rename to internal/apps/nginx/app.go index eb64c7902d..71bb8709eb 100644 --- a/internal/apps/nginx/service.go +++ b/internal/apps/nginx/app.go @@ -6,6 +6,7 @@ import ( "regexp" "time" + "github.com/go-chi/chi/v5" "github.com/go-resty/resty/v2" "github.com/spf13/cast" @@ -18,15 +19,23 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct { +type App struct { // Dependent services } -func NewService() *Service { - return &Service{} +func NewApp() *App { + return &App{} } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) Route(r chi.Router) { + r.Get("/load", s.Load) + r.Get("/config", s.GetConfig) + r.Post("/config", s.SaveConfig) + r.Get("/errorLog", s.ErrorLog) + r.Post("/clearErrorLog", s.ClearErrorLog) +} + +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(fmt.Sprintf("%s/server/nginx/conf/nginx.conf", app.Root)) if err != nil { service.Error(w, http.StatusInternalServerError, "获取配置失败") @@ -36,7 +45,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) SaveConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) SaveConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -57,11 +66,11 @@ func (s *Service) SaveConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ErrorLog(w http.ResponseWriter, r *http.Request) { service.Success(w, fmt.Sprintf("%s/%s", app.Root, "wwwlogs/nginx-error.log")) } -func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("echo '' > %s/%s", app.Root, "wwwlogs/nginx-error.log"); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -70,7 +79,7 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { client := resty.New().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/nginx_status") if err != nil || !resp.IsSuccess() { diff --git a/internal/apps/nginx/init.go b/internal/apps/nginx/init.go deleted file mode 100644 index ec1950f7b2..0000000000 --- a/internal/apps/nginx/init.go +++ /dev/null @@ -1,22 +0,0 @@ -package nginx - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "nginx", - Route: func(r chi.Router) { - service := NewService() - r.Get("/load", service.Load) - r.Get("/config", service.GetConfig) - r.Post("/config", service.SaveConfig) - r.Get("/errorLog", service.ErrorLog) - r.Post("/clearErrorLog", service.ClearErrorLog) - }, - }) -} diff --git a/internal/apps/php/service.go b/internal/apps/php/app.go similarity index 86% rename from internal/apps/php/service.go rename to internal/apps/php/app.go index 59e4f450f1..4573c48052 100644 --- a/internal/apps/php/service.go +++ b/internal/apps/php/app.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/go-chi/chi/v5" "github.com/go-resty/resty/v2" "github.com/spf13/cast" @@ -19,19 +20,39 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct { +type App struct { version uint taskRepo biz.TaskRepo } -func NewService(version uint) *Service { - return &Service{ - version: version, - taskRepo: nil, // TODO fixme +func NewApp(task biz.TaskRepo) *App { + return &App{ + taskRepo: task, } } -func (s *Service) SetCli(w http.ResponseWriter, r *http.Request) { +func (s *App) Route(version uint) func(r chi.Router) { + return func(r chi.Router) { + php := new(App) + php.version = version + php.taskRepo = s.taskRepo + r.Post("/setCli", php.SetCli) + r.Get("/config", php.GetConfig) + r.Post("/config", php.UpdateConfig) + r.Get("/fpmConfig", php.GetFPMConfig) + r.Post("/fpmConfig", php.UpdateFPMConfig) + r.Get("/load", php.Load) + r.Get("/errorLog", php.ErrorLog) + r.Get("/slowLog", php.SlowLog) + r.Post("/clearErrorLog", php.ClearErrorLog) + r.Post("/clearSlowLog", php.ClearSlowLog) + r.Get("/extensions", php.ExtensionList) + r.Post("/extensions", php.InstallExtension) + r.Delete("/extensions", php.UninstallExtension) + } +} + +func (s *App) SetCli(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("ln -sf %s/server/php/%d/bin/php /usr/bin/php", app.Root, s.version); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -40,7 +61,7 @@ func (s *Service) SetCli(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(fmt.Sprintf("%s/server/php/%d/etc/php.ini", app.Root, s.version)) if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -50,7 +71,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -65,7 +86,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) GetFPMConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetFPMConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(fmt.Sprintf("%s/server/php/%d/etc/php-fpm.conf", app.Root, s.version)) if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -75,7 +96,7 @@ func (s *Service) GetFPMConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -90,7 +111,7 @@ func (s *Service) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { var raw map[string]any client := resty.New().SetTimeout(10 * time.Second) _, err := client.R().SetResult(&raw).Get(fmt.Sprintf("http://127.0.0.1/phpfpm_status/%d?json", s.version)) @@ -116,15 +137,15 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { service.Success(w, loads) } -func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ErrorLog(w http.ResponseWriter, r *http.Request) { service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/php-fpm.log", app.Root, s.version)) } -func (s *Service) SlowLog(w http.ResponseWriter, r *http.Request) { +func (s *App) SlowLog(w http.ResponseWriter, r *http.Request) { service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/slow.log", app.Root, s.version)) } -func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("echo '' > %s/server/php/%d/var/log/php-fpm.log", app.Root, s.version); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -133,7 +154,7 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearSlowLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("echo '' > %s/server/php/%d/var/log/slow.log", app.Root, s.version); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -142,7 +163,7 @@ func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) ExtensionList(w http.ResponseWriter, r *http.Request) { +func (s *App) ExtensionList(w http.ResponseWriter, r *http.Request) { extensions := s.getExtensions() raw, err := shell.Execf("%s/server/php/%d/bin/php -m", app.Root, s.version) if err != nil { @@ -165,7 +186,7 @@ func (s *Service) ExtensionList(w http.ResponseWriter, r *http.Request) { service.Success(w, extensions) } -func (s *Service) InstallExtension(w http.ResponseWriter, r *http.Request) { +func (s *App) InstallExtension(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ExtensionSlug](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -196,7 +217,7 @@ func (s *Service) InstallExtension(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) UninstallExtension(w http.ResponseWriter, r *http.Request) { +func (s *App) UninstallExtension(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ExtensionSlug](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -227,7 +248,7 @@ func (s *Service) UninstallExtension(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) getExtensions() []Extension { +func (s *App) getExtensions() []Extension { extensions := []Extension{ { Name: "fileinfo", @@ -395,7 +416,7 @@ func (s *Service) getExtensions() []Extension { return extensions } -func (s *Service) checkExtension(slug string) bool { +func (s *App) checkExtension(slug string) bool { extensions := s.getExtensions() for _, item := range extensions { diff --git a/internal/apps/php/init.go b/internal/apps/php/init.go deleted file mode 100644 index 8f6a1b552a..0000000000 --- a/internal/apps/php/init.go +++ /dev/null @@ -1,35 +0,0 @@ -package php - -import ( - "fmt" - - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - php := []uint{74, 80, 81, 82, 83, 84} - for _, version := range php { - apploader.Register(&types.App{ - Slug: fmt.Sprintf("php%d", version), - Route: func(r chi.Router) { - service := NewService(version) - r.Post("/setCli", service.SetCli) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - r.Get("/fpmConfig", service.GetFPMConfig) - r.Post("/fpmConfig", service.UpdateFPMConfig) - r.Get("/load", service.Load) - r.Get("/errorLog", service.ErrorLog) - r.Get("/slowLog", service.SlowLog) - r.Post("/clearErrorLog", service.ClearErrorLog) - r.Post("/clearSlowLog", service.ClearSlowLog) - r.Get("/extensions", service.ExtensionList) - r.Post("/extensions", service.InstallExtension) - r.Delete("/extensions", service.UninstallExtension) - }, - }) - } -} diff --git a/internal/apps/phpmyadmin/service.go b/internal/apps/phpmyadmin/app.go similarity index 85% rename from internal/apps/phpmyadmin/service.go rename to internal/apps/phpmyadmin/app.go index 80b5932e66..d3d702aad3 100644 --- a/internal/apps/phpmyadmin/service.go +++ b/internal/apps/phpmyadmin/app.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/spf13/cast" @@ -17,13 +18,20 @@ import ( "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} -func NewService() *Service { - return &Service{} +func NewApp() *App { + return &App{} } -func (s *Service) Info(w http.ResponseWriter, r *http.Request) { +func (s *App) Route(r chi.Router) { + r.Get("/info", s.Info) + r.Post("/port", s.UpdatePort) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) +} + +func (s *App) Info(w http.ResponseWriter, r *http.Request) { files, err := io.ReadDir(fmt.Sprintf("%s/server/phpmyadmin", app.Root)) if err != nil { service.Error(w, http.StatusInternalServerError, "找不到 phpMyAdmin 目录") @@ -58,7 +66,7 @@ func (s *Service) Info(w http.ResponseWriter, r *http.Request) { }) } -func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdatePort(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdatePort](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -98,7 +106,7 @@ func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(fmt.Sprintf("%s/server/vhost/phpmyadmin.conf", app.Root)) if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -108,7 +116,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/phpmyadmin/init.go b/internal/apps/phpmyadmin/init.go deleted file mode 100644 index 22697a3326..0000000000 --- a/internal/apps/phpmyadmin/init.go +++ /dev/null @@ -1,21 +0,0 @@ -package phpmyadmin - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "phpmyadmin", - Route: func(r chi.Router) { - service := NewService() - r.Get("/info", service.Info) - r.Post("/port", service.UpdatePort) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/podman/service.go b/internal/apps/podman/app.go similarity index 70% rename from internal/apps/podman/service.go rename to internal/apps/podman/app.go index 5cde9752ec..5fa9280a11 100644 --- a/internal/apps/podman/service.go +++ b/internal/apps/podman/app.go @@ -3,18 +3,27 @@ package podman import ( "net/http" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/registryConfig", s.GetRegistryConfig) + r.Post("/registryConfig", s.UpdateRegistryConfig) + r.Get("/storageConfig", s.GetStorageConfig) + r.Post("/storageConfig", s.UpdateStorageConfig) } -func (s *Service) GetRegistryConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetRegistryConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/containers/registries.conf") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -24,7 +33,7 @@ func (s *Service) GetRegistryConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -44,7 +53,7 @@ func (s *Service) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) GetStorageConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetStorageConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/containers/storage.conf") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -54,7 +63,7 @@ func (s *Service) GetStorageConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateStorageConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateStorageConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/podman/init.go b/internal/apps/podman/init.go deleted file mode 100644 index bf500e8840..0000000000 --- a/internal/apps/podman/init.go +++ /dev/null @@ -1,21 +0,0 @@ -package podman - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "podman", - Route: func(r chi.Router) { - service := NewService() - r.Get("/registryConfig", service.GetRegistryConfig) - r.Post("/registryConfig", service.UpdateRegistryConfig) - r.Get("/storageConfig", service.GetStorageConfig) - r.Post("/storageConfig", service.UpdateStorageConfig) - }, - }) -} diff --git a/internal/apps/postgresql/service.go b/internal/apps/postgresql/app.go similarity index 83% rename from internal/apps/postgresql/service.go rename to internal/apps/postgresql/app.go index 62059c585c..ce15be7d82 100644 --- a/internal/apps/postgresql/service.go +++ b/internal/apps/postgresql/app.go @@ -5,6 +5,8 @@ import ( "net/http" "time" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" @@ -13,14 +15,24 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) + r.Get("/userConfig", s.GetUserConfig) + r.Post("/userConfig", s.UpdateUserConfig) + r.Get("/load", s.Load) + r.Get("/log", s.Log) + r.Post("/clearLog", s.ClearLog) } // GetConfig 获取配置 -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { // 获取配置 config, err := io.Read(fmt.Sprintf("%s/server/postgresql/data/postgresql.conf", app.Root)) if err != nil { @@ -32,7 +44,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { } // UpdateConfig 保存配置 -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -53,7 +65,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { } // GetUserConfig 获取用户配置 -func (s *Service) GetUserConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetUserConfig(w http.ResponseWriter, r *http.Request) { // 获取配置 config, err := io.Read(fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root)) if err != nil { @@ -65,7 +77,7 @@ func (s *Service) GetUserConfig(w http.ResponseWriter, r *http.Request) { } // UpdateUserConfig 保存用户配置 -func (s *Service) UpdateUserConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateUserConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -86,7 +98,7 @@ func (s *Service) UpdateUserConfig(w http.ResponseWriter, r *http.Request) { } // Load 获取负载 -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { status, _ := systemctl.Status("postgresql") if !status { service.Success(w, []types.NV{}) @@ -131,12 +143,12 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { } // Log 获取日志 -func (s *Service) Log(w http.ResponseWriter, r *http.Request) { +func (s *App) Log(w http.ResponseWriter, r *http.Request) { service.Success(w, fmt.Sprintf("%s/server/postgresql/logs/postgresql-%s.log", app.Root, time.Now().Format(time.DateOnly))) } // ClearLog 清空日志 -func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf("rm -rf %s/server/postgresql/logs/postgresql-*.log", app.Root); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return diff --git a/internal/apps/postgresql/init.go b/internal/apps/postgresql/init.go deleted file mode 100644 index f1a13bff29..0000000000 --- a/internal/apps/postgresql/init.go +++ /dev/null @@ -1,24 +0,0 @@ -package postgresql - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "postgresql", - Route: func(r chi.Router) { - service := NewService() - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - r.Get("/userConfig", service.GetUserConfig) - r.Post("/userConfig", service.UpdateUserConfig) - r.Get("/load", service.Load) - r.Get("/log", service.Log) - r.Post("/clearLog", service.ClearLog) - }, - }) -} diff --git a/internal/apps/pureftpd/service.go b/internal/apps/pureftpd/app.go similarity index 85% rename from internal/apps/pureftpd/service.go rename to internal/apps/pureftpd/app.go index 951f11731d..bfd46662f9 100644 --- a/internal/apps/pureftpd/service.go +++ b/internal/apps/pureftpd/app.go @@ -5,6 +5,7 @@ import ( "regexp" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/spf13/cast" @@ -16,14 +17,23 @@ import ( "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} -func NewService() *Service { - return &Service{} +func NewApp() *App { + return &App{} +} + +func (s *App) Route(r chi.Router) { + r.Get("/users", s.List) + r.Post("/users", s.Create) + r.Delete("/users/{username}", s.Delete) + r.Post("/users/{username}/password", s.ChangePassword) + r.Get("/port", s.GetPort) + r.Post("/port", s.UpdatePort) } // List 获取用户列表 -func (s *Service) List(w http.ResponseWriter, r *http.Request) { +func (s *App) List(w http.ResponseWriter, r *http.Request) { listRaw, err := shell.Execf("pure-pw list") if err != nil { service.Success(w, chix.M{ @@ -55,7 +65,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { } // Create 创建用户 -func (s *Service) Create(w http.ResponseWriter, r *http.Request) { +func (s *App) Create(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Create](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -91,7 +101,7 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) { } // Delete 删除用户 -func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { +func (s *App) Delete(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Delete](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -111,7 +121,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { } // ChangePassword 修改密码 -func (s *Service) ChangePassword(w http.ResponseWriter, r *http.Request) { +func (s *App) ChangePassword(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ChangePassword](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -131,7 +141,7 @@ func (s *Service) ChangePassword(w http.ResponseWriter, r *http.Request) { } // GetPort 获取端口 -func (s *Service) GetPort(w http.ResponseWriter, r *http.Request) { +func (s *App) GetPort(w http.ResponseWriter, r *http.Request) { port, err := shell.Execf(`cat %s/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`, app.Root) if err != nil { service.Error(w, http.StatusInternalServerError, "获取PureFtpd端口失败") @@ -142,7 +152,7 @@ func (s *Service) GetPort(w http.ResponseWriter, r *http.Request) { } // UpdatePort 设置端口 -func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdatePort(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdatePort](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/pureftpd/init.go b/internal/apps/pureftpd/init.go deleted file mode 100644 index 71397dba1d..0000000000 --- a/internal/apps/pureftpd/init.go +++ /dev/null @@ -1,23 +0,0 @@ -package pureftpd - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "pureftpd", - Route: func(r chi.Router) { - service := NewService() - r.Get("/users", service.List) - r.Post("/users", service.Create) - r.Delete("/users/{username}", service.Delete) - r.Post("/users/{username}/password", service.ChangePassword) - r.Get("/port", service.GetPort) - r.Post("/port", service.UpdatePort) - }, - }) -} diff --git a/internal/apps/redis/service.go b/internal/apps/redis/app.go similarity index 86% rename from internal/apps/redis/service.go rename to internal/apps/redis/app.go index eb27665298..2c3bb6c958 100644 --- a/internal/apps/redis/service.go +++ b/internal/apps/redis/app.go @@ -5,6 +5,8 @@ import ( "net/http" "strings" + "github.com/go-chi/chi/v5" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/service" "github.com/TheTNB/panel/pkg/io" @@ -13,13 +15,19 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct{} +type App struct{} + +func NewApp() *App { + return &App{} +} -func NewService() *Service { - return &Service{} +func (s *App) Route(r chi.Router) { + r.Get("/load", s.Load) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) } -func (s *Service) Load(w http.ResponseWriter, r *http.Request) { +func (s *App) Load(w http.ResponseWriter, r *http.Request) { status, err := systemctl.Status("redis") if err != nil { service.Error(w, http.StatusInternalServerError, "获取 Redis 状态失败") @@ -65,7 +73,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { service.Success(w, data) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read(fmt.Sprintf("%s/server/redis/redis.conf", app.Root)) if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -75,7 +83,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/redis/init.go b/internal/apps/redis/init.go deleted file mode 100644 index eefed56971..0000000000 --- a/internal/apps/redis/init.go +++ /dev/null @@ -1,20 +0,0 @@ -package redis - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "redis", - Route: func(r chi.Router) { - service := NewService() - r.Get("/load", service.Load) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/rsync/service.go b/internal/apps/rsync/app.go similarity index 90% rename from internal/apps/rsync/service.go rename to internal/apps/rsync/app.go index 0cc0df1865..bf3fc81dc7 100644 --- a/internal/apps/rsync/service.go +++ b/internal/apps/rsync/app.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/go-rat/utils/str" @@ -15,13 +16,22 @@ import ( "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct{} +type App struct{} -func NewService() *Service { - return &Service{} +func NewApp() *App { + return &App{} } -func (s *Service) List(w http.ResponseWriter, r *http.Request) { +func (s *App) Route(r chi.Router) { + r.Get("/modules", s.List) + r.Post("/modules", s.Create) + r.Post("/modules/{name}", s.Update) + r.Delete("/modules/{name}", s.Delete) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) +} + +func (s *App) List(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/rsyncd.conf") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -86,7 +96,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { }) } -func (s *Service) Create(w http.ResponseWriter, r *http.Request) { +func (s *App) Create(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Create](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -131,7 +141,7 @@ secrets file = /etc/rsyncd.secrets service.Success(w, nil) } -func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { +func (s *App) Delete(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Delete](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -173,7 +183,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { service.Success(w, nil) } -func (s *Service) Update(w http.ResponseWriter, r *http.Request) { +func (s *App) Update(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Update](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -229,7 +239,7 @@ secrets file = /etc/rsyncd.secrets service.Success(w, nil) } -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { config, err := io.Read("/etc/rsyncd.conf") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -239,7 +249,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { service.Success(w, config) } -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/rsync/init.go b/internal/apps/rsync/init.go deleted file mode 100644 index 551554570a..0000000000 --- a/internal/apps/rsync/init.go +++ /dev/null @@ -1,23 +0,0 @@ -package rsync - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "rsync", - Route: func(r chi.Router) { - service := NewService() - r.Get("/modules", service.List) - r.Post("/modules", service.Create) - r.Post("/modules/{name}", service.Update) - r.Delete("/modules/{name}", service.Delete) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - }, - }) -} diff --git a/internal/apps/s3fs/service.go b/internal/apps/s3fs/app.go similarity index 92% rename from internal/apps/s3fs/service.go rename to internal/apps/s3fs/app.go index 8d0aec22b6..865fdab69c 100644 --- a/internal/apps/s3fs/service.go +++ b/internal/apps/s3fs/app.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/spf13/cast" @@ -15,18 +16,24 @@ import ( "github.com/TheTNB/panel/pkg/shell" ) -type Service struct { +type App struct { settingRepo biz.SettingRepo } -func NewService() *Service { - return &Service{ - settingRepo: nil, // TODO fixme +func NewApp(setting biz.SettingRepo) *App { + return &App{ + settingRepo: setting, } } +func (s *App) Route(r chi.Router) { + r.Get("/mounts", s.List) + r.Post("/mounts", s.Create) + r.Delete("/mounts", s.Delete) +} + // List 所有 S3fs 挂载 -func (s *Service) List(w http.ResponseWriter, r *http.Request) { +func (s *App) List(w http.ResponseWriter, r *http.Request) { var s3fsList []Mount list, err := s.settingRepo.Get("s3fs", "[]") if err != nil { @@ -48,7 +55,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) { } // Create 添加 S3fs 挂载 -func (s *Service) Create(w http.ResponseWriter, r *http.Request) { +func (s *App) Create(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Create](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -133,7 +140,7 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) { } // Delete 删除 S3fs 挂载 -func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { +func (s *App) Delete(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Delete](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/s3fs/init.go b/internal/apps/s3fs/init.go deleted file mode 100644 index 0b7e100186..0000000000 --- a/internal/apps/s3fs/init.go +++ /dev/null @@ -1,20 +0,0 @@ -package s3fs - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "s3fs", - Route: func(r chi.Router) { - service := NewService() - r.Get("/mounts", service.List) - r.Post("/mounts", service.Create) - r.Delete("/mounts", service.Delete) - }, - }) -} diff --git a/internal/apps/supervisor/service.go b/internal/apps/supervisor/app.go similarity index 83% rename from internal/apps/supervisor/service.go rename to internal/apps/supervisor/app.go index d301f5bea2..40e7fe34fb 100644 --- a/internal/apps/supervisor/service.go +++ b/internal/apps/supervisor/app.go @@ -4,6 +4,7 @@ import ( "net/http" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/spf13/cast" @@ -14,11 +15,11 @@ import ( "github.com/TheTNB/panel/pkg/systemctl" ) -type Service struct { +type App struct { name string } -func NewService() *Service { +func NewApp() *App { var name string if os.IsRHEL() { name = "supervisord" @@ -26,18 +27,35 @@ func NewService() *Service { name = "supervisor" } - return &Service{ + return &App{ name: name, } } +func (s *App) Route(r chi.Router) { + r.Get("/service", s.Service) + r.Post("/clearLog", s.ClearLog) + r.Get("/config", s.GetConfig) + r.Post("/config", s.UpdateConfig) + r.Get("/processes", s.Processes) + r.Post("/processes/{process}/start", s.StartProcess) + r.Post("/processes/{process}/stop", s.StopProcess) + r.Post("/processes/{process}/restart", s.RestartProcess) + r.Get("/processes/{process}/log", s.ProcessLog) + r.Post("/processes/{process}/clearLog", s.ClearProcessLog) + r.Get("/processes/{process}", s.ProcessConfig) + r.Post("/processes/{process}", s.UpdateProcessConfig) + r.Delete("/processes/{process}", s.DeleteProcess) + r.Post("/processes", s.CreateProcess) +} + // Service 获取服务名称 -func (s *Service) Service(w http.ResponseWriter, r *http.Request) { +func (s *App) Service(w http.ResponseWriter, r *http.Request) { service.Success(w, s.name) } // ClearLog 清空日志 -func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) { if _, err := shell.Execf(`echo "" > /var/log/supervisor/supervisord.log`); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) return @@ -47,7 +65,7 @@ func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) { } // GetConfig 获取配置 -func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) { var config string var err error if os.IsRHEL() { @@ -65,7 +83,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) { } // UpdateConfig 保存配置 -func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -92,7 +110,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) { } // Processes 进程列表 -func (s *Service) Processes(w http.ResponseWriter, r *http.Request) { +func (s *App) Processes(w http.ResponseWriter, r *http.Request) { out, err := shell.Execf(`supervisorctl status | awk '{print $1}'`) if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -131,7 +149,7 @@ func (s *Service) Processes(w http.ResponseWriter, r *http.Request) { } // StartProcess 启动进程 -func (s *Service) StartProcess(w http.ResponseWriter, r *http.Request) { +func (s *App) StartProcess(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -147,7 +165,7 @@ func (s *Service) StartProcess(w http.ResponseWriter, r *http.Request) { } // StopProcess 停止进程 -func (s *Service) StopProcess(w http.ResponseWriter, r *http.Request) { +func (s *App) StopProcess(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -163,7 +181,7 @@ func (s *Service) StopProcess(w http.ResponseWriter, r *http.Request) { } // RestartProcess 重启进程 -func (s *Service) RestartProcess(w http.ResponseWriter, r *http.Request) { +func (s *App) RestartProcess(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -179,7 +197,7 @@ func (s *Service) RestartProcess(w http.ResponseWriter, r *http.Request) { } // ProcessLog 进程日志 -func (s *Service) ProcessLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ProcessLog(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -202,7 +220,7 @@ func (s *Service) ProcessLog(w http.ResponseWriter, r *http.Request) { } // ClearProcessLog 清空进程日志 -func (s *Service) ClearProcessLog(w http.ResponseWriter, r *http.Request) { +func (s *App) ClearProcessLog(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -230,7 +248,7 @@ func (s *Service) ClearProcessLog(w http.ResponseWriter, r *http.Request) { } // ProcessConfig 获取进程配置 -func (s *Service) ProcessConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) ProcessConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -253,7 +271,7 @@ func (s *Service) ProcessConfig(w http.ResponseWriter, r *http.Request) { } // UpdateProcessConfig 保存进程配置 -func (s *Service) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[UpdateProcessConfig](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -279,7 +297,7 @@ func (s *Service) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) { } // CreateProcess 添加进程 -func (s *Service) CreateProcess(w http.ResponseWriter, r *http.Request) { +func (s *App) CreateProcess(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[CreateProcess](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -318,7 +336,7 @@ stdout_logfile_maxbytes=2MB } // DeleteProcess 删除进程 -func (s *Service) DeleteProcess(w http.ResponseWriter, r *http.Request) { +func (s *App) DeleteProcess(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[ProcessName](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/supervisor/init.go b/internal/apps/supervisor/init.go deleted file mode 100644 index 8a1f179634..0000000000 --- a/internal/apps/supervisor/init.go +++ /dev/null @@ -1,31 +0,0 @@ -package supervisor - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "supervisor", - Route: func(r chi.Router) { - service := NewService() - r.Get("/service", service.Service) - r.Post("/clearLog", service.ClearLog) - r.Get("/config", service.GetConfig) - r.Post("/config", service.UpdateConfig) - r.Get("/processes", service.Processes) - r.Post("/processes/{process}/start", service.StartProcess) - r.Post("/processes/{process}/stop", service.StopProcess) - r.Post("/processes/{process}/restart", service.RestartProcess) - r.Get("/processes/{process}/log", service.ProcessLog) - r.Post("/processes/{process}/clearLog", service.ClearProcessLog) - r.Get("/processes/{process}", service.ProcessConfig) - r.Post("/processes/{process}", service.UpdateProcessConfig) - r.Delete("/processes/{process}", service.DeleteProcess) - r.Post("/processes", service.CreateProcess) - }, - }) -} diff --git a/internal/apps/toolbox/service.go b/internal/apps/toolbox/app.go similarity index 84% rename from internal/apps/toolbox/service.go rename to internal/apps/toolbox/app.go index 6e1bc79c3a..50a6bfeb8f 100644 --- a/internal/apps/toolbox/service.go +++ b/internal/apps/toolbox/app.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/go-chi/chi/v5" "github.com/go-rat/chix" "github.com/spf13/cast" @@ -18,14 +19,30 @@ import ( "github.com/TheTNB/panel/pkg/types" ) -type Service struct{} +type App struct{} -func NewService() *Service { - return &Service{} +func NewApp() *App { + return &App{} +} + +func (s *App) Route(r chi.Router) { + r.Get("/dns", s.GetDNS) + r.Post("/dns", s.UpdateDNS) + r.Get("/swap", s.GetSWAP) + r.Post("/swap", s.UpdateSWAP) + r.Get("/timezone", s.GetTimezone) + r.Post("/timezone", s.UpdateTimezone) + r.Post("/time", s.UpdateTime) + r.Post("/syncTime", s.SyncTime) + r.Get("/hostname", s.GetHostname) + r.Post("/hostname", s.UpdateHostname) + r.Get("/hosts", s.GetHosts) + r.Post("/hosts", s.UpdateHosts) + r.Post("/rootPassword", s.UpdateRootPassword) } // GetDNS 获取 DNS 信息 -func (s *Service) GetDNS(w http.ResponseWriter, r *http.Request) { +func (s *App) GetDNS(w http.ResponseWriter, r *http.Request) { raw, err := io.Read("/etc/resolv.conf") if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -46,7 +63,7 @@ func (s *Service) GetDNS(w http.ResponseWriter, r *http.Request) { } // UpdateDNS 设置 DNS 信息 -func (s *Service) UpdateDNS(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateDNS(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[DNS](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -66,7 +83,7 @@ func (s *Service) UpdateDNS(w http.ResponseWriter, r *http.Request) { } // GetSWAP 获取 SWAP 信息 -func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) { +func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) { var total, used, free string var size int64 if io.Exists(filepath.Join(app.Root, "swap")) { @@ -104,7 +121,7 @@ func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) { } // UpdateSWAP 设置 SWAP 信息 -func (s *Service) UpdateSWAP(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateSWAP(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[SWAP](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -172,7 +189,7 @@ func (s *Service) UpdateSWAP(w http.ResponseWriter, r *http.Request) { } // GetTimezone 获取时区 -func (s *Service) GetTimezone(w http.ResponseWriter, r *http.Request) { +func (s *App) GetTimezone(w http.ResponseWriter, r *http.Request) { raw, err := shell.Execf("timedatectl | grep zone") if err != nil { service.Error(w, http.StatusInternalServerError, "获取时区信息失败") @@ -207,7 +224,7 @@ func (s *Service) GetTimezone(w http.ResponseWriter, r *http.Request) { } // UpdateTimezone 设置时区 -func (s *Service) UpdateTimezone(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateTimezone(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Timezone](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -223,7 +240,7 @@ func (s *Service) UpdateTimezone(w http.ResponseWriter, r *http.Request) { } // UpdateTime 设置时间 -func (s *Service) UpdateTime(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateTime(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Time](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -240,7 +257,7 @@ func (s *Service) UpdateTime(w http.ResponseWriter, r *http.Request) { } // SyncTime 同步时间 -func (s *Service) SyncTime(w http.ResponseWriter, r *http.Request) { +func (s *App) SyncTime(w http.ResponseWriter, r *http.Request) { now, err := ntp.Now() if err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) @@ -256,13 +273,13 @@ func (s *Service) SyncTime(w http.ResponseWriter, r *http.Request) { } // GetHostname 获取主机名 -func (s *Service) GetHostname(w http.ResponseWriter, r *http.Request) { +func (s *App) GetHostname(w http.ResponseWriter, r *http.Request) { hostname, _ := io.Read("/etc/hostname") service.Success(w, strings.TrimSpace(hostname)) } // UpdateHostname 设置主机名 -func (s *Service) UpdateHostname(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateHostname(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Hostname](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -281,13 +298,13 @@ func (s *Service) UpdateHostname(w http.ResponseWriter, r *http.Request) { } // GetHosts 获取 hosts 信息 -func (s *Service) GetHosts(w http.ResponseWriter, r *http.Request) { +func (s *App) GetHosts(w http.ResponseWriter, r *http.Request) { hosts, _ := io.Read("/etc/hosts") service.Success(w, hosts) } // UpdateHosts 设置 hosts 信息 -func (s *Service) UpdateHosts(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateHosts(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Hosts](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) @@ -303,7 +320,7 @@ func (s *Service) UpdateHosts(w http.ResponseWriter, r *http.Request) { } // UpdateRootPassword 设置 root 密码 -func (s *Service) UpdateRootPassword(w http.ResponseWriter, r *http.Request) { +func (s *App) UpdateRootPassword(w http.ResponseWriter, r *http.Request) { req, err := service.Bind[Password](r) if err != nil { service.Error(w, http.StatusUnprocessableEntity, "%v", err) diff --git a/internal/apps/toolbox/init.go b/internal/apps/toolbox/init.go deleted file mode 100644 index df78b391c9..0000000000 --- a/internal/apps/toolbox/init.go +++ /dev/null @@ -1,30 +0,0 @@ -package toolbox - -import ( - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/apploader" - "github.com/TheTNB/panel/pkg/types" -) - -func init() { - apploader.Register(&types.App{ - Slug: "toolbox", - Route: func(r chi.Router) { - service := NewService() - r.Get("/dns", service.GetDNS) - r.Post("/dns", service.UpdateDNS) - r.Get("/swap", service.GetSWAP) - r.Post("/swap", service.UpdateSWAP) - r.Get("/timezone", service.GetTimezone) - r.Post("/timezone", service.UpdateTimezone) - r.Post("/time", service.UpdateTime) - r.Post("/syncTime", service.SyncTime) - r.Get("/hostname", service.GetHostname) - r.Post("/hostname", service.UpdateHostname) - r.Get("/hosts", service.GetHosts) - r.Post("/hosts", service.UpdateHosts) - r.Post("/rootPassword", service.UpdateRootPassword) - }, - }) -} diff --git a/internal/biz/task.go b/internal/biz/task.go index e58380d0d5..35a8d5869e 100644 --- a/internal/biz/task.go +++ b/internal/biz/task.go @@ -28,5 +28,4 @@ type TaskRepo interface { Delete(id uint) error UpdateStatus(id uint, status TaskStatus) error Push(task *Task) error - DispatchWaiting() } diff --git a/internal/bootstrap/http.go b/internal/bootstrap/http.go index 225dc991e4..3748da7afc 100644 --- a/internal/bootstrap/http.go +++ b/internal/bootstrap/http.go @@ -2,20 +2,18 @@ package bootstrap import ( "crypto/tls" - "log/slog" + "fmt" "net/http" "github.com/bddjr/hlfhr" "github.com/go-chi/chi/v5" - "github.com/go-rat/sessions" "github.com/knadh/koanf/v2" - "gorm.io/gorm" "github.com/TheTNB/panel/internal/http/middleware" "github.com/TheTNB/panel/internal/route" ) -func NewRouter(conf *koanf.Koanf, db *gorm.DB, log *slog.Logger, session *sessions.Manager, middlewares *middleware.Middlewares, http *route.Http, ws *route.Ws) (*chi.Mux, error) { +func NewRouter(middlewares *middleware.Middlewares, http *route.Http, ws *route.Ws) (*chi.Mux, error) { r := chi.NewRouter() // add middleware @@ -30,7 +28,7 @@ func NewRouter(conf *koanf.Koanf, db *gorm.DB, log *slog.Logger, session *sessio func NewHttp(conf *koanf.Koanf, r *chi.Mux) (*hlfhr.Server, error) { srv := hlfhr.New(&http.Server{ - Addr: conf.MustString("http.address"), + Addr: fmt.Sprintf(":%d", conf.MustInt("http.port")), Handler: http.AllowQuerySemicolons(r), MaxHeaderBytes: 2048 << 20, }) diff --git a/internal/data/cache.go b/internal/data/cache.go index 72ae99af59..540f361cb7 100644 --- a/internal/data/cache.go +++ b/internal/data/cache.go @@ -8,9 +8,9 @@ import ( "gorm.io/gorm" "github.com/TheTNB/panel/internal/app" + "github.com/TheTNB/panel/internal/apps" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/pkg/api" - "github.com/TheTNB/panel/pkg/apploader" ) type cacheRepo struct { @@ -58,8 +58,7 @@ func (r *cacheRepo) UpdateApps() error { // 去除本地不存在的应用 *remote = slices.Clip(slices.DeleteFunc(*remote, func(app *api.App) bool { - _, err = apploader.Get(app.Slug) - return err != nil + return !slices.Contains(apps.Slugs(), app.Slug) })) encoded, err := json.Marshal(remote) diff --git a/internal/data/database.go b/internal/data/database.go index 8161ada27e..2b24d38285 100644 --- a/internal/data/database.go +++ b/internal/data/database.go @@ -5,24 +5,30 @@ import ( "fmt" "slices" - "github.com/TheTNB/panel/internal/app" + "gorm.io/gorm" + "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/db" ) type databaseRepo struct { + db *gorm.DB server biz.DatabaseServerRepo user biz.DatabaseUserRepo } -func NewDatabaseRepo(server biz.DatabaseServerRepo, user biz.DatabaseUserRepo) biz.DatabaseRepo { - return &databaseRepo{server: server, user: user} +func NewDatabaseRepo(db *gorm.DB, server biz.DatabaseServerRepo, user biz.DatabaseUserRepo) biz.DatabaseRepo { + return &databaseRepo{ + db: db, + server: server, + user: user, + } } func (r databaseRepo) List(page, limit uint) ([]*biz.Database, int64, error) { var databaseServer []*biz.DatabaseServer - if err := app.Orm.Model(&biz.DatabaseServer{}).Order("id desc").Find(&databaseServer).Error; err != nil { + if err := r.db.Model(&biz.DatabaseServer{}).Order("id desc").Find(&databaseServer).Error; err != nil { return nil, 0, err } diff --git a/internal/data/database_server.go b/internal/data/database_server.go index 16b644112b..e66f979057 100644 --- a/internal/data/database_server.go +++ b/internal/data/database_server.go @@ -7,7 +7,6 @@ import ( "gorm.io/gorm" - "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" @@ -120,7 +119,7 @@ func (r databaseServerRepo) Delete(id uint) error { // ClearUsers 删除指定服务器的所有用户,只是删除面板记录,不会实际删除 func (r databaseServerRepo) ClearUsers(serverID uint) error { - return app.Orm.Where("server_id = ?", serverID).Delete(&biz.DatabaseUser{}).Error + return r.db.Where("server_id = ?", serverID).Delete(&biz.DatabaseUser{}).Error } func (r databaseServerRepo) Sync(id uint) error { diff --git a/internal/data/database_user.go b/internal/data/database_user.go index 93417eff05..76440024c5 100644 --- a/internal/data/database_user.go +++ b/internal/data/database_user.go @@ -4,23 +4,28 @@ import ( "fmt" "slices" - "github.com/TheTNB/panel/internal/app" + "gorm.io/gorm" + "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/db" ) type databaseUserRepo struct { + db *gorm.DB server biz.DatabaseServerRepo } -func NewDatabaseUserRepo(server biz.DatabaseServerRepo) biz.DatabaseUserRepo { - return &databaseUserRepo{server: server} +func NewDatabaseUserRepo(db *gorm.DB, server biz.DatabaseServerRepo) biz.DatabaseUserRepo { + return &databaseUserRepo{ + db: db, + server: server, + } } func (r databaseUserRepo) Count() (int64, error) { var count int64 - if err := app.Orm.Model(&biz.DatabaseUser{}).Count(&count).Error; err != nil { + if err := r.db.Model(&biz.DatabaseUser{}).Count(&count).Error; err != nil { return 0, err } @@ -30,7 +35,7 @@ func (r databaseUserRepo) Count() (int64, error) { func (r databaseUserRepo) List(page, limit uint) ([]*biz.DatabaseUser, int64, error) { var user []*biz.DatabaseUser var total int64 - err := app.Orm.Model(&biz.DatabaseUser{}).Preload("Server").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&user).Error + err := r.db.Model(&biz.DatabaseUser{}).Preload("Server").Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&user).Error for u := range slices.Values(user) { r.fillUser(u) @@ -41,7 +46,7 @@ func (r databaseUserRepo) List(page, limit uint) ([]*biz.DatabaseUser, int64, er func (r databaseUserRepo) Get(id uint) (*biz.DatabaseUser, error) { user := new(biz.DatabaseUser) - if err := app.Orm.Preload("Server").Where("id = ?", id).First(user).Error; err != nil { + if err := r.db.Preload("Server").Where("id = ?", id).First(user).Error; err != nil { return nil, err } @@ -97,14 +102,14 @@ func (r databaseUserRepo) Create(req *request.DatabaseUserCreate) error { } } - if err = app.Orm.FirstOrInit(user, user).Error; err != nil { + if err = r.db.FirstOrInit(user, user).Error; err != nil { return err } user.Password = req.Password user.Remark = req.Remark - return app.Orm.Save(user).Error + return r.db.Save(user).Error } func (r databaseUserRepo) Update(req *request.DatabaseUserUpdate) error { @@ -156,7 +161,7 @@ func (r databaseUserRepo) Update(req *request.DatabaseUserUpdate) error { user.Password = req.Password user.Remark = req.Remark - return app.Orm.Save(user).Error + return r.db.Save(user).Error } func (r databaseUserRepo) UpdateRemark(req *request.DatabaseUserUpdateRemark) error { @@ -167,7 +172,7 @@ func (r databaseUserRepo) UpdateRemark(req *request.DatabaseUserUpdateRemark) er user.Remark = req.Remark - return app.Orm.Save(user).Error + return r.db.Save(user).Error } func (r databaseUserRepo) Delete(id uint) error { @@ -198,7 +203,7 @@ func (r databaseUserRepo) Delete(id uint) error { _ = postgres.UserDrop(user.Username) } - return app.Orm.Where("id = ?", id).Delete(&biz.DatabaseUser{}).Error + return r.db.Where("id = ?", id).Delete(&biz.DatabaseUser{}).Error } func (r databaseUserRepo) DeleteByNames(serverID uint, names []string) error { @@ -215,7 +220,7 @@ func (r databaseUserRepo) DeleteByNames(serverID uint, names []string) error { } defer mysql.Close() users := make([]*biz.DatabaseUser, 0) - if err = app.Orm.Where("server_id = ? AND username IN ?", serverID, names).Find(&users).Error; err != nil { + if err = r.db.Where("server_id = ? AND username IN ?", serverID, names).Find(&users).Error; err != nil { return err } for name := range slices.Values(names) { @@ -239,7 +244,7 @@ func (r databaseUserRepo) DeleteByNames(serverID uint, names []string) error { } } - return app.Orm.Where("server_id = ? AND username IN ?", serverID, names).Delete(&biz.DatabaseUser{}).Error + return r.db.Where("server_id = ? AND username IN ?", serverID, names).Delete(&biz.DatabaseUser{}).Error } func (r databaseUserRepo) fillUser(user *biz.DatabaseUser) { diff --git a/internal/data/monitor.go b/internal/data/monitor.go index abbb2205a6..a584e5a636 100644 --- a/internal/data/monitor.go +++ b/internal/data/monitor.go @@ -7,7 +7,6 @@ import ( "github.com/spf13/cast" "gorm.io/gorm" - "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" ) @@ -53,12 +52,12 @@ func (r monitorRepo) UpdateSetting(setting *request.MonitorSetting) error { } func (r monitorRepo) Clear() error { - return app.Orm.Where("1 = 1").Delete(&biz.Monitor{}).Error + return r.db.Where("1 = 1").Delete(&biz.Monitor{}).Error } func (r monitorRepo) List(start, end time.Time) ([]*biz.Monitor, error) { var monitors []*biz.Monitor - if err := app.Orm.Where("created_at BETWEEN ? AND ?", start, end).Find(&monitors).Error; err != nil { + if err := r.db.Where("created_at BETWEEN ? AND ?", start, end).Find(&monitors).Error; err != nil { return nil, err } diff --git a/internal/data/task.go b/internal/data/task.go index c3afcf0e78..c1d17f7831 100644 --- a/internal/data/task.go +++ b/internal/data/task.go @@ -6,7 +6,6 @@ import ( "gorm.io/gorm" - "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/queuejob" "github.com/TheTNB/panel/pkg/queue" @@ -70,31 +69,3 @@ func (r *taskRepo) Push(task *biz.Task) error { task.ID, }) } - -// TODO 修复此功能 -func (r *taskRepo) DispatchWaiting() { - // cli下不处理 - if app.IsCli { - return - } - - 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 := 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 := r.queue.Push(queuejob.NewProcessTask(r.log, r), []any{ - task.ID, - }); err != nil { - r.log.Warn("failed to push task", slog.Any("err", err)) - return - } - } -} diff --git a/internal/job/monitoring.go b/internal/job/monitoring.go index 98c3a4058c..8df12f0d39 100644 --- a/internal/job/monitoring.go +++ b/internal/job/monitoring.go @@ -32,10 +32,6 @@ func (r *Monitoring) Run() { return } - // 将等待中的任务分发 - //task := data.NewTaskRepo() - //_ = task.DispatchWaiting() - monitor, err := r.settingRepo.Get(biz.SettingKeyMonitor) if err != nil || !cast.ToBool(monitor) { return diff --git a/internal/route/http.go b/internal/route/http.go index 3d11f87693..053002ad8f 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -40,6 +40,7 @@ type Http struct { monitor *service.MonitorService setting *service.SettingService systemctl *service.SystemctlService + apps *apps.Loader } func NewHttp( @@ -68,6 +69,7 @@ func NewHttp( monitor *service.MonitorService, setting *service.SettingService, systemctl *service.SystemctlService, + apps *apps.Loader, ) *Http { return &Http{ user: user, @@ -95,6 +97,7 @@ func NewHttp( monitor: monitor, setting: setting, systemctl: systemctl, + apps: apps, } } @@ -344,7 +347,7 @@ func (route *Http) Register(r *chi.Mux) { }) r.Route("/apps", func(r chi.Router) { - apps.Boot(r) + route.apps.Register(r) }) }) diff --git a/internal/service/cli.go b/internal/service/cli.go index f71f1768c6..1ee9e9f725 100644 --- a/internal/service/cli.go +++ b/internal/service/cli.go @@ -34,6 +34,7 @@ type CliService struct { hr string api *api.API conf *koanf.Koanf + db *gorm.DB appRepo biz.AppRepo cacheRepo biz.CacheRepo userRepo biz.UserRepo @@ -44,11 +45,12 @@ type CliService struct { hash hash.Hasher } -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 { +func NewCliService(conf *koanf.Koanf, db *gorm.DB, 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), conf: conf, + db: db, appRepo: appRepo, cacheRepo: cache, userRepo: user, @@ -120,7 +122,7 @@ func (s *CliService) Fix(ctx context.Context, cmd *cli.Command) error { func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error { user := new(biz.User) - if err := app.Orm.Where("id", 1).First(user).Error; err != nil { + if err := s.db.Where("id", 1).First(user).Error; err != nil { return fmt.Errorf("获取管理员信息失败:%v", err) } @@ -135,7 +137,7 @@ func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error { user.Email = str.Random(8) + "@example.com" } - if err = app.Orm.Save(user).Error; err != nil { + if err = s.db.Save(user).Error; err != nil { return fmt.Errorf("管理员信息保存失败:%v", err) } @@ -185,7 +187,7 @@ func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error { func (s *CliService) UserList(ctx context.Context, cmd *cli.Command) error { users := make([]biz.User, 0) - if err := app.Orm.Find(&users).Error; err != nil { + if err := s.db.Find(&users).Error; err != nil { return fmt.Errorf("获取用户列表失败:%v", err) } @@ -207,7 +209,7 @@ func (s *CliService) UserName(ctx context.Context, cmd *cli.Command) error { return fmt.Errorf("新用户名不能为空") } - if err := app.Orm.Where("username", oldUsername).First(user).Error; err != nil { + if err := s.db.Where("username", oldUsername).First(user).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("用户不存在") } else { @@ -216,7 +218,7 @@ func (s *CliService) UserName(ctx context.Context, cmd *cli.Command) error { } user.Username = newUsername - if err := app.Orm.Save(user).Error; err != nil { + if err := s.db.Save(user).Error; err != nil { return fmt.Errorf("用户名修改失败:%v", err) } @@ -235,7 +237,7 @@ func (s *CliService) UserPassword(ctx context.Context, cmd *cli.Command) error { return fmt.Errorf("密码长度不能小于6") } - if err := app.Orm.Where("username", username).First(user).Error; err != nil { + if err := s.db.Where("username", username).First(user).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("用户不存在") } else { @@ -248,7 +250,7 @@ func (s *CliService) UserPassword(ctx context.Context, cmd *cli.Command) error { return fmt.Errorf("密码生成失败:%v", err) } user.Password = hashed - if err = app.Orm.Save(user).Error; err != nil { + if err = s.db.Save(user).Error; err != nil { return fmt.Errorf("密码修改失败:%v", err) } @@ -702,7 +704,7 @@ func (s *CliService) AppWrite(ctx context.Context, cmd *cli.Command) error { } newApp := new(biz.App) - if err := app.Orm.Where("slug", slug).First(newApp).Error; err != nil { + if err := s.db.Where("slug", slug).First(newApp).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("获取应用失败:%v", err) } @@ -710,7 +712,7 @@ func (s *CliService) AppWrite(ctx context.Context, cmd *cli.Command) error { newApp.Slug = slug newApp.Channel = channel newApp.Version = version - if err := app.Orm.Save(newApp).Error; err != nil { + if err := s.db.Save(newApp).Error; err != nil { return fmt.Errorf("应用保存失败:%v", err) } @@ -723,7 +725,7 @@ func (s *CliService) AppRemove(ctx context.Context, cmd *cli.Command) error { return fmt.Errorf("参数不能为空") } - if err := app.Orm.Where("slug", slug).Delete(&biz.App{}).Error; err != nil { + if err := s.db.Where("slug", slug).Delete(&biz.App{}).Error; err != nil { return fmt.Errorf("应用删除失败:%v", err) } @@ -745,7 +747,7 @@ func (s *CliService) SyncTime(ctx context.Context, cmd *cli.Command) error { } func (s *CliService) ClearTask(ctx context.Context, cmd *cli.Command) error { - if err := app.Orm.Model(&biz.Task{}). + if err := s.db.Model(&biz.Task{}). Where("status", biz.TaskStatusRunning).Or("status", biz.TaskStatusWaiting). Update("status", biz.TaskStatusFailed). Error; err != nil { @@ -763,7 +765,7 @@ func (s *CliService) GetSetting(ctx context.Context, cmd *cli.Command) error { } setting := new(biz.Setting) - if err := app.Orm.Where("key", key).First(setting).Error; err != nil { + if err := s.db.Where("key", key).First(setting).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("设置不存在") } @@ -783,14 +785,14 @@ func (s *CliService) WriteSetting(ctx context.Context, cmd *cli.Command) error { } setting := new(biz.Setting) - if err := app.Orm.Where("key", key).First(setting).Error; err != nil { + if err := s.db.Where("key", key).First(setting).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("获取设置失败:%v", err) } } setting.Key = biz.SettingKey(key) setting.Value = value - if err := app.Orm.Save(setting).Error; err != nil { + if err := s.db.Save(setting).Error; err != nil { return fmt.Errorf("设置保存失败:%v", err) } @@ -803,7 +805,7 @@ func (s *CliService) RemoveSetting(ctx context.Context, cmd *cli.Command) error return fmt.Errorf("参数不能为空") } - if err := app.Orm.Where("key", key).Delete(&biz.Setting{}).Error; err != nil { + if err := s.db.Where("key", key).Delete(&biz.Setting{}).Error; err != nil { return fmt.Errorf("设置删除失败:%v", err) } @@ -812,7 +814,7 @@ func (s *CliService) RemoveSetting(ctx context.Context, cmd *cli.Command) error func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error { var check biz.User - if err := app.Orm.First(&check).Error; err == nil { + if err := s.db.First(&check).Error; err == nil { return fmt.Errorf("已经初始化过了") } @@ -824,7 +826,7 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error { {Key: biz.SettingKeyWebsitePath, Value: filepath.Join(app.Root, "wwwroot")}, {Key: biz.SettingKeyVersion, Value: app.Version}, } - if err := app.Orm.Create(&settings).Error; err != nil { + if err := s.db.Create(&settings).Error; err != nil { return fmt.Errorf("初始化失败:%v", err) } diff --git a/pkg/apploader/apploader.go b/pkg/apploader/apploader.go deleted file mode 100644 index 991fb1d78d..0000000000 --- a/pkg/apploader/apploader.go +++ /dev/null @@ -1,54 +0,0 @@ -// Package apploader 面板应用加载器 -package apploader - -import ( - "fmt" - "log" - "sync" - - "github.com/go-chi/chi/v5" - - "github.com/TheTNB/panel/pkg/types" -) - -var apps sync.Map - -func Register(app *types.App) { - if _, ok := apps.Load(app.Slug); ok { - log.Fatalf("app %s already exists", app.Slug) - } - apps.Store(app.Slug, app) -} - -func Get(slug string) (*types.App, error) { - if app, ok := apps.Load(slug); ok { - return app.(*types.App), nil - } - return nil, fmt.Errorf("app %s not found", slug) -} - -func All() []*types.App { - var list []*types.App - apps.Range(func(_, app any) bool { - if p, ok := app.(*types.App); ok { - list = append(list, p) - } - return true - }) - - // 排序 - /*slices.SortFunc(list, func(a, b *types.App) int { - return cmp.Compare(a.Order, b.Order) - })*/ - - return list -} - -func Boot(r chi.Router) { - apps.Range(func(_, app any) bool { - if p, ok := app.(*types.App); ok { - r.Route(fmt.Sprintf("/%s", p.Slug), p.Route) - } - return true - }) -}