refactor!: 迁移至 samber/do 依赖注入与三层架构

依赖注入:
- 移除 google/wire(含 wire.go/wire_gen.go 与全部 ProviderSet),
  改用 samber/do v2 单注入器 + 双入口惰性构建
- 贡献模型替代命令式注册:路由 routes:、命令 commands:、
  任务 jobs: 前缀经 internal/registry 收集与校验
- 构造函数统一 func NewXxx(i do.Injector) (T, error)

三层架构:
- 补全用例层:每个 biz.XxxRepo 配 XxxUsecase,
  service/command/job 表现层只依赖用例,不再直接引用仓储

路由与文档:
- route/http.go 按域拆为声明式 Endpoint 贡献,
  Endpoint 承载登录白名单与端点限流语义
- 调试模式下提供 OpenAPI 3.1 文档:/openapi.json 与 /docs(Scalar),
  从 validate 标签生成

目录与依赖:
- internal/http/{middleware,request,rule} 拍平至 internal/*
- CLI 命令拆至 internal/command
- 日志轮转 timberjack 换为 libtnb/logrotate
- 升级 validator/cron/sessions/gormstore/sqlite/securecookie
- 数据库迁移保持 gormigrate 不变

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
耗子
2026-07-09 21:54:22 +08:00
co-authored by Claude Opus 4.8
parent 6f0593fbf8
commit 443516a2cf
331 changed files with 5524 additions and 2850 deletions
+21 -6
View File
@@ -1,24 +1,39 @@
package main package main
import ( import (
"errors"
"fmt"
"os" "os"
"runtime/debug" "runtime/debug"
_ "time/tzdata" _ "time/tzdata"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/injector"
) )
func main() { func main() {
if err := run(); err != nil {
_, _ = fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
}
}
func run() error {
if os.Geteuid() != 0 { if os.Geteuid() != 0 {
panic("panel must run as root") return errors.New("panel must run as root")
} }
debug.SetGCPercent(10) debug.SetGCPercent(10)
ace, err := initAce() inj := injector.New()
defer func() { _ = inj.Shutdown() }()
ace, err := do.Invoke[*app.Ace](inj)
if err != nil { if err != nil {
panic(err) return err
} }
if err = ace.Run(); err != nil { return ace.Run()
panic(err)
}
} }
-21
View File
@@ -1,21 +0,0 @@
//go:build wireinject
package main
import (
"github.com/google/wire"
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/apps"
"github.com/acepanel/panel/v3/internal/bootstrap"
"github.com/acepanel/panel/v3/internal/data"
"github.com/acepanel/panel/v3/internal/http/middleware"
"github.com/acepanel/panel/v3/internal/job"
"github.com/acepanel/panel/v3/internal/route"
"github.com/acepanel/panel/v3/internal/service"
)
// initAce init application.
func initAce() (*app.Ace, error) {
panic(wire.Build(bootstrap.ProviderSet, middleware.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, job.ProviderSet, app.NewAce))
}
-224
View File
@@ -1,224 +0,0 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/apps/apache"
"github.com/acepanel/panel/v3/internal/apps/clickhouse"
"github.com/acepanel/panel/v3/internal/apps/codeserver"
"github.com/acepanel/panel/v3/internal/apps/docker"
"github.com/acepanel/panel/v3/internal/apps/elasticsearch"
"github.com/acepanel/panel/v3/internal/apps/fail2ban"
"github.com/acepanel/panel/v3/internal/apps/frp"
"github.com/acepanel/panel/v3/internal/apps/gitea"
"github.com/acepanel/panel/v3/internal/apps/grafana"
"github.com/acepanel/panel/v3/internal/apps/kafka"
"github.com/acepanel/panel/v3/internal/apps/mariadb"
"github.com/acepanel/panel/v3/internal/apps/memcached"
"github.com/acepanel/panel/v3/internal/apps/minio"
"github.com/acepanel/panel/v3/internal/apps/mongodb"
"github.com/acepanel/panel/v3/internal/apps/mysql"
"github.com/acepanel/panel/v3/internal/apps/nginx"
"github.com/acepanel/panel/v3/internal/apps/openresty"
"github.com/acepanel/panel/v3/internal/apps/opensearch"
"github.com/acepanel/panel/v3/internal/apps/percona"
"github.com/acepanel/panel/v3/internal/apps/phpmyadmin"
"github.com/acepanel/panel/v3/internal/apps/podman"
"github.com/acepanel/panel/v3/internal/apps/postgresql"
"github.com/acepanel/panel/v3/internal/apps/prometheus"
"github.com/acepanel/panel/v3/internal/apps/pureftpd"
"github.com/acepanel/panel/v3/internal/apps/redis"
"github.com/acepanel/panel/v3/internal/apps/rocketmq"
"github.com/acepanel/panel/v3/internal/apps/rsync"
"github.com/acepanel/panel/v3/internal/apps/s3fs"
"github.com/acepanel/panel/v3/internal/apps/supervisor"
"github.com/acepanel/panel/v3/internal/apps/valkey"
"github.com/acepanel/panel/v3/internal/bootstrap"
"github.com/acepanel/panel/v3/internal/data"
"github.com/acepanel/panel/v3/internal/http/middleware"
"github.com/acepanel/panel/v3/internal/job"
"github.com/acepanel/panel/v3/internal/route"
"github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/websitestat"
)
import (
_ "time/tzdata"
)
// Injectors from wire.go:
// initAce init application.
func initAce() (*app.Ace, error) {
config, err := bootstrap.NewConf()
if err != nil {
return nil, err
}
locale, err := bootstrap.NewT(config)
if err != nil {
return nil, err
}
db, err := bootstrap.NewDB(config)
if err != nil {
return nil, err
}
manager, err := bootstrap.NewSession(config, db)
if err != nil {
return nil, err
}
logger := bootstrap.NewLog(config)
cacheRepo := data.NewCacheRepo(db)
taskRunner := bootstrap.NewRunner(db, logger)
taskRepo := data.NewTaskRepo(locale, db, logger, taskRunner)
appRepo := data.NewAppRepo(locale, config, db, logger, cacheRepo, taskRepo)
userTokenRepo := data.NewUserTokenRepo(locale, config, db)
middlewares := middleware.NewMiddlewares(config, manager, appRepo, userTokenRepo)
userRepo := data.NewUserRepo(locale, db, logger)
userService := service.NewUserService(locale, config, manager, userRepo)
userPasskeyRepo := data.NewUserPasskeyRepo(db)
userPasskeyService := service.NewUserPasskeyService(locale, config, manager, userPasskeyRepo, userRepo)
userTokenService := service.NewUserTokenService(locale, userTokenRepo)
databaseServerRepo := data.NewDatabaseServerRepo(locale, db, logger)
databaseUserRepo := data.NewDatabaseUserRepo(locale, db, logger, databaseServerRepo)
databaseRepo := data.NewDatabaseRepo(locale, db, logger, databaseServerRepo, databaseUserRepo)
settingRepo := data.NewSettingRepo(locale, db, logger, config, taskRepo)
certRepo := data.NewCertRepo(locale, db, logger, settingRepo)
certAccountRepo := data.NewCertAccountRepo(locale, db, userRepo, logger)
websiteRepo := data.NewWebsiteRepo(locale, db, logger, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo, settingRepo)
projectRepo := data.NewProjectRepo(locale, db, logger)
environmentRepo := data.NewEnvironmentRepo(locale, config, cacheRepo, taskRepo)
cronRepo := data.NewCronRepo(locale, db, logger)
backupRepo := data.NewBackupRepo(locale, config, db, logger, settingRepo, websiteRepo)
containerRepo := data.NewContainerRepo(settingRepo)
homeService := service.NewHomeService(locale, config, taskRepo, websiteRepo, projectRepo, appRepo, environmentRepo, settingRepo, databaseServerRepo, cronRepo, backupRepo, containerRepo)
taskService := service.NewTaskService(taskRepo)
websiteService := service.NewWebsiteService(websiteRepo, settingRepo)
projectService := service.NewProjectService(projectRepo, settingRepo)
databaseService := service.NewDatabaseService(databaseRepo)
databaseServerService := service.NewDatabaseServerService(databaseServerRepo)
databaseRedisRepo := data.NewDatabaseRedisRepo(locale, db, logger)
databaseRedisService := service.NewDatabaseRedisService(databaseRedisRepo)
databaseElasticsearchRepo := data.NewDatabaseElasticsearchRepo(locale, db, logger)
databaseElasticsearchService := service.NewDatabaseElasticsearchService(databaseElasticsearchRepo)
databaseUserService := service.NewDatabaseUserService(databaseUserRepo)
backupService := service.NewBackupService(locale, backupRepo, taskRepo)
backupAccountRepo := data.NewBackupAccountRepo(locale, db, logger, settingRepo)
backupStorageService := service.NewBackupStorageService(locale, backupAccountRepo)
certService := service.NewCertService(locale, certRepo)
certDNSRepo := data.NewCertDNSRepo(db, logger)
certDNSService := service.NewCertDNSService(certDNSRepo)
certAccountService := service.NewCertAccountService(certAccountRepo)
apacheApp := apache.NewApp(locale)
clickhouseApp := clickhouse.NewApp(locale, settingRepo, databaseServerRepo)
codeserverApp := codeserver.NewApp()
dockerApp := docker.NewApp()
elasticsearchApp := elasticsearch.NewApp(locale)
fail2banApp := fail2ban.NewApp(locale, websiteRepo)
frpApp := frp.NewApp()
giteaApp := gitea.NewApp()
grafanaApp := grafana.NewApp(locale)
kafkaApp := kafka.NewApp(locale)
mariadbApp := mariadb.NewApp(locale, settingRepo, databaseServerRepo)
memcachedApp := memcached.NewApp(locale)
minioApp := minio.NewApp()
mongodbApp := mongodb.NewApp(locale, settingRepo, databaseServerRepo)
mysqlApp := mysql.NewApp(locale, settingRepo, databaseServerRepo)
nginxApp := nginx.NewApp(locale)
openrestyApp := openresty.NewApp(locale)
opensearchApp := opensearch.NewApp(locale)
perconaApp := percona.NewApp(locale, settingRepo, databaseServerRepo)
phpmyadminApp := phpmyadmin.NewApp(locale)
podmanApp := podman.NewApp()
postgresqlApp := postgresql.NewApp(locale, settingRepo, databaseServerRepo)
prometheusApp := prometheus.NewApp(locale, config, taskRepo)
pureftpdApp := pureftpd.NewApp(locale)
redisApp := redis.NewApp(locale, databaseServerRepo)
rocketmqApp := rocketmq.NewApp(locale)
rsyncApp := rsync.NewApp(locale)
s3fsApp := s3fs.NewApp(locale)
supervisorApp := supervisor.NewApp(locale)
valkeyApp := valkey.NewApp(locale, databaseServerRepo)
loader := bootstrap.NewLoader(apacheApp, clickhouseApp, codeserverApp, dockerApp, elasticsearchApp, fail2banApp, frpApp, giteaApp, grafanaApp, kafkaApp, mariadbApp, memcachedApp, minioApp, mongodbApp, mysqlApp, nginxApp, openrestyApp, opensearchApp, perconaApp, phpmyadminApp, podmanApp, postgresqlApp, prometheusApp, pureftpdApp, redisApp, rocketmqApp, rsyncApp, s3fsApp, supervisorApp, valkeyApp)
appService := service.NewAppService(locale, appRepo, cacheRepo, settingRepo, loader)
environmentService := service.NewEnvironmentService(locale, environmentRepo, taskRepo)
environmentGoService := service.NewEnvironmentGoService(locale, environmentRepo)
environmentJavaService := service.NewEnvironmentJavaService(locale, environmentRepo)
environmentNodejsService := service.NewEnvironmentNodejsService(locale, environmentRepo)
environmentPHPService := service.NewEnvironmentPHPService(locale, config, environmentRepo, taskRepo)
environmentPythonService := service.NewEnvironmentPythonService(locale, environmentRepo)
environmentDotnetService := service.NewEnvironmentDotnetService(locale, environmentRepo)
cronService := service.NewCronService(cronRepo)
processService := service.NewProcessService()
safeRepo := data.NewSafeRepo(logger)
safeService := service.NewSafeService(safeRepo)
firewallService := service.NewFirewallService()
scanEventRepo, err := data.NewScanEventRepo(settingRepo)
if err != nil {
return nil, err
}
firewallScanService := service.NewFirewallScanService(scanEventRepo)
sshRepo := data.NewSSHRepo(locale, db, logger)
sshService := service.NewSSHService(sshRepo)
containerService := service.NewContainerService(containerRepo)
containerComposeRepo := data.NewContainerComposeRepo()
containerComposeService := service.NewContainerComposeService(containerComposeRepo)
containerNetworkRepo := data.NewContainerNetworkRepo(settingRepo)
containerNetworkService := service.NewContainerNetworkService(containerNetworkRepo)
containerImageRepo := data.NewContainerImageRepo(settingRepo)
containerImageService := service.NewContainerImageService(containerImageRepo)
containerVolumeRepo := data.NewContainerVolumeRepo(settingRepo)
containerVolumeService := service.NewContainerVolumeService(containerVolumeRepo)
fileService := service.NewFileService(locale, taskRepo, containerRepo)
logRepo := data.NewLogRepo(db)
logService := service.NewLogService(locale, logRepo)
monitorRepo := data.NewMonitorRepo(db, settingRepo)
monitorService := service.NewMonitorService(settingRepo, monitorRepo)
settingService := service.NewSettingService(locale, db, settingRepo, certRepo, certAccountRepo)
systemctlService := service.NewSystemctlService(locale)
toolboxNetworkService := service.NewToolboxNetworkService()
toolboxSystemService := service.NewToolboxSystemService(locale)
toolboxBenchmarkService := service.NewToolboxBenchmarkService(locale)
toolboxSSHService := service.NewToolboxSSHService(locale)
toolboxDiskService := service.NewToolboxDiskService(locale)
toolboxLogService := service.NewToolboxLogService(locale, db, containerImageRepo, settingRepo)
toolboxMigrationService := service.NewToolboxMigrationService(locale, config, logger, settingRepo, websiteRepo, databaseRepo, databaseServerRepo, databaseUserRepo, projectRepo, appRepo, environmentRepo)
webHookRepo := data.NewWebHookRepo(locale, db, logger)
webHookService := service.NewWebHookService(webHookRepo)
templateRepo := data.NewTemplateRepo(locale, logger, cacheRepo)
templateService := service.NewTemplateService(locale, templateRepo, settingRepo)
websiteStatRepo, err := data.NewWebsiteStatRepo()
if err != nil {
return nil, err
}
aggregator := websitestat.NewAggregator()
websiteStatService := service.NewWebsiteStatService(settingRepo, websiteStatRepo, websiteRepo, aggregator)
http := route.NewHttp(config, userService, userPasskeyService, userTokenService, homeService, taskService, websiteService, projectService, databaseService, databaseServerService, databaseRedisService, databaseElasticsearchService, databaseUserService, backupService, backupStorageService, certService, certDNSService, certAccountService, appService, environmentService, environmentGoService, environmentJavaService, environmentNodejsService, environmentPHPService, environmentPythonService, environmentDotnetService, cronService, processService, safeService, firewallService, firewallScanService, sshService, containerService, containerComposeService, containerNetworkService, containerImageService, containerVolumeService, fileService, logService, monitorService, settingService, systemctlService, toolboxNetworkService, toolboxSystemService, toolboxBenchmarkService, toolboxSSHService, toolboxDiskService, toolboxLogService, toolboxMigrationService, webHookService, templateService, websiteStatService, loader)
wsService := service.NewWsService(locale, config, logger, sshRepo, settingRepo, certRepo, backupRepo, taskRepo)
ws := route.NewWs(wsService, toolboxMigrationService)
mux, err := bootstrap.NewRouter(locale, middlewares, http, ws)
if err != nil {
return nil, err
}
reloader, err := bootstrap.NewTLSReloader(config)
if err != nil {
return nil, err
}
server, err := bootstrap.NewHttp(config, mux, reloader)
if err != nil {
return nil, err
}
gormigrate := bootstrap.NewMigrate(db)
jobs := job.NewJobs(config, db, logger, aggregator, settingRepo, certRepo, certAccountRepo, backupRepo, cacheRepo, taskRepo, scanEventRepo, websiteStatRepo, websiteRepo)
cron, err := bootstrap.NewCron(logger, jobs)
if err != nil {
return nil, err
}
validator := service.NewValidator(config, db)
ace := app.NewAce(config, mux, server, reloader, gormigrate, cron, taskRunner, validator)
return ace, nil
}
+26 -11
View File
@@ -1,21 +1,36 @@
package main package main
import ( import (
"errors"
"fmt"
"os" "os"
_ "time/tzdata" _ "time/tzdata"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/injector"
) )
func main() { func main() {
if os.Geteuid() != 0 { if err := run(); err != nil {
panic("panel must run as root") _, _ = fmt.Fprintln(os.Stderr, "Error:", err)
} os.Exit(1)
cli, err := initCli()
if err != nil {
panic(err)
}
if err = cli.Run(); err != nil {
panic(err)
} }
} }
func run() error {
if os.Geteuid() != 0 {
return errors.New("panel must run as root")
}
inj := injector.New()
defer func() { _ = inj.Shutdown() }()
cli, err := do.Invoke[*app.Cli](inj)
if err != nil {
return err
}
return cli.Run()
}
-19
View File
@@ -1,19 +0,0 @@
//go:build wireinject
package main
import (
"github.com/google/wire"
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/apps"
"github.com/acepanel/panel/v3/internal/bootstrap"
"github.com/acepanel/panel/v3/internal/data"
"github.com/acepanel/panel/v3/internal/route"
"github.com/acepanel/panel/v3/internal/service"
)
// initCli init command line.
func initCli() (*app.Cli, error) {
panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, app.NewCli))
}
-119
View File
@@ -1,119 +0,0 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/apps/apache"
"github.com/acepanel/panel/v3/internal/apps/clickhouse"
"github.com/acepanel/panel/v3/internal/apps/codeserver"
"github.com/acepanel/panel/v3/internal/apps/docker"
"github.com/acepanel/panel/v3/internal/apps/elasticsearch"
"github.com/acepanel/panel/v3/internal/apps/fail2ban"
"github.com/acepanel/panel/v3/internal/apps/frp"
"github.com/acepanel/panel/v3/internal/apps/gitea"
"github.com/acepanel/panel/v3/internal/apps/grafana"
"github.com/acepanel/panel/v3/internal/apps/kafka"
"github.com/acepanel/panel/v3/internal/apps/mariadb"
"github.com/acepanel/panel/v3/internal/apps/memcached"
"github.com/acepanel/panel/v3/internal/apps/minio"
"github.com/acepanel/panel/v3/internal/apps/mongodb"
"github.com/acepanel/panel/v3/internal/apps/mysql"
"github.com/acepanel/panel/v3/internal/apps/nginx"
"github.com/acepanel/panel/v3/internal/apps/openresty"
"github.com/acepanel/panel/v3/internal/apps/opensearch"
"github.com/acepanel/panel/v3/internal/apps/percona"
"github.com/acepanel/panel/v3/internal/apps/phpmyadmin"
"github.com/acepanel/panel/v3/internal/apps/podman"
"github.com/acepanel/panel/v3/internal/apps/postgresql"
"github.com/acepanel/panel/v3/internal/apps/prometheus"
"github.com/acepanel/panel/v3/internal/apps/pureftpd"
"github.com/acepanel/panel/v3/internal/apps/redis"
"github.com/acepanel/panel/v3/internal/apps/rocketmq"
"github.com/acepanel/panel/v3/internal/apps/rsync"
"github.com/acepanel/panel/v3/internal/apps/s3fs"
"github.com/acepanel/panel/v3/internal/apps/supervisor"
"github.com/acepanel/panel/v3/internal/apps/valkey"
"github.com/acepanel/panel/v3/internal/bootstrap"
"github.com/acepanel/panel/v3/internal/data"
"github.com/acepanel/panel/v3/internal/route"
"github.com/acepanel/panel/v3/internal/service"
)
import (
_ "time/tzdata"
)
// Injectors from wire.go:
// initCli init command line.
func initCli() (*app.Cli, error) {
config, err := bootstrap.NewConf()
if err != nil {
return nil, err
}
locale, err := bootstrap.NewT(config)
if err != nil {
return nil, err
}
db, err := bootstrap.NewDB(config)
if err != nil {
return nil, err
}
logger := bootstrap.NewLog(config)
cacheRepo := data.NewCacheRepo(db)
taskRunner := bootstrap.NewRunner(db, logger)
taskRepo := data.NewTaskRepo(locale, db, logger, taskRunner)
appRepo := data.NewAppRepo(locale, config, db, logger, cacheRepo, taskRepo)
userRepo := data.NewUserRepo(locale, db, logger)
userPasskeyRepo := data.NewUserPasskeyRepo(db)
settingRepo := data.NewSettingRepo(locale, db, logger, config, taskRepo)
databaseServerRepo := data.NewDatabaseServerRepo(locale, db, logger)
databaseUserRepo := data.NewDatabaseUserRepo(locale, db, logger, databaseServerRepo)
databaseRepo := data.NewDatabaseRepo(locale, db, logger, databaseServerRepo, databaseUserRepo)
certRepo := data.NewCertRepo(locale, db, logger, settingRepo)
certAccountRepo := data.NewCertAccountRepo(locale, db, userRepo, logger)
websiteRepo := data.NewWebsiteRepo(locale, db, logger, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo, settingRepo)
backupRepo := data.NewBackupRepo(locale, config, db, logger, settingRepo, websiteRepo)
cliService := service.NewCliService(locale, config, db, appRepo, cacheRepo, userRepo, userPasskeyRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo, certRepo, certAccountRepo)
cli := route.NewCli(locale, cliService)
command := bootstrap.NewCli(locale, cli)
gormigrate := bootstrap.NewMigrate(db)
apacheApp := apache.NewApp(locale)
clickhouseApp := clickhouse.NewApp(locale, settingRepo, databaseServerRepo)
codeserverApp := codeserver.NewApp()
dockerApp := docker.NewApp()
elasticsearchApp := elasticsearch.NewApp(locale)
fail2banApp := fail2ban.NewApp(locale, websiteRepo)
frpApp := frp.NewApp()
giteaApp := gitea.NewApp()
grafanaApp := grafana.NewApp(locale)
kafkaApp := kafka.NewApp(locale)
mariadbApp := mariadb.NewApp(locale, settingRepo, databaseServerRepo)
memcachedApp := memcached.NewApp(locale)
minioApp := minio.NewApp()
mongodbApp := mongodb.NewApp(locale, settingRepo, databaseServerRepo)
mysqlApp := mysql.NewApp(locale, settingRepo, databaseServerRepo)
nginxApp := nginx.NewApp(locale)
openrestyApp := openresty.NewApp(locale)
opensearchApp := opensearch.NewApp(locale)
perconaApp := percona.NewApp(locale, settingRepo, databaseServerRepo)
phpmyadminApp := phpmyadmin.NewApp(locale)
podmanApp := podman.NewApp()
postgresqlApp := postgresql.NewApp(locale, settingRepo, databaseServerRepo)
prometheusApp := prometheus.NewApp(locale, config, taskRepo)
pureftpdApp := pureftpd.NewApp(locale)
redisApp := redis.NewApp(locale, databaseServerRepo)
rocketmqApp := rocketmq.NewApp(locale)
rsyncApp := rsync.NewApp(locale)
s3fsApp := s3fs.NewApp(locale)
supervisorApp := supervisor.NewApp(locale)
valkeyApp := valkey.NewApp(locale, databaseServerRepo)
loader := bootstrap.NewLoader(apacheApp, clickhouseApp, codeserverApp, dockerApp, elasticsearchApp, fail2banApp, frpApp, giteaApp, grafanaApp, kafkaApp, mariadbApp, memcachedApp, minioApp, mongodbApp, mysqlApp, nginxApp, openrestyApp, opensearchApp, perconaApp, phpmyadminApp, podmanApp, postgresqlApp, prometheusApp, pureftpdApp, redisApp, rocketmqApp, rsyncApp, s3fsApp, supervisorApp, valkeyApp)
appCli := app.NewCli(command, gormigrate, loader)
return appCli, nil
}
+10 -11
View File
@@ -3,7 +3,6 @@ module github.com/acepanel/panel/v3
go 1.26 go 1.26
require ( require (
github.com/DeRuina/timberjack v1.4.5
github.com/andybalholm/brotli v1.2.2 github.com/andybalholm/brotli v1.2.2
github.com/bddjr/hlfhr v1.6.1 github.com/bddjr/hlfhr v1.6.1
github.com/beevik/ntp v1.5.0 github.com/beevik/ntp v1.5.0
@@ -21,7 +20,6 @@ require (
github.com/go-sql-driver/mysql v1.10.0 github.com/go-sql-driver/mysql v1.10.0
github.com/go-webauthn/webauthn v0.17.4 github.com/go-webauthn/webauthn v0.17.4
github.com/gomodule/redigo v1.9.3 github.com/gomodule/redigo v1.9.3
github.com/google/wire v0.7.0
github.com/gookit/color v1.6.1 github.com/gookit/color v1.6.1
github.com/hashicorp/go-version v1.9.0 github.com/hashicorp/go-version v1.9.0
github.com/leonelquinteros/gotext v1.7.2 github.com/leonelquinteros/gotext v1.7.2
@@ -38,12 +36,14 @@ require (
github.com/libdns/westcn v1.0.2 github.com/libdns/westcn v1.0.2
github.com/libtnb/cache v1.2.0 github.com/libtnb/cache v1.2.0
github.com/libtnb/chix v1.3.2 github.com/libtnb/chix v1.3.2
github.com/libtnb/cron v0.2.2 github.com/libtnb/cron v0.5.2
github.com/libtnb/gormstore v1.2.1 github.com/libtnb/gormstore v1.3.0
github.com/libtnb/sessions v1.4.2 github.com/libtnb/logrotate v0.1.2
github.com/libtnb/sqlite v1.1.2 github.com/libtnb/sessions v1.5.0
github.com/libtnb/sqlite v1.2.0
github.com/libtnb/utils v1.2.2 github.com/libtnb/utils v1.2.2
github.com/libtnb/validator v0.2.1 github.com/libtnb/validator v0.4.0
github.com/libtnb/validator/contrib/openapi v0.1.2
github.com/medama-io/go-useragent v1.2.3 github.com/medama-io/go-useragent v1.2.3
github.com/mholt/acmez/v3 v3.1.6 github.com/mholt/acmez/v3 v3.1.6
github.com/moby/moby/api v1.55.0 github.com/moby/moby/api v1.55.0
@@ -51,6 +51,7 @@ require (
github.com/orandin/slog-gorm v1.4.0 github.com/orandin/slog-gorm v1.4.0
github.com/pkg/sftp v1.13.10 github.com/pkg/sftp v1.13.10
github.com/pquerna/otp v1.5.0 github.com/pquerna/otp v1.5.0
github.com/samber/do/v2 v2.0.0
github.com/samber/lo v1.53.0 github.com/samber/lo v1.53.0
github.com/sethvargo/go-limiter v1.1.0 github.com/sethvargo/go-limiter v1.1.0
github.com/shirou/gopsutil/v4 v4.26.6 github.com/shirou/gopsutil/v4 v4.26.6
@@ -99,9 +100,8 @@ require (
github.com/jaevor/go-nanoid v1.4.0 // indirect github.com/jaevor/go-nanoid v1.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/libtnb/securecookie v1.2.0 // indirect github.com/libtnb/securecookie v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
github.com/mattn/go-isatty v0.0.21 // indirect github.com/mattn/go-isatty v0.0.21 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect
@@ -111,6 +111,7 @@ require (
github.com/philhofer/fwd v1.2.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/samber/go-type-to-string v1.8.0 // indirect
github.com/stretchr/objx v0.5.3 // indirect github.com/stretchr/objx v0.5.3 // indirect
github.com/timtadh/data-structures v0.6.2 // indirect github.com/timtadh/data-structures v0.6.2 // indirect
github.com/timtadh/lexmachine v0.2.3 // indirect github.com/timtadh/lexmachine v0.2.3 // indirect
@@ -137,5 +138,3 @@ replace (
github.com/mholt/acmez/v3 => github.com/libtnb/acmez/v3 v3.0.0-20260406165834-a264acd02292 github.com/mholt/acmez/v3 => github.com/libtnb/acmez/v3 v3.0.0-20260406165834-a264acd02292
github.com/stretchr/testify => github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7 github.com/stretchr/testify => github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7
) )
tool github.com/google/wire
+20 -22
View File
@@ -17,8 +17,6 @@ filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DeRuina/timberjack v1.4.5 h1:F/kms5MPNAXUeWdOILt5ALC6iDHWNRPevaeIVH7tqYU=
github.com/DeRuina/timberjack v1.4.5/go.mod h1:RLoeQrwrCGIEF8gO5nV5b/gMD0QIy7bzQhBUgpp1EqE=
github.com/G-Core/gcore-dns-sdk-go v0.3.3 h1:McILJSbJ5nOcT0MI0aBYhEuufCF329YbqKwFIN0RjCI= github.com/G-Core/gcore-dns-sdk-go v0.3.3 h1:McILJSbJ5nOcT0MI0aBYhEuufCF329YbqKwFIN0RjCI=
github.com/G-Core/gcore-dns-sdk-go v0.3.3/go.mod h1:35t795gOfzfVanhzkFyUXEzaBuMXwETmJldPpP28MN4= github.com/G-Core/gcore-dns-sdk-go v0.3.3/go.mod h1:35t795gOfzfVanhzkFyUXEzaBuMXwETmJldPpP28MN4=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
@@ -86,8 +84,6 @@ github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -157,8 +153,6 @@ github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc= github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc=
github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc= github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -167,8 +161,6 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0= github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=
@@ -227,8 +219,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@@ -274,22 +264,26 @@ github.com/libtnb/cache v1.2.0 h1:6MHHRTzP2GgNs1gD9VJoTIeQ3ud20tkkgvbOtzIf0Zs=
github.com/libtnb/cache v1.2.0/go.mod h1:QzCzSS5KBP2dcwMZtwKZO94eFMOViYMkUuxeLallZTE= github.com/libtnb/cache v1.2.0/go.mod h1:QzCzSS5KBP2dcwMZtwKZO94eFMOViYMkUuxeLallZTE=
github.com/libtnb/chix v1.3.2 h1:LkA/+OaHeMyTiQoWEcCQKAMSKDZ0LxBXSENQO5d+OKk= github.com/libtnb/chix v1.3.2 h1:LkA/+OaHeMyTiQoWEcCQKAMSKDZ0LxBXSENQO5d+OKk=
github.com/libtnb/chix v1.3.2/go.mod h1:ItssStBa/ov7v4qujyYzORqIf7Z6DO7Q4carOM7pyAQ= github.com/libtnb/chix v1.3.2/go.mod h1:ItssStBa/ov7v4qujyYzORqIf7Z6DO7Q4carOM7pyAQ=
github.com/libtnb/cron v0.2.2 h1:f7HM3qaoEqFU1Dw1S2UFva1pmxgYOHOPS3Cw2tsbNi0= github.com/libtnb/cron v0.5.2 h1:Yy9a/S82bAS4KzE1SSMjNLtigPkejgMPUp9BHGeb1pw=
github.com/libtnb/cron v0.2.2/go.mod h1:nrOHxS4Ernkn1E//vs64xzC58hGfoL0+lYSW2zsROGI= github.com/libtnb/cron v0.5.2/go.mod h1:nrOHxS4Ernkn1E//vs64xzC58hGfoL0+lYSW2zsROGI=
github.com/libtnb/gormstore v1.2.1 h1:oBRwSsVCa42leVT9GVFP5AzRxtyqj+FhRns9mQwSzEQ= github.com/libtnb/gormstore v1.3.0 h1:OvVTYHZ9MCHI3Anf2ITtJLunAefyBQWG96EmHCE0eLM=
github.com/libtnb/gormstore v1.2.1/go.mod h1:YLsGjjOiUIPhQ6f/ZDb/Vt1ZNI8TXhGZqSzxP1v7vGY= github.com/libtnb/gormstore v1.3.0/go.mod h1:Z/n6VlVdLPmvunSM8sYGNHVebTTN5yUSTZsyNxW2IZc=
github.com/libtnb/securecookie v1.2.0 h1:2uc0PBDm0foeSTrcZ9QTX1IEjf6kFEwfgEYSIXQSKrA= github.com/libtnb/logrotate v0.1.2 h1:q9FLtYQYtzAlOB9bs91nPppqt3GNTUOonrBOivrtiOc=
github.com/libtnb/securecookie v1.2.0/go.mod h1:ja+wNGnQzYqcqXQnJWu6icsaWi5JEBwNEMJ2ReTVDxA= github.com/libtnb/logrotate v0.1.2/go.mod h1:yqC9N3C5mg0fBlquK+cWLB7xG5plQrP0ma84hMRj3ic=
github.com/libtnb/sessions v1.4.2 h1:KEYfuzEW7vtEedwvAZnDWWeW1yMSlwOUfp4hIUirFb8= github.com/libtnb/securecookie v1.4.0 h1:SkKHO7T5I4aRGV7/6fnYYsleQDnnDzeAmTDA0GMPD98=
github.com/libtnb/sessions v1.4.2/go.mod h1:PvxiaI3PCD+kzjPmIrpV3s9e4ACps6OUaXgmKCYlUFo= github.com/libtnb/securecookie v1.4.0/go.mod h1:mg1i9HfstsYBGwCfQdU+3Z1GuieyZRAxbkFUnrzchJU=
github.com/libtnb/sqlite v1.1.2 h1:3g8nez8MwdEhn+oqt3bfKWnYJxk0ZGTO0kVA1WT+hjQ= github.com/libtnb/sessions v1.5.0 h1:gvTRkSR8lpp1PB0Nms/kc+gh1BwJ411fxLjnZLYItLs=
github.com/libtnb/sqlite v1.1.2/go.mod h1:2PGCWOR6HqqXuoIVMmwfJ655epvRO8sw0b9kHWuKNsQ= github.com/libtnb/sessions v1.5.0/go.mod h1:/Q/+lO7DcnJJEU1nL59ScPV/V8ct34F8BjoEMwwxjRw=
github.com/libtnb/sqlite v1.2.0 h1:XsA7jsXHH2qmFkTWoy5YCKJybzHzWQ0flqDFP5Y9Yto=
github.com/libtnb/sqlite v1.2.0/go.mod h1:O6vURH5fa5IgSmXd/qLAL2zSnYFUd7xSIumsmX3BrSI=
github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7 h1:ZzONsNhw69uC/wJQlMj66n1zfsRgKAElfJ//E9G380U= github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7 h1:ZzONsNhw69uC/wJQlMj66n1zfsRgKAElfJ//E9G380U=
github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7/go.mod h1:HeQeTfKU6tj2Lx1z79UacwYeDioo6M4ZD7BDDI6+rrg= github.com/libtnb/testify v0.0.0-20260406170114-25da2dad39e7/go.mod h1:HeQeTfKU6tj2Lx1z79UacwYeDioo6M4ZD7BDDI6+rrg=
github.com/libtnb/utils v1.2.2 h1:HUqgAIb+TIrZPXRytYB5XqzkEXG2U4a4/ZGpprNtL5A= github.com/libtnb/utils v1.2.2 h1:HUqgAIb+TIrZPXRytYB5XqzkEXG2U4a4/ZGpprNtL5A=
github.com/libtnb/utils v1.2.2/go.mod h1:KUCx2+Phw3cLXOwuQDy6XwFOliaYuU1rpAuJQuHf+lQ= github.com/libtnb/utils v1.2.2/go.mod h1:KUCx2+Phw3cLXOwuQDy6XwFOliaYuU1rpAuJQuHf+lQ=
github.com/libtnb/validator v0.2.1 h1:ZbFx7bEXB9ri0Eb7p81LOSAq0M+VrizDR4aD06TcCvg= github.com/libtnb/validator v0.4.0 h1:2IgL89ci1WGH1EakxwfWO/VQadXqpmii9IWaIkkPpVg=
github.com/libtnb/validator v0.2.1/go.mod h1:j08Lydxwy7ModkoKeYIHxvZvAtnzzdE8xi2J+SGVrgc= github.com/libtnb/validator v0.4.0/go.mod h1:j08Lydxwy7ModkoKeYIHxvZvAtnzzdE8xi2J+SGVrgc=
github.com/libtnb/validator/contrib/openapi v0.1.2 h1:erwPcaSceamwnkBdyKKAFLu5irkaGuZRSNu7OyiMDpE=
github.com/libtnb/validator/contrib/openapi v0.1.2/go.mod h1:3z0diS6h42GzBvJ4nUjuzXQ0dvqhtliBRZd1Bx6un9o=
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -367,6 +361,10 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samber/do/v2 v2.0.0 h1:tnunwWaoqSfJ9hxVIaJawIo7JXHQlqT9d9YBXlE9Keg=
github.com/samber/do/v2 v2.0.0/go.mod h1:ZSBCE7Xr6nTNIOVo4DBrkl2+ydUbIOzJjjdV8En5XO4=
github.com/samber/go-type-to-string v1.8.0 h1:5z6tDTjtXxkIAoAuHAZYMYR8mkBZjVgeSH7jcSLqc8w=
github.com/samber/go-type-to-string v1.8.0/go.mod h1:jpU77vIDoIxkahknKDoEx9C8bQ1ADnh2sotZ8I4QqBU=
github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM= github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM=
github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+10 -10
View File
@@ -14,7 +14,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-gormigrate/gormigrate/v2" "github.com/go-gormigrate/gormigrate/v2"
"github.com/libtnb/cron" "github.com/libtnb/cron"
"github.com/libtnb/validator" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
"github.com/acepanel/panel/v3/pkg/tlscert" "github.com/acepanel/panel/v3/pkg/tlscert"
@@ -31,16 +31,16 @@ type Ace struct {
runner types.TaskRunner runner types.TaskRunner
} }
func NewAce(conf *config.Config, router *chi.Mux, server *hlfhr.Server, reloader *tlscert.Reloader, migrator *gormigrate.Gormigrate, cron *cron.Cron, runner types.TaskRunner, _ *validator.Validator) *Ace { func NewAce(i do.Injector) (*Ace, error) {
return &Ace{ return &Ace{
conf: conf, conf: do.MustInvoke[*config.Config](i),
router: router, router: do.MustInvoke[*chi.Mux](i),
server: server, server: do.MustInvoke[*hlfhr.Server](i),
reloader: reloader, reloader: do.MustInvoke[*tlscert.Reloader](i),
migrator: migrator, migrator: do.MustInvoke[*gormigrate.Gormigrate](i),
cron: cron, cron: do.MustInvoke[*cron.Cron](i),
runner: runner, runner: do.MustInvoke[types.TaskRunner](i),
} }, nil
} }
func (r *Ace) Run() error { func (r *Ace) Run() error {
+6 -4
View File
@@ -6,6 +6,7 @@ import (
"github.com/go-gormigrate/gormigrate/v2" "github.com/go-gormigrate/gormigrate/v2"
"github.com/gookit/color" "github.com/gookit/color"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/pkg/apploader" "github.com/acepanel/panel/v3/pkg/apploader"
@@ -16,12 +17,13 @@ type Cli struct {
migrator *gormigrate.Gormigrate migrator *gormigrate.Gormigrate
} }
func NewCli(cmd *cli.Command, migrator *gormigrate.Gormigrate, _ *apploader.Loader) *Cli { func NewCli(i do.Injector) (*Cli, error) {
IsCli = true IsCli = true
_ = do.MustInvoke[*apploader.Loader](i) // 强制构造 loader,触发全局应用注册
return &Cli{ return &Cli{
cmd: cmd, cmd: do.MustInvoke[*cli.Command](i),
migrator: migrator, migrator: do.MustInvoke[*gormigrate.Gormigrate](i),
} }, nil
} }
func (r *Cli) Run() error { func (r *Cli) Run() error {
+68
View File
@@ -0,0 +1,68 @@
package app_test
import (
"os"
"path/filepath"
"testing"
"github.com/samber/do/v2"
"github.com/stretchr/testify/require"
"github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/command"
"github.com/acepanel/panel/v3/internal/injector"
"github.com/acepanel/panel/v3/internal/job"
"github.com/acepanel/panel/v3/internal/registry"
"github.com/acepanel/panel/v3/internal/route"
)
// TestContainer 构建完整对象图,在测试期而非启动期暴露装配错误
func TestContainer(t *testing.T) {
tmp := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(tmp, "panel/storage/logs"), 0o755))
// 写入临时配置并经 PANEL_CONFIG 指向,避免读取 /opt/ace
cfg := filepath.Join(tmp, "config.yml")
content := "app:\n" +
" debug: true\n" +
" key: 12345678901234567890123456789012\n" +
" locale: zh_CN\n" +
" timezone: UTC\n" +
" root: " + tmp + "\n" +
"http:\n" +
" port: 8888\n" +
" tls: \"off\"\n" +
"database: {}\n" +
"session:\n" +
" lifetime: 120\n"
require.NoError(t, os.WriteFile(cfg, []byte(content), 0o600))
t.Setenv("PANEL_CONFIG", cfg)
inj := injector.New()
defer func() { _ = inj.Shutdown() }()
// 构造两个入口即触发全图:路由 + SpecJSON + cron 注册(5 段表达式)+ nil 证书重载器
_, err := do.Invoke[*app.Ace](inj)
require.NoError(t, err)
_, err = do.Invoke[*app.Cli](inj)
require.NoError(t, err)
// 每个带冒号的命名贡献必须命中已知前缀(拼错如 route:user 会被静默丢弃)
require.NoError(t, registry.Verify(inj, route.RoutePrefix, command.Prefix, job.Prefix))
routes, err := registry.Collect[route.Endpoints](inj, route.RoutePrefix)
require.NoError(t, err)
require.NotEmpty(t, routes)
cmds, err := command.Commands(inj)
require.NoError(t, err)
require.NotEmpty(t, cmds)
jobs, err := registry.Collect[job.JobFn](inj, job.Prefix)
require.NoError(t, err)
require.NotEmpty(t, jobs)
spec, err := route.SpecJSON(inj, "AcePanel")
require.NoError(t, err)
require.NotEmpty(t, spec)
}
+4 -3
View File
@@ -7,6 +7,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -22,10 +23,10 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+12 -32
View File
@@ -1,7 +1,7 @@
package apps package apps
import ( import (
"github.com/google/wire" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/apps/apache" "github.com/acepanel/panel/v3/internal/apps/apache"
"github.com/acepanel/panel/v3/internal/apps/clickhouse" "github.com/acepanel/panel/v3/internal/apps/clickhouse"
@@ -35,35 +35,15 @@ import (
"github.com/acepanel/panel/v3/internal/apps/valkey" "github.com/acepanel/panel/v3/internal/apps/valkey"
) )
var ProviderSet = wire.NewSet( var Package = do.Package(
apache.NewApp, do.Lazy(apache.NewApp), do.Lazy(clickhouse.NewApp), do.Lazy(codeserver.NewApp),
clickhouse.NewApp, do.Lazy(docker.NewApp), do.Lazy(elasticsearch.NewApp), do.Lazy(fail2ban.NewApp),
codeserver.NewApp, do.Lazy(frp.NewApp), do.Lazy(gitea.NewApp), do.Lazy(grafana.NewApp),
docker.NewApp, do.Lazy(kafka.NewApp), do.Lazy(mariadb.NewApp), do.Lazy(memcached.NewApp),
elasticsearch.NewApp, do.Lazy(minio.NewApp), do.Lazy(mongodb.NewApp), do.Lazy(mysql.NewApp),
fail2ban.NewApp, do.Lazy(nginx.NewApp), do.Lazy(openresty.NewApp), do.Lazy(opensearch.NewApp),
frp.NewApp, do.Lazy(percona.NewApp), do.Lazy(phpmyadmin.NewApp), do.Lazy(podman.NewApp),
gitea.NewApp, do.Lazy(postgresql.NewApp), do.Lazy(prometheus.NewApp), do.Lazy(pureftpd.NewApp),
grafana.NewApp, do.Lazy(redis.NewApp), do.Lazy(rocketmq.NewApp), do.Lazy(rsync.NewApp),
kafka.NewApp, do.Lazy(s3fs.NewApp), do.Lazy(supervisor.NewApp), do.Lazy(valkey.NewApp),
mariadb.NewApp,
memcached.NewApp,
minio.NewApp,
mongodb.NewApp,
mysql.NewApp,
nginx.NewApp,
openresty.NewApp,
opensearch.NewApp,
percona.NewApp,
phpmyadmin.NewApp,
podman.NewApp,
postgresql.NewApp,
prometheus.NewApp,
pureftpd.NewApp,
redis.NewApp,
rocketmq.NewApp,
rsync.NewApp,
s3fs.NewApp,
supervisor.NewApp,
valkey.NewApp,
) )
+6 -5
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
"resty.dev/v3" "resty.dev/v3"
@@ -27,12 +28,12 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
settingRepo: setting, settingRepo: do.MustInvoke[biz.SettingRepo](i),
databaseServerRepo: databaseServer, databaseServerRepo: do.MustInvoke[biz.DatabaseServerRepo](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -13,8 +14,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -7,6 +7,7 @@ import (
"strings" "strings"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -16,8 +17,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
"resty.dev/v3" "resty.dev/v3"
@@ -25,8 +26,8 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t} return &App{t: do.MustInvoke[*gotext.Locale](i)}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+5 -4
View File
@@ -10,6 +10,7 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/libtnb/utils/str" "github.com/libtnb/utils/str"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/spf13/cast" "github.com/spf13/cast"
@@ -27,11 +28,11 @@ type App struct {
websiteRepo biz.WebsiteRepo websiteRepo biz.WebsiteRepo
} }
func NewApp(t *gotext.Locale, website biz.WebsiteRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
websiteRepo: website, websiteRepo: do.MustInvoke[biz.WebsiteRepo](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
@@ -15,8 +16,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
@@ -15,8 +16,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
"resty.dev/v3" "resty.dev/v3"
@@ -24,8 +25,8 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t} return &App{t: do.MustInvoke[*gotext.Locale](i)}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
@@ -20,8 +21,8 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t} return &App{t: do.MustInvoke[*gotext.Locale](i)}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+8 -5
View File
@@ -2,20 +2,23 @@ package mariadb
import ( import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/apps/mysql" "github.com/acepanel/panel/v3/internal/apps/mysql"
"github.com/acepanel/panel/v3/internal/biz"
) )
type App struct { type App struct {
mysql *mysql.App mysql *mysql.App
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ app, err := mysql.NewApp(i)
mysql: mysql.NewApp(t, setting, databaseServer), if err != nil {
return nil, err
} }
return &App{
mysql: app,
}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -3
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -20,10 +21,10 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -13,8 +14,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+6 -5
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
@@ -26,12 +27,12 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
settingRepo: setting, settingRepo: do.MustInvoke[biz.SettingRepo](i),
databaseServerRepo: databaseServer, databaseServerRepo: do.MustInvoke[biz.DatabaseServerRepo](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+6 -5
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -28,12 +29,12 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
t: t, t: do.MustInvoke[*gotext.Locale](i),
settingRepo: setting, settingRepo: do.MustInvoke[biz.SettingRepo](i),
databaseServerRepo: databaseServer, databaseServerRepo: do.MustInvoke[biz.DatabaseServerRepo](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"resty.dev/v3" "resty.dev/v3"
@@ -25,10 +26,11 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &App{ return &App{
t: t, t: t,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -4
View File
@@ -2,7 +2,7 @@ package openresty
import ( import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/apps/nginx" "github.com/acepanel/panel/v3/internal/apps/nginx"
"github.com/acepanel/panel/v3/pkg/systemctl" "github.com/acepanel/panel/v3/pkg/systemctl"
@@ -13,10 +13,10 @@ type App struct {
nginx *nginx.App nginx *nginx.App
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
nginx: nginx.NewApp(t), nginx: do.MustInvoke[*nginx.App](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
"resty.dev/v3" "resty.dev/v3"
@@ -25,8 +26,9 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t} t := do.MustInvoke[*gotext.Locale](i)
return &App{t: t}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -5
View File
@@ -2,20 +2,19 @@ package percona
import ( import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/apps/mysql" "github.com/acepanel/panel/v3/internal/apps/mysql"
"github.com/acepanel/panel/v3/internal/biz"
) )
type App struct { type App struct {
mysql *mysql.App mysql *mysql.App
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{ return &App{
mysql: mysql.NewApp(t, setting, databaseServer), mysql: do.MustInvoke[*mysql.App](i),
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -25,10 +26,11 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &App{ return &App{
t: t, t: t,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -13,8 +14,8 @@ import (
type App struct{} type App struct{}
func NewApp() *App { func NewApp(i do.Injector) (*App, error) {
return &App{} return &App{}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+6 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -27,12 +28,15 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, setting biz.SettingRepo, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
setting := do.MustInvoke[biz.SettingRepo](i)
databaseServer := do.MustInvoke[biz.DatabaseServerRepo](i)
return &App{ return &App{
t: t, t: t,
settingRepo: setting, settingRepo: setting,
databaseServerRepo: databaseServer, databaseServerRepo: databaseServer,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+6 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
@@ -29,8 +30,11 @@ type App struct {
taskRepo biz.TaskRepo taskRepo biz.TaskRepo
} }
func NewApp(t *gotext.Locale, conf *config.Config, taskRepo biz.TaskRepo) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t, conf: conf, taskRepo: taskRepo} t := do.MustInvoke[*gotext.Locale](i)
conf := do.MustInvoke[*config.Config](i)
taskRepo := do.MustInvoke[biz.TaskRepo](i)
return &App{t: t, conf: conf, taskRepo: taskRepo}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/spf13/cast" "github.com/spf13/cast"
@@ -25,10 +26,11 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &App{ return &App{
t: t, t: t,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+5 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -24,11 +25,13 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
databaseServer := do.MustInvoke[biz.DatabaseServerRepo](i)
return &App{ return &App{
t: t, t: t,
databaseServerRepo: databaseServer, databaseServerRepo: databaseServer,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
@@ -20,8 +21,9 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
return &App{t: t} t := do.MustInvoke[*gotext.Locale](i)
return &App{t: t}, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/libtnb/utils/str" "github.com/libtnb/utils/str"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
"github.com/acepanel/panel/v3/pkg/io" "github.com/acepanel/panel/v3/pkg/io"
@@ -22,10 +23,11 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &App{ return &App{
t: t, t: t,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/spf13/cast" "github.com/spf13/cast"
@@ -23,10 +24,11 @@ type App struct {
t *gotext.Locale t *gotext.Locale
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &App{ return &App{
t: t, t: t,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+4 -2
View File
@@ -7,6 +7,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/chix" "github.com/libtnb/chix"
"github.com/samber/do/v2"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/acepanel/panel/v3/internal/service" "github.com/acepanel/panel/v3/internal/service"
@@ -22,7 +23,8 @@ type App struct {
name string name string
} }
func NewApp(t *gotext.Locale) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
var name string var name string
if os.IsRHEL() { if os.IsRHEL() {
name = "supervisord" name = "supervisord"
@@ -33,7 +35,7 @@ func NewApp(t *gotext.Locale) *App {
return &App{ return &App{
t: t, t: t,
name: name, name: name,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+5 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -24,11 +25,13 @@ type App struct {
databaseServerRepo biz.DatabaseServerRepo databaseServerRepo biz.DatabaseServerRepo
} }
func NewApp(t *gotext.Locale, databaseServer biz.DatabaseServerRepo) *App { func NewApp(i do.Injector) (*App, error) {
t := do.MustInvoke[*gotext.Locale](i)
databaseServer := do.MustInvoke[biz.DatabaseServerRepo](i)
return &App{ return &App{
t: t, t: t,
databaseServerRepo: databaseServer, databaseServerRepo: databaseServer,
} }, nil
} }
func (s *App) Route(r chi.Router) { func (s *App) Route(r chi.Router) {
+64
View File
@@ -34,3 +34,67 @@ type AppRepo interface {
UpdateShow(slug string, show bool) error UpdateShow(slug string, show bool) error
UpdateOrder(slugs []string) error UpdateOrder(slugs []string) error
} }
type AppUsecase struct {
repo AppRepo
}
func NewAppUsecase(repo AppRepo) *AppUsecase {
return &AppUsecase{repo: repo}
}
func (uc *AppUsecase) Categories() []types.LV {
return uc.repo.Categories()
}
func (uc *AppUsecase) All() api.Apps {
return uc.repo.All()
}
func (uc *AppUsecase) Get(slug string) (*api.App, error) {
return uc.repo.Get(slug)
}
func (uc *AppUsecase) UpdateExist(slug string) bool {
return uc.repo.UpdateExist(slug)
}
func (uc *AppUsecase) Installed() ([]*App, error) {
return uc.repo.Installed()
}
func (uc *AppUsecase) GetInstalled(slug string) (*App, error) {
return uc.repo.GetInstalled(slug)
}
func (uc *AppUsecase) GetInstalledAll(query string, cond ...string) ([]*App, error) {
return uc.repo.GetInstalledAll(query, cond...)
}
func (uc *AppUsecase) GetHomeShow() ([]map[string]string, error) {
return uc.repo.GetHomeShow()
}
func (uc *AppUsecase) IsInstalled(query string, cond ...any) (bool, error) {
return uc.repo.IsInstalled(query, cond...)
}
func (uc *AppUsecase) Install(channel, slug string) error {
return uc.repo.Install(channel, slug)
}
func (uc *AppUsecase) UnInstall(slug string) error {
return uc.repo.UnInstall(slug)
}
func (uc *AppUsecase) Update(slug string) error {
return uc.repo.Update(slug)
}
func (uc *AppUsecase) UpdateShow(slug string, show bool) error {
return uc.repo.UpdateShow(slug, show)
}
func (uc *AppUsecase) UpdateOrder(slugs []string) error {
return uc.repo.UpdateOrder(slugs)
}
+56
View File
@@ -33,3 +33,59 @@ type BackupRepo interface {
FixPanel() error FixPanel() error
UpdatePanel(version, url, checksum string, progress func(string)) error UpdatePanel(version, url, checksum string, progress func(string)) error
} }
type BackupUsecase struct {
repo BackupRepo
}
func NewBackupUsecase(repo BackupRepo) *BackupUsecase {
return &BackupUsecase{repo: repo}
}
func (uc *BackupUsecase) List(typ BackupType) ([]*types.BackupFile, error) {
return uc.repo.List(typ)
}
func (uc *BackupUsecase) Create(ctx context.Context, typ BackupType, target string, account uint) error {
return uc.repo.Create(ctx, typ, target, account)
}
func (uc *BackupUsecase) CreatePanel() error {
return uc.repo.CreatePanel()
}
func (uc *BackupUsecase) Delete(ctx context.Context, typ BackupType, name string) error {
return uc.repo.Delete(ctx, typ, name)
}
func (uc *BackupUsecase) Restore(ctx context.Context, typ BackupType, backup, target string) error {
return uc.repo.Restore(ctx, typ, backup, target)
}
func (uc *BackupUsecase) ClearExpired(path, prefix string, save uint) error {
return uc.repo.ClearExpired(path, prefix, save)
}
func (uc *BackupUsecase) ClearStorageExpired(account uint, typ BackupType, prefix string, save uint) error {
return uc.repo.ClearStorageExpired(account, typ, prefix, save)
}
func (uc *BackupUsecase) CutoffLog(path, target string) (string, error) {
return uc.repo.CutoffLog(path, target)
}
func (uc *BackupUsecase) CutoffUpload(account uint, typ BackupType, name string, files []string) error {
return uc.repo.CutoffUpload(account, typ, name, files)
}
func (uc *BackupUsecase) GetDefaultPath(typ BackupType) string {
return uc.repo.GetDefaultPath(typ)
}
func (uc *BackupUsecase) FixPanel() error {
return uc.repo.FixPanel()
}
func (uc *BackupUsecase) UpdatePanel(version, url, checksum string, progress func(string)) error {
return uc.repo.UpdatePanel(version, url, checksum, progress)
}
+29 -1
View File
@@ -8,7 +8,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -135,3 +135,31 @@ type BackupAccountRepo interface {
Update(ctx context.Context, req *request.BackupStorageUpdate) error Update(ctx context.Context, req *request.BackupStorageUpdate) error
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
} }
type BackupAccountUsecase struct {
repo BackupAccountRepo
}
func NewBackupAccountUsecase(repo BackupAccountRepo) *BackupAccountUsecase {
return &BackupAccountUsecase{repo: repo}
}
func (uc *BackupAccountUsecase) List(page, limit uint) ([]*BackupStorage, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *BackupAccountUsecase) Get(id uint) (*BackupStorage, error) {
return uc.repo.Get(id)
}
func (uc *BackupAccountUsecase) Create(ctx context.Context, req *request.BackupStorageCreate) (*BackupStorage, error) {
return uc.repo.Create(ctx, req)
}
func (uc *BackupAccountUsecase) Update(ctx context.Context, req *request.BackupStorageUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *BackupAccountUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
+22
View File
@@ -0,0 +1,22 @@
package biz
import (
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/registry"
)
var Package = do.Package(
registry.Lazy(NewAppUsecase), registry.Lazy(NewBackupUsecase), registry.Lazy(NewBackupAccountUsecase),
registry.Lazy(NewCacheUsecase), registry.Lazy(NewCertUsecase), registry.Lazy(NewCertAccountUsecase),
registry.Lazy(NewCertDNSUsecase), registry.Lazy(NewContainerUsecase), registry.Lazy(NewContainerComposeUsecase),
registry.Lazy(NewContainerImageUsecase), registry.Lazy(NewContainerNetworkUsecase), registry.Lazy(NewContainerVolumeUsecase),
registry.Lazy(NewCronUsecase), registry.Lazy(NewDatabaseUsecase), registry.Lazy(NewDatabaseRedisUsecase),
registry.Lazy(NewDatabaseElasticsearchUsecase), registry.Lazy(NewDatabaseServerUsecase), registry.Lazy(NewDatabaseUserUsecase),
registry.Lazy(NewEnvironmentUsecase), registry.Lazy(NewLogUsecase), registry.Lazy(NewMonitorUsecase),
registry.Lazy(NewProjectUsecase), registry.Lazy(NewSafeUsecase), registry.Lazy(NewScanEventUsecase),
registry.Lazy(NewSettingUsecase), registry.Lazy(NewSSHUsecase), registry.Lazy(NewTaskUsecase),
registry.Lazy(NewTemplateUsecase), registry.Lazy(NewUserUsecase), registry.Lazy(NewUserPasskeyUsecase),
registry.Lazy(NewUserTokenUsecase), registry.Lazy(NewWebHookUsecase), registry.Lazy(NewWebsiteUsecase),
registry.Lazy(NewWebsiteStatUsecase),
)
+32
View File
@@ -26,3 +26,35 @@ type CacheRepo interface {
UpdateEnvironments() error UpdateEnvironments() error
UpdateTemplates() error UpdateTemplates() error
} }
type CacheUsecase struct {
repo CacheRepo
}
func NewCacheUsecase(repo CacheRepo) *CacheUsecase {
return &CacheUsecase{repo: repo}
}
func (uc *CacheUsecase) Get(key CacheKey, defaultValue ...string) (string, error) {
return uc.repo.Get(key, defaultValue...)
}
func (uc *CacheUsecase) Set(key CacheKey, value string) error {
return uc.repo.Set(key, value)
}
func (uc *CacheUsecase) UpdateCategories() error {
return uc.repo.UpdateCategories()
}
func (uc *CacheUsecase) UpdateApps() error {
return uc.repo.UpdateApps()
}
func (uc *CacheUsecase) UpdateEnvironments() error {
return uc.repo.UpdateEnvironments()
}
func (uc *CacheUsecase) UpdateTemplates() error {
return uc.repo.UpdateTemplates()
}
+69 -1
View File
@@ -6,7 +6,7 @@ import (
mholtacme "github.com/mholt/acmez/v3/acme" mholtacme "github.com/mholt/acmez/v3/acme"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/acme" "github.com/acepanel/panel/v3/pkg/acme"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -50,3 +50,71 @@ type CertRepo interface {
RefreshRenewalInfo(id uint) (mholtacme.RenewalInfo, error) RefreshRenewalInfo(id uint) (mholtacme.RenewalInfo, error)
Deploy(ID, WebsiteID uint, enableHTTPS bool) error Deploy(ID, WebsiteID uint, enableHTTPS bool) error
} }
type CertUsecase struct {
repo CertRepo
}
func NewCertUsecase(repo CertRepo) *CertUsecase {
return &CertUsecase{repo: repo}
}
func (uc *CertUsecase) List(page, limit uint) ([]*types.CertList, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *CertUsecase) Get(id uint) (*Cert, error) {
return uc.repo.Get(id)
}
func (uc *CertUsecase) GetByWebsite(WebsiteID uint) (*Cert, error) {
return uc.repo.GetByWebsite(WebsiteID)
}
func (uc *CertUsecase) Upload(ctx context.Context, req *request.CertUpload) (*Cert, error) {
return uc.repo.Upload(ctx, req)
}
func (uc *CertUsecase) Create(ctx context.Context, req *request.CertCreate) (*Cert, error) {
return uc.repo.Create(ctx, req)
}
func (uc *CertUsecase) Update(ctx context.Context, req *request.CertUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *CertUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
func (uc *CertUsecase) ObtainAuto(id uint) (*acme.Certificate, error) {
return uc.repo.ObtainAuto(id)
}
func (uc *CertUsecase) ObtainAutoWithProgressCallback(ctx context.Context, id uint, progressCallback func(string)) (*acme.Certificate, error) {
return uc.repo.ObtainAutoWithProgressCallback(ctx, id, progressCallback)
}
func (uc *CertUsecase) ObtainPanel(account *CertAccount, ips []string) ([]byte, []byte, error) {
return uc.repo.ObtainPanel(account, ips)
}
func (uc *CertUsecase) ObtainSelfSigned(id uint) error {
return uc.repo.ObtainSelfSigned(id)
}
func (uc *CertUsecase) Renew(id uint) (*acme.Certificate, error) {
return uc.repo.Renew(id)
}
func (uc *CertUsecase) RenewWithProgressCallback(ctx context.Context, id uint, progressCallback func(string)) (*acme.Certificate, error) {
return uc.repo.RenewWithProgressCallback(ctx, id, progressCallback)
}
func (uc *CertUsecase) RefreshRenewalInfo(id uint) (mholtacme.RenewalInfo, error) {
return uc.repo.RefreshRenewalInfo(id)
}
func (uc *CertUsecase) Deploy(ID, WebsiteID uint, enableHTTPS bool) error {
return uc.repo.Deploy(ID, WebsiteID, enableHTTPS)
}
+33 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type CertAccount struct { type CertAccount struct {
@@ -29,3 +29,35 @@ type CertAccountRepo interface {
Update(ctx context.Context, req *request.CertAccountUpdate) error Update(ctx context.Context, req *request.CertAccountUpdate) error
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
} }
type CertAccountUsecase struct {
repo CertAccountRepo
}
func NewCertAccountUsecase(repo CertAccountRepo) *CertAccountUsecase {
return &CertAccountUsecase{repo: repo}
}
func (uc *CertAccountUsecase) List(page, limit uint) ([]*CertAccount, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *CertAccountUsecase) GetDefault(userID uint) (*CertAccount, error) {
return uc.repo.GetDefault(userID)
}
func (uc *CertAccountUsecase) Get(id uint) (*CertAccount, error) {
return uc.repo.Get(id)
}
func (uc *CertAccountUsecase) Create(ctx context.Context, req *request.CertAccountCreate) (*CertAccount, error) {
return uc.repo.Create(ctx, req)
}
func (uc *CertAccountUsecase) Update(ctx context.Context, req *request.CertAccountUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *CertAccountUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
+29 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/acme" "github.com/acepanel/panel/v3/pkg/acme"
) )
@@ -26,3 +26,31 @@ type CertDNSRepo interface {
Update(ctx context.Context, req *request.CertDNSUpdate) error Update(ctx context.Context, req *request.CertDNSUpdate) error
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
} }
type CertDNSUsecase struct {
repo CertDNSRepo
}
func NewCertDNSUsecase(repo CertDNSRepo) *CertDNSUsecase {
return &CertDNSUsecase{repo: repo}
}
func (uc *CertDNSUsecase) List(page, limit uint) ([]*CertDNS, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *CertDNSUsecase) Get(id uint) (*CertDNS, error) {
return uc.repo.Get(id)
}
func (uc *CertDNSUsecase) Create(ctx context.Context, req *request.CertDNSCreate) (*CertDNS, error) {
return uc.repo.Create(ctx, req)
}
func (uc *CertDNSUsecase) Update(ctx context.Context, req *request.CertDNSUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *CertDNSUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
+61 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -20,3 +20,63 @@ type ContainerRepo interface {
Logs(id string, tail int) (string, error) Logs(id string, tail int) (string, error)
Prune() error Prune() error
} }
type ContainerUsecase struct {
repo ContainerRepo
}
func NewContainerUsecase(repo ContainerRepo) *ContainerUsecase {
return &ContainerUsecase{repo: repo}
}
func (uc *ContainerUsecase) ListAll() ([]types.Container, error) {
return uc.repo.ListAll()
}
func (uc *ContainerUsecase) ListByName(name string) ([]types.Container, error) {
return uc.repo.ListByName(name)
}
func (uc *ContainerUsecase) Create(req *request.ContainerCreate) (string, error) {
return uc.repo.Create(req)
}
func (uc *ContainerUsecase) Remove(id string) error {
return uc.repo.Remove(id)
}
func (uc *ContainerUsecase) Start(id string) error {
return uc.repo.Start(id)
}
func (uc *ContainerUsecase) Stop(id string) error {
return uc.repo.Stop(id)
}
func (uc *ContainerUsecase) Restart(id string) error {
return uc.repo.Restart(id)
}
func (uc *ContainerUsecase) Pause(id string) error {
return uc.repo.Pause(id)
}
func (uc *ContainerUsecase) Unpause(id string) error {
return uc.repo.Unpause(id)
}
func (uc *ContainerUsecase) Kill(id string) error {
return uc.repo.Kill(id)
}
func (uc *ContainerUsecase) Rename(id string, newName string) error {
return uc.repo.Rename(id, newName)
}
func (uc *ContainerUsecase) Logs(id string, tail int) (string, error) {
return uc.repo.Logs(id, tail)
}
func (uc *ContainerUsecase) Prune() error {
return uc.repo.Prune()
}
+36
View File
@@ -11,3 +11,39 @@ type ContainerComposeRepo interface {
Down(name string) error Down(name string) error
Remove(name string) error Remove(name string) error
} }
type ContainerComposeUsecase struct {
repo ContainerComposeRepo
}
func NewContainerComposeUsecase(repo ContainerComposeRepo) *ContainerComposeUsecase {
return &ContainerComposeUsecase{repo: repo}
}
func (uc *ContainerComposeUsecase) List() ([]types.ContainerCompose, error) {
return uc.repo.List()
}
func (uc *ContainerComposeUsecase) Get(name string) (string, []types.KV, error) {
return uc.repo.Get(name)
}
func (uc *ContainerComposeUsecase) Create(name, compose string, envs []types.KV) error {
return uc.repo.Create(name, compose, envs)
}
func (uc *ContainerComposeUsecase) Update(name, compose string, envs []types.KV) error {
return uc.repo.Update(name, compose, envs)
}
func (uc *ContainerComposeUsecase) Up(name string, force bool) error {
return uc.repo.Up(name, force)
}
func (uc *ContainerComposeUsecase) Down(name string) error {
return uc.repo.Down(name)
}
func (uc *ContainerComposeUsecase) Remove(name string) error {
return uc.repo.Remove(name)
}
+29 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -12,3 +12,31 @@ type ContainerImageRepo interface {
Remove(id string) error Remove(id string) error
Prune() error Prune() error
} }
type ContainerImageUsecase struct {
repo ContainerImageRepo
}
func NewContainerImageUsecase(repo ContainerImageRepo) *ContainerImageUsecase {
return &ContainerImageUsecase{repo: repo}
}
func (uc *ContainerImageUsecase) List() ([]types.ContainerImage, error) {
return uc.repo.List()
}
func (uc *ContainerImageUsecase) Exist(name string) (bool, error) {
return uc.repo.Exist(name)
}
func (uc *ContainerImageUsecase) Pull(req *request.ContainerImagePull) error {
return uc.repo.Pull(req)
}
func (uc *ContainerImageUsecase) Remove(id string) error {
return uc.repo.Remove(id)
}
func (uc *ContainerImageUsecase) Prune() error {
return uc.repo.Prune()
}
+25 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -11,3 +11,27 @@ type ContainerNetworkRepo interface {
Remove(id string) error Remove(id string) error
Prune() error Prune() error
} }
type ContainerNetworkUsecase struct {
repo ContainerNetworkRepo
}
func NewContainerNetworkUsecase(repo ContainerNetworkRepo) *ContainerNetworkUsecase {
return &ContainerNetworkUsecase{repo: repo}
}
func (uc *ContainerNetworkUsecase) List() ([]types.ContainerNetwork, error) {
return uc.repo.List()
}
func (uc *ContainerNetworkUsecase) Create(req *request.ContainerNetworkCreate) (string, error) {
return uc.repo.Create(req)
}
func (uc *ContainerNetworkUsecase) Remove(id string) error {
return uc.repo.Remove(id)
}
func (uc *ContainerNetworkUsecase) Prune() error {
return uc.repo.Prune()
}
+25 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -11,3 +11,27 @@ type ContainerVolumeRepo interface {
Remove(id string) error Remove(id string) error
Prune() error Prune() error
} }
type ContainerVolumeUsecase struct {
repo ContainerVolumeRepo
}
func NewContainerVolumeUsecase(repo ContainerVolumeRepo) *ContainerVolumeUsecase {
return &ContainerVolumeUsecase{repo: repo}
}
func (uc *ContainerVolumeUsecase) List() ([]types.ContainerVolume, error) {
return uc.repo.List()
}
func (uc *ContainerVolumeUsecase) Create(req *request.ContainerVolumeCreate) (string, error) {
return uc.repo.Create(req)
}
func (uc *ContainerVolumeUsecase) Remove(id string) error {
return uc.repo.Remove(id)
}
func (uc *ContainerVolumeUsecase) Prune() error {
return uc.repo.Prune()
}
+38 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -30,3 +30,40 @@ type CronRepo interface {
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
Status(id uint, status bool) error Status(id uint, status bool) error
} }
// CronUsecase 计划任务业务逻辑
type CronUsecase struct {
repo CronRepo
}
func NewCronUsecase(repo CronRepo) *CronUsecase {
return &CronUsecase{repo: repo}
}
func (uc *CronUsecase) Count() (int64, error) {
return uc.repo.Count()
}
func (uc *CronUsecase) List(page, limit uint) ([]*Cron, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *CronUsecase) Get(id uint) (*Cron, error) {
return uc.repo.Get(id)
}
func (uc *CronUsecase) Create(ctx context.Context, req *request.CronCreate) error {
return uc.repo.Create(ctx, req)
}
func (uc *CronUsecase) Update(ctx context.Context, req *request.CronUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *CronUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
func (uc *CronUsecase) Status(id uint, status bool) error {
return uc.repo.Status(id, status)
}
+26 -1
View File
@@ -3,7 +3,7 @@ package biz
import ( import (
"context" "context"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type DatabaseType string type DatabaseType string
@@ -33,3 +33,28 @@ type DatabaseRepo interface {
Delete(ctx context.Context, serverID uint, name string) error Delete(ctx context.Context, serverID uint, name string) error
Comment(req *request.DatabaseComment) error Comment(req *request.DatabaseComment) error
} }
// DatabaseUsecase 数据库业务用例
type DatabaseUsecase struct {
repo DatabaseRepo
}
func NewDatabaseUsecase(repo DatabaseRepo) *DatabaseUsecase {
return &DatabaseUsecase{repo: repo}
}
func (uc *DatabaseUsecase) List(page, limit uint, typ string) ([]*Database, int64, error) {
return uc.repo.List(page, limit, typ)
}
func (uc *DatabaseUsecase) Create(ctx context.Context, req *request.DatabaseCreate) error {
return uc.repo.Create(ctx, req)
}
func (uc *DatabaseUsecase) Delete(ctx context.Context, serverID uint, name string) error {
return uc.repo.Delete(ctx, serverID, name)
}
func (uc *DatabaseUsecase) Comment(req *request.DatabaseComment) error {
return uc.repo.Comment(req)
}
+38 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/db" "github.com/acepanel/panel/v3/pkg/db"
) )
@@ -14,3 +14,40 @@ type DatabaseElasticsearchRepo interface {
DocumentSet(req *request.DatabaseESDocumentSet) error DocumentSet(req *request.DatabaseESDocumentSet) error
DocumentDelete(req *request.DatabaseESDocumentDelete) error DocumentDelete(req *request.DatabaseESDocumentDelete) error
} }
// DatabaseElasticsearchUsecase Elasticsearch 业务用例
type DatabaseElasticsearchUsecase struct {
repo DatabaseElasticsearchRepo
}
func NewDatabaseElasticsearchUsecase(repo DatabaseElasticsearchRepo) *DatabaseElasticsearchUsecase {
return &DatabaseElasticsearchUsecase{repo: repo}
}
func (uc *DatabaseElasticsearchUsecase) Indices(req *request.DatabaseESIndices) ([]db.ESIndex, error) {
return uc.repo.Indices(req)
}
func (uc *DatabaseElasticsearchUsecase) IndexCreate(req *request.DatabaseESIndexCreate) error {
return uc.repo.IndexCreate(req)
}
func (uc *DatabaseElasticsearchUsecase) IndexDelete(req *request.DatabaseESIndexDelete) error {
return uc.repo.IndexDelete(req)
}
func (uc *DatabaseElasticsearchUsecase) Data(req *request.DatabaseESData) ([]db.ESDocument, int64, error) {
return uc.repo.Data(req)
}
func (uc *DatabaseElasticsearchUsecase) DocumentGet(req *request.DatabaseESDocumentGet) (*db.ESDocument, error) {
return uc.repo.DocumentGet(req)
}
func (uc *DatabaseElasticsearchUsecase) DocumentSet(req *request.DatabaseESDocumentSet) error {
return uc.repo.DocumentSet(req)
}
func (uc *DatabaseElasticsearchUsecase) DocumentDelete(req *request.DatabaseESDocumentDelete) error {
return uc.repo.DocumentDelete(req)
}
+42 -1
View File
@@ -1,7 +1,7 @@
package biz package biz
import ( import (
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/db" "github.com/acepanel/panel/v3/pkg/db"
) )
@@ -15,3 +15,44 @@ type DatabaseRedisRepo interface {
KeyRename(req *request.DatabaseRedisKeyRename) error KeyRename(req *request.DatabaseRedisKeyRename) error
Clear(req *request.DatabaseRedisClear) error Clear(req *request.DatabaseRedisClear) error
} }
// DatabaseRedisUsecase Redis 业务用例
type DatabaseRedisUsecase struct {
repo DatabaseRedisRepo
}
func NewDatabaseRedisUsecase(repo DatabaseRedisRepo) *DatabaseRedisUsecase {
return &DatabaseRedisUsecase{repo: repo}
}
func (uc *DatabaseRedisUsecase) Databases(req *request.DatabaseRedisDatabases) (int, error) {
return uc.repo.Databases(req)
}
func (uc *DatabaseRedisUsecase) Data(req *request.DatabaseRedisData) ([]db.RedisKV, int, error) {
return uc.repo.Data(req)
}
func (uc *DatabaseRedisUsecase) KeyGet(req *request.DatabaseRedisKeyGet) (*db.RedisKV, error) {
return uc.repo.KeyGet(req)
}
func (uc *DatabaseRedisUsecase) KeySet(req *request.DatabaseRedisKeySet) error {
return uc.repo.KeySet(req)
}
func (uc *DatabaseRedisUsecase) KeyDelete(req *request.DatabaseRedisKeyDelete) error {
return uc.repo.KeyDelete(req)
}
func (uc *DatabaseRedisUsecase) KeyTTL(req *request.DatabaseRedisKeyTTL) error {
return uc.repo.KeyTTL(req)
}
func (uc *DatabaseRedisUsecase) KeyRename(req *request.DatabaseRedisKeyRename) error {
return uc.repo.KeyRename(req)
}
func (uc *DatabaseRedisUsecase) Clear(req *request.DatabaseRedisClear) error {
return uc.repo.Clear(req)
}
+58 -1
View File
@@ -7,7 +7,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type DatabaseServerStatus string type DatabaseServerStatus string
@@ -74,3 +74,60 @@ type DatabaseServerRepo interface {
ClearUsers(id uint) error ClearUsers(id uint) error
Sync(id uint) error Sync(id uint) error
} }
// DatabaseServerUsecase 数据库服务器业务用例
type DatabaseServerUsecase struct {
repo DatabaseServerRepo
}
func NewDatabaseServerUsecase(repo DatabaseServerRepo) *DatabaseServerUsecase {
return &DatabaseServerUsecase{repo: repo}
}
func (uc *DatabaseServerUsecase) Count() (int64, error) {
return uc.repo.Count()
}
func (uc *DatabaseServerUsecase) List(page, limit uint, typ string) ([]*DatabaseServer, int64, error) {
return uc.repo.List(page, limit, typ)
}
func (uc *DatabaseServerUsecase) Get(id uint) (*DatabaseServer, error) {
return uc.repo.Get(id)
}
func (uc *DatabaseServerUsecase) GetByName(name string) (*DatabaseServer, error) {
return uc.repo.GetByName(name)
}
func (uc *DatabaseServerUsecase) Create(req *request.DatabaseServerCreate) error {
return uc.repo.Create(req)
}
func (uc *DatabaseServerUsecase) Update(req *request.DatabaseServerUpdate) error {
return uc.repo.Update(req)
}
func (uc *DatabaseServerUsecase) UpdateRemark(req *request.DatabaseServerUpdateRemark) error {
return uc.repo.UpdateRemark(req)
}
func (uc *DatabaseServerUsecase) UpdatePassword(name string, password string) error {
return uc.repo.UpdatePassword(name, password)
}
func (uc *DatabaseServerUsecase) UpdatePort(name string, port uint) error {
return uc.repo.UpdatePort(name, port)
}
func (uc *DatabaseServerUsecase) Delete(id uint) error {
return uc.repo.Delete(id)
}
func (uc *DatabaseServerUsecase) ClearUsers(id uint) error {
return uc.repo.ClearUsers(id)
}
func (uc *DatabaseServerUsecase) Sync(id uint) error {
return uc.repo.Sync(id)
}
+42 -1
View File
@@ -8,7 +8,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type DatabaseUserStatus string type DatabaseUserStatus string
@@ -72,3 +72,44 @@ type DatabaseUserRepo interface {
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
DeleteByNames(serverID uint, names []string) error DeleteByNames(serverID uint, names []string) error
} }
// DatabaseUserUsecase 数据库用户业务用例
type DatabaseUserUsecase struct {
repo DatabaseUserRepo
}
func NewDatabaseUserUsecase(repo DatabaseUserRepo) *DatabaseUserUsecase {
return &DatabaseUserUsecase{repo: repo}
}
func (uc *DatabaseUserUsecase) Count() (int64, error) {
return uc.repo.Count()
}
func (uc *DatabaseUserUsecase) List(page, limit uint, typ string) ([]*DatabaseUser, int64, error) {
return uc.repo.List(page, limit, typ)
}
func (uc *DatabaseUserUsecase) Get(id uint) (*DatabaseUser, error) {
return uc.repo.Get(id)
}
func (uc *DatabaseUserUsecase) Create(ctx context.Context, req *request.DatabaseUserCreate) error {
return uc.repo.Create(ctx, req)
}
func (uc *DatabaseUserUsecase) Update(req *request.DatabaseUserUpdate) error {
return uc.repo.Update(req)
}
func (uc *DatabaseUserUsecase) UpdateRemark(req *request.DatabaseUserUpdateRemark) error {
return uc.repo.UpdateRemark(req)
}
func (uc *DatabaseUserUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
func (uc *DatabaseUserUsecase) DeleteByNames(serverID uint, names []string) error {
return uc.repo.DeleteByNames(serverID, names)
}
+44
View File
@@ -16,3 +16,47 @@ type EnvironmentRepo interface {
Uninstall(typ, slug string) error Uninstall(typ, slug string) error
Update(typ, slug string) error Update(typ, slug string) error
} }
type EnvironmentUsecase struct {
repo EnvironmentRepo
}
func NewEnvironmentUsecase(repo EnvironmentRepo) *EnvironmentUsecase {
return &EnvironmentUsecase{repo: repo}
}
func (uc *EnvironmentUsecase) Types() []types.LV {
return uc.repo.Types()
}
func (uc *EnvironmentUsecase) All(typ ...string) api.Environments {
return uc.repo.All(typ...)
}
func (uc *EnvironmentUsecase) IsInstalled(typ, slug string) bool {
return uc.repo.IsInstalled(typ, slug)
}
func (uc *EnvironmentUsecase) InstalledSlugs(typ string) []string {
return uc.repo.InstalledSlugs(typ)
}
func (uc *EnvironmentUsecase) InstalledVersion(typ, slug string) string {
return uc.repo.InstalledVersion(typ, slug)
}
func (uc *EnvironmentUsecase) HasUpdate(typ, slug string) bool {
return uc.repo.HasUpdate(typ, slug)
}
func (uc *EnvironmentUsecase) Install(typ, slug string) error {
return uc.repo.Install(typ, slug)
}
func (uc *EnvironmentUsecase) Uninstall(typ, slug string) error {
return uc.repo.Uninstall(typ, slug)
}
func (uc *EnvironmentUsecase) Update(typ, slug string) error {
return uc.repo.Update(typ, slug)
}
+16
View File
@@ -52,3 +52,19 @@ type LogRepo interface {
// ListDates 获取可用的日志日期列表 // ListDates 获取可用的日志日期列表
ListDates(logType string) ([]string, error) ListDates(logType string) ([]string, error)
} }
type LogUsecase struct {
repo LogRepo
}
func NewLogUsecase(repo LogRepo) *LogUsecase {
return &LogUsecase{repo: repo}
}
func (uc *LogUsecase) List(logType string, limit int, date string) ([]LogEntry, error) {
return uc.repo.List(logType, limit, date)
}
func (uc *LogUsecase) ListDates(logType string) ([]string, error) {
return uc.repo.ListDates(logType)
}
+25 -1
View File
@@ -3,7 +3,7 @@ package biz
import ( import (
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -20,3 +20,27 @@ type MonitorRepo interface {
Clear() error Clear() error
List(start, end time.Time) ([]*Monitor, error) List(start, end time.Time) ([]*Monitor, error)
} }
type MonitorUsecase struct {
repo MonitorRepo
}
func NewMonitorUsecase(repo MonitorRepo) *MonitorUsecase {
return &MonitorUsecase{repo: repo}
}
func (uc *MonitorUsecase) GetSetting() (*request.MonitorSetting, error) {
return uc.repo.GetSetting()
}
func (uc *MonitorUsecase) UpdateSetting(setting *request.MonitorSetting) error {
return uc.repo.UpdateSetting(setting)
}
func (uc *MonitorUsecase) Clear() error {
return uc.repo.Clear()
}
func (uc *MonitorUsecase) List(start, end time.Time) ([]*Monitor, error) {
return uc.repo.List(start, end)
}
+33 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -25,3 +25,35 @@ type ProjectRepo interface {
Update(ctx context.Context, req *request.ProjectUpdate) error Update(ctx context.Context, req *request.ProjectUpdate) error
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
} }
type ProjectUsecase struct {
repo ProjectRepo
}
func NewProjectUsecase(repo ProjectRepo) *ProjectUsecase {
return &ProjectUsecase{repo: repo}
}
func (uc *ProjectUsecase) Count() (int64, error) {
return uc.repo.Count()
}
func (uc *ProjectUsecase) List(typ types.ProjectType, page, limit uint) ([]*types.ProjectDetail, int64, error) {
return uc.repo.List(typ, page, limit)
}
func (uc *ProjectUsecase) Get(id uint) (*types.ProjectDetail, error) {
return uc.repo.Get(id)
}
func (uc *ProjectUsecase) Create(ctx context.Context, req *request.ProjectCreate) (*types.ProjectDetail, error) {
return uc.repo.Create(ctx, req)
}
func (uc *ProjectUsecase) Update(ctx context.Context, req *request.ProjectUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *ProjectUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
+16
View File
@@ -6,3 +6,19 @@ type SafeRepo interface {
GetPingStatus() (bool, error) GetPingStatus() (bool, error)
UpdatePingStatus(ctx context.Context, status bool) error UpdatePingStatus(ctx context.Context, status bool) error
} }
type SafeUsecase struct {
repo SafeRepo
}
func NewSafeUsecase(repo SafeRepo) *SafeUsecase {
return &SafeUsecase{repo: repo}
}
func (uc *SafeUsecase) GetPingStatus() (bool, error) {
return uc.repo.GetPingStatus()
}
func (uc *SafeUsecase) UpdatePingStatus(ctx context.Context, status bool) error {
return uc.repo.UpdatePingStatus(ctx, status)
}
+53
View File
@@ -80,3 +80,56 @@ type ScanEventRepo interface {
Clear() error Clear() error
VacuumDB() error VacuumDB() error
} }
// ScanEventUsecase 扫描事件业务逻辑
type ScanEventUsecase struct {
repo ScanEventRepo
}
func NewScanEventUsecase(repo ScanEventRepo) *ScanEventUsecase {
return &ScanEventUsecase{repo: repo}
}
func (uc *ScanEventUsecase) Upsert(events []*ScanEvent) error {
return uc.repo.Upsert(events)
}
func (uc *ScanEventUsecase) List(start, end, sourceIP string, port uint, location string, page, limit uint) ([]*ScanEvent, uint, error) {
return uc.repo.List(start, end, sourceIP, port, location, page, limit)
}
func (uc *ScanEventUsecase) Summary(start, end string) (*ScanSummary, error) {
return uc.repo.Summary(start, end)
}
func (uc *ScanEventUsecase) Trend(start, end string) ([]*ScanDayTrend, error) {
return uc.repo.Trend(start, end)
}
func (uc *ScanEventUsecase) TopSourceIPs(start, end string, limit uint) ([]*ScanSourceRank, error) {
return uc.repo.TopSourceIPs(start, end, limit)
}
func (uc *ScanEventUsecase) TopPorts(start, end string, limit uint) ([]*ScanPortRank, error) {
return uc.repo.TopPorts(start, end, limit)
}
func (uc *ScanEventUsecase) ClearBefore(date string) error {
return uc.repo.ClearBefore(date)
}
func (uc *ScanEventUsecase) GetSetting() (*ScanSetting, error) {
return uc.repo.GetSetting()
}
func (uc *ScanEventUsecase) UpdateSetting(setting *ScanSetting) error {
return uc.repo.UpdateSetting(setting)
}
func (uc *ScanEventUsecase) Clear() error {
return uc.repo.Clear()
}
func (uc *ScanEventUsecase) VacuumDB() error {
return uc.repo.VacuumDB()
}
+49 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type SettingKey string type SettingKey string
@@ -73,3 +73,51 @@ type SettingRepo interface {
UpdatePanel(ctx context.Context, req *request.SettingPanel) (bool, error) UpdatePanel(ctx context.Context, req *request.SettingPanel) (bool, error)
UpdateCert(req *request.SettingCert) error UpdateCert(req *request.SettingCert) error
} }
type SettingUsecase struct {
repo SettingRepo
}
func NewSettingUsecase(repo SettingRepo) *SettingUsecase {
return &SettingUsecase{repo: repo}
}
func (uc *SettingUsecase) Get(key SettingKey, defaultValue ...string) (string, error) {
return uc.repo.Get(key, defaultValue...)
}
func (uc *SettingUsecase) GetBool(key SettingKey, defaultValue ...bool) (bool, error) {
return uc.repo.GetBool(key, defaultValue...)
}
func (uc *SettingUsecase) GetInt(key SettingKey, defaultValue ...int) (int, error) {
return uc.repo.GetInt(key, defaultValue...)
}
func (uc *SettingUsecase) GetSlice(key SettingKey, defaultValue ...[]string) ([]string, error) {
return uc.repo.GetSlice(key, defaultValue...)
}
func (uc *SettingUsecase) Set(key SettingKey, value string) error {
return uc.repo.Set(key, value)
}
func (uc *SettingUsecase) SetSlice(key SettingKey, value []string) error {
return uc.repo.SetSlice(key, value)
}
func (uc *SettingUsecase) Delete(key SettingKey) error {
return uc.repo.Delete(key)
}
func (uc *SettingUsecase) GetPanel() (*request.SettingPanel, error) {
return uc.repo.GetPanel()
}
func (uc *SettingUsecase) UpdatePanel(ctx context.Context, req *request.SettingPanel) (bool, error) {
return uc.repo.UpdatePanel(ctx, req)
}
func (uc *SettingUsecase) UpdateCert(req *request.SettingCert) error {
return uc.repo.UpdateCert(req)
}
+30 -1
View File
@@ -8,7 +8,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/ssh" "github.com/acepanel/panel/v3/pkg/ssh"
) )
@@ -66,3 +66,32 @@ type SSHRepo interface {
Update(ctx context.Context, req *request.SSHUpdate) error Update(ctx context.Context, req *request.SSHUpdate) error
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
} }
// SSHUsecase SSH 业务逻辑
type SSHUsecase struct {
repo SSHRepo
}
func NewSSHUsecase(repo SSHRepo) *SSHUsecase {
return &SSHUsecase{repo: repo}
}
func (uc *SSHUsecase) List(page, limit uint) ([]*SSH, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *SSHUsecase) Get(id uint) (*SSH, error) {
return uc.repo.Get(id)
}
func (uc *SSHUsecase) Create(ctx context.Context, req *request.SSHCreate) error {
return uc.repo.Create(ctx, req)
}
func (uc *SSHUsecase) Update(ctx context.Context, req *request.SSHUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *SSHUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
+36
View File
@@ -30,3 +30,39 @@ type TaskRepo interface {
UpdateLog(id uint, log string) error UpdateLog(id uint, log string) error
Push(task *Task) error Push(task *Task) error
} }
type TaskUsecase struct {
repo TaskRepo
}
func NewTaskUsecase(repo TaskRepo) *TaskUsecase {
return &TaskUsecase{repo: repo}
}
func (uc *TaskUsecase) HasRunningTask() bool {
return uc.repo.HasRunningTask()
}
func (uc *TaskUsecase) List(page, limit uint) ([]*Task, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *TaskUsecase) Get(id uint) (*Task, error) {
return uc.repo.Get(id)
}
func (uc *TaskUsecase) Delete(id uint) error {
return uc.repo.Delete(id)
}
func (uc *TaskUsecase) UpdateStatus(id uint, status TaskStatus) error {
return uc.repo.UpdateStatus(id, status)
}
func (uc *TaskUsecase) UpdateLog(id uint, log string) error {
return uc.repo.UpdateLog(id, log)
}
func (uc *TaskUsecase) Push(task *Task) error {
return uc.repo.Push(task)
}
+24
View File
@@ -11,3 +11,27 @@ type TemplateRepo interface {
Callback(slug string) error Callback(slug string) error
CreateCompose(name, compose string, envs []types.KV, autoFirewall bool) (string, error) CreateCompose(name, compose string, envs []types.KV, autoFirewall bool) (string, error)
} }
type TemplateUsecase struct {
repo TemplateRepo
}
func NewTemplateUsecase(repo TemplateRepo) *TemplateUsecase {
return &TemplateUsecase{repo: repo}
}
func (uc *TemplateUsecase) List() api.Templates {
return uc.repo.List()
}
func (uc *TemplateUsecase) Get(slug string) (*api.Template, error) {
return uc.repo.Get(slug)
}
func (uc *TemplateUsecase) Callback(slug string) error {
return uc.repo.Callback(slug)
}
func (uc *TemplateUsecase) CreateCompose(name, compose string, envs []types.KV, autoFirewall bool) (string, error) {
return uc.repo.CreateCompose(name, compose, envs, autoFirewall)
}
+52
View File
@@ -34,3 +34,55 @@ type UserRepo interface {
GenerateTwoFA(id uint) (image.Image, string, string, error) GenerateTwoFA(id uint) (image.Image, string, string, error)
UpdateTwoFA(id uint, code, secret string) error UpdateTwoFA(id uint, code, secret string) error
} }
type UserUsecase struct {
repo UserRepo
}
func NewUserUsecase(repo UserRepo) *UserUsecase {
return &UserUsecase{repo: repo}
}
func (uc *UserUsecase) List(page, limit uint) ([]*User, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *UserUsecase) Get(id uint) (*User, error) {
return uc.repo.Get(id)
}
func (uc *UserUsecase) Create(ctx context.Context, username, password, email string) (*User, error) {
return uc.repo.Create(ctx, username, password, email)
}
func (uc *UserUsecase) UpdateUsername(ctx context.Context, id uint, username string) error {
return uc.repo.UpdateUsername(ctx, id, username)
}
func (uc *UserUsecase) UpdatePassword(ctx context.Context, id uint, password string) error {
return uc.repo.UpdatePassword(ctx, id, password)
}
func (uc *UserUsecase) UpdateEmail(ctx context.Context, id uint, email string) error {
return uc.repo.UpdateEmail(ctx, id, email)
}
func (uc *UserUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
func (uc *UserUsecase) CheckPassword(username, password string) (*User, error) {
return uc.repo.CheckPassword(username, password)
}
func (uc *UserUsecase) IsTwoFA(username string) (bool, error) {
return uc.repo.IsTwoFA(username)
}
func (uc *UserUsecase) GenerateTwoFA(id uint) (image.Image, string, string, error) {
return uc.repo.GenerateTwoFA(id)
}
func (uc *UserUsecase) UpdateTwoFA(id uint, code, secret string) error {
return uc.repo.UpdateTwoFA(id, code, secret)
}
+44
View File
@@ -34,3 +34,47 @@ type UserPasskeyRepo interface {
HasAny() (bool, error) HasAny() (bool, error)
DeleteAllByUserID(userID uint) error DeleteAllByUserID(userID uint) error
} }
type UserPasskeyUsecase struct {
repo UserPasskeyRepo
}
func NewUserPasskeyUsecase(repo UserPasskeyRepo) *UserPasskeyUsecase {
return &UserPasskeyUsecase{repo: repo}
}
func (uc *UserPasskeyUsecase) List(userID uint) ([]*UserPasskey, error) {
return uc.repo.List(userID)
}
func (uc *UserPasskeyUsecase) Create(passkey *UserPasskey) error {
return uc.repo.Create(passkey)
}
func (uc *UserPasskeyUsecase) UpdateSignCount(credentialID []byte, signCount uint32) error {
return uc.repo.UpdateSignCount(credentialID, signCount)
}
func (uc *UserPasskeyUsecase) UpdateLastUsed(credentialID []byte) error {
return uc.repo.UpdateLastUsed(credentialID)
}
func (uc *UserPasskeyUsecase) Delete(userID, id uint) error {
return uc.repo.Delete(userID, id)
}
func (uc *UserPasskeyUsecase) GetByCredentialID(credentialID []byte) (*UserPasskey, *User, error) {
return uc.repo.GetByCredentialID(credentialID)
}
func (uc *UserPasskeyUsecase) HasPasskey(userID uint) (bool, error) {
return uc.repo.HasPasskey(userID)
}
func (uc *UserPasskeyUsecase) HasAny() (bool, error) {
return uc.repo.HasAny()
}
func (uc *UserPasskeyUsecase) DeleteAllByUserID(userID uint) error {
return uc.repo.DeleteAllByUserID(userID)
}
+32
View File
@@ -56,3 +56,35 @@ type UserTokenRepo interface {
Update(id uint, ips []string, expired time.Time) (*UserToken, error) Update(id uint, ips []string, expired time.Time) (*UserToken, error)
ValidateReq(req *http.Request) (uint, error) ValidateReq(req *http.Request) (uint, error)
} }
type UserTokenUsecase struct {
repo UserTokenRepo
}
func NewUserTokenUsecase(repo UserTokenRepo) *UserTokenUsecase {
return &UserTokenUsecase{repo: repo}
}
func (uc *UserTokenUsecase) List(userID, page, limit uint) ([]*UserToken, int64, error) {
return uc.repo.List(userID, page, limit)
}
func (uc *UserTokenUsecase) Create(userID uint, ips []string, expired time.Time) (*UserToken, error) {
return uc.repo.Create(userID, ips, expired)
}
func (uc *UserTokenUsecase) Get(id uint) (*UserToken, error) {
return uc.repo.Get(id)
}
func (uc *UserTokenUsecase) Delete(id uint) error {
return uc.repo.Delete(id)
}
func (uc *UserTokenUsecase) Update(id uint, ips []string, expired time.Time) (*UserToken, error) {
return uc.repo.Update(id, ips, expired)
}
func (uc *UserTokenUsecase) ValidateReq(req *http.Request) (uint, error) {
return uc.repo.ValidateReq(req)
}
+37 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
) )
type WebHook struct { type WebHook struct {
@@ -30,3 +30,39 @@ type WebHookRepo interface {
Delete(ctx context.Context, id uint) error Delete(ctx context.Context, id uint) error
Call(key string) (string, error) Call(key string) (string, error)
} }
type WebHookUsecase struct {
repo WebHookRepo
}
func NewWebHookUsecase(repo WebHookRepo) *WebHookUsecase {
return &WebHookUsecase{repo: repo}
}
func (uc *WebHookUsecase) List(page, limit uint) ([]*WebHook, int64, error) {
return uc.repo.List(page, limit)
}
func (uc *WebHookUsecase) Get(id uint) (*WebHook, error) {
return uc.repo.Get(id)
}
func (uc *WebHookUsecase) GetByKey(key string) (*WebHook, error) {
return uc.repo.GetByKey(key)
}
func (uc *WebHookUsecase) Create(ctx context.Context, req *request.WebHookCreate) (*WebHook, error) {
return uc.repo.Create(ctx, req)
}
func (uc *WebHookUsecase) Update(ctx context.Context, req *request.WebHookUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *WebHookUsecase) Delete(ctx context.Context, id uint) error {
return uc.repo.Delete(ctx, id)
}
func (uc *WebHookUsecase) Call(key string) (string, error) {
return uc.repo.Call(key)
}
+69 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/acepanel/panel/v3/internal/http/request" "github.com/acepanel/panel/v3/internal/request"
"github.com/acepanel/panel/v3/pkg/types" "github.com/acepanel/panel/v3/pkg/types"
) )
@@ -52,3 +52,71 @@ type WebsiteRepo interface {
UpdateCert(req *request.WebsiteUpdateCert) error UpdateCert(req *request.WebsiteUpdateCert) error
ObtainCert(ctx context.Context, id uint, dnsID uint) error ObtainCert(ctx context.Context, id uint, dnsID uint) error
} }
type WebsiteUsecase struct {
repo WebsiteRepo
}
func NewWebsiteUsecase(repo WebsiteRepo) *WebsiteUsecase {
return &WebsiteUsecase{repo: repo}
}
func (uc *WebsiteUsecase) GetRewrites() (map[string]string, error) {
return uc.repo.GetRewrites()
}
func (uc *WebsiteUsecase) UpdateDefaultConfig(req *request.WebsiteDefaultConfig) error {
return uc.repo.UpdateDefaultConfig(req)
}
func (uc *WebsiteUsecase) Count() (int64, error) {
return uc.repo.Count()
}
func (uc *WebsiteUsecase) Get(id uint) (*types.WebsiteSetting, error) {
return uc.repo.Get(id)
}
func (uc *WebsiteUsecase) GetByName(name string) (*types.WebsiteSetting, error) {
return uc.repo.GetByName(name)
}
func (uc *WebsiteUsecase) List(typ string, page, limit uint) ([]*Website, int64, error) {
return uc.repo.List(typ, page, limit)
}
func (uc *WebsiteUsecase) Create(ctx context.Context, req *request.WebsiteCreate) (*Website, error) {
return uc.repo.Create(ctx, req)
}
func (uc *WebsiteUsecase) Update(ctx context.Context, req *request.WebsiteUpdate) error {
return uc.repo.Update(ctx, req)
}
func (uc *WebsiteUsecase) Delete(ctx context.Context, req *request.WebsiteDelete) error {
return uc.repo.Delete(ctx, req)
}
func (uc *WebsiteUsecase) UpdateRemark(id uint, remark string) error {
return uc.repo.UpdateRemark(id, remark)
}
func (uc *WebsiteUsecase) ResetConfig(id uint) error {
return uc.repo.ResetConfig(id)
}
func (uc *WebsiteUsecase) UpdateStatus(id uint, status bool) error {
return uc.repo.UpdateStatus(id, status)
}
func (uc *WebsiteUsecase) UpdateExpireAt(id uint, expireAt *time.Time) error {
return uc.repo.UpdateExpireAt(id, expireAt)
}
func (uc *WebsiteUsecase) UpdateCert(req *request.WebsiteUpdateCert) error {
return uc.repo.UpdateCert(req)
}
func (uc *WebsiteUsecase) ObtainCert(ctx context.Context, id uint, dnsID uint) error {
return uc.repo.ObtainCert(ctx, id, dnsID)
}
+108
View File
@@ -223,3 +223,111 @@ type WebsiteStatRepo interface {
// 网站维度汇总 // 网站维度汇总
ListSiteStats(start, end string, sites []string) ([]*WebsiteStatSiteItem, error) ListSiteStats(start, end string, sites []string) ([]*WebsiteStatSiteItem, error)
} }
type WebsiteStatUsecase struct {
repo WebsiteStatRepo
}
func NewWebsiteStatUsecase(repo WebsiteStatRepo) *WebsiteStatUsecase {
return &WebsiteStatUsecase{repo: repo}
}
func (uc *WebsiteStatUsecase) Upsert(stats []*WebsiteStat) error {
return uc.repo.Upsert(stats)
}
func (uc *WebsiteStatUsecase) ListByDateRange(start, end string, sites []string) ([]*WebsiteStat, error) {
return uc.repo.ListByDateRange(start, end, sites)
}
func (uc *WebsiteStatUsecase) DailySeries(start, end string, sites []string) ([]*WebsiteStatSeries, error) {
return uc.repo.DailySeries(start, end, sites)
}
func (uc *WebsiteStatUsecase) HourlySeries(date string, sites []string) ([]*WebsiteStatSeries, error) {
return uc.repo.HourlySeries(date, sites)
}
func (uc *WebsiteStatUsecase) ClearBefore(date string) error {
return uc.repo.ClearBefore(date)
}
func (uc *WebsiteStatUsecase) InsertErrors(errors []*WebsiteErrorLog) error {
return uc.repo.InsertErrors(errors)
}
func (uc *WebsiteStatUsecase) ClearErrorsBefore(t time.Time) error {
return uc.repo.ClearErrorsBefore(t)
}
func (uc *WebsiteStatUsecase) Clear() error {
return uc.repo.Clear()
}
func (uc *WebsiteStatUsecase) VacuumDB() error {
return uc.repo.VacuumDB()
}
func (uc *WebsiteStatUsecase) UpsertSpiders(stats []*WebsiteStatSpider) error {
return uc.repo.UpsertSpiders(stats)
}
func (uc *WebsiteStatUsecase) TopSpiders(start, end string, sites []string, limit uint) ([]*WebsiteStatSpiderRank, error) {
return uc.repo.TopSpiders(start, end, sites, limit)
}
func (uc *WebsiteStatUsecase) ClearSpidersBefore(date string) error {
return uc.repo.ClearSpidersBefore(date)
}
func (uc *WebsiteStatUsecase) UpsertClients(stats []*WebsiteStatClient) error {
return uc.repo.UpsertClients(stats)
}
func (uc *WebsiteStatUsecase) TopClients(start, end string, sites []string, limit uint) ([]*WebsiteStatClientRank, error) {
return uc.repo.TopClients(start, end, sites, limit)
}
func (uc *WebsiteStatUsecase) ClearClientsBefore(date string) error {
return uc.repo.ClearClientsBefore(date)
}
func (uc *WebsiteStatUsecase) UpsertIPs(stats []*WebsiteStatIP) error {
return uc.repo.UpsertIPs(stats)
}
func (uc *WebsiteStatUsecase) TopIPs(start, end string, sites []string, page, limit uint) ([]*WebsiteStatIPRank, uint, error) {
return uc.repo.TopIPs(start, end, sites, page, limit)
}
func (uc *WebsiteStatUsecase) TopGeos(start, end string, sites []string, groupBy string, country string, limit uint) ([]*WebsiteStatGeoRank, error) {
return uc.repo.TopGeos(start, end, sites, groupBy, country, limit)
}
func (uc *WebsiteStatUsecase) ClearIPsBefore(date string) error {
return uc.repo.ClearIPsBefore(date)
}
func (uc *WebsiteStatUsecase) UpsertURIs(stats []*WebsiteStatURI) error {
return uc.repo.UpsertURIs(stats)
}
func (uc *WebsiteStatUsecase) TopURIs(start, end string, sites []string, page, limit uint) ([]*WebsiteStatURIRank, uint, error) {
return uc.repo.TopURIs(start, end, sites, page, limit)
}
func (uc *WebsiteStatUsecase) TopSlowURIs(start, end string, sites []string, threshold, page, limit uint) ([]*WebsiteStatURIRank, uint, error) {
return uc.repo.TopSlowURIs(start, end, sites, threshold, page, limit)
}
func (uc *WebsiteStatUsecase) ClearURIsBefore(date string) error {
return uc.repo.ClearURIsBefore(date)
}
func (uc *WebsiteStatUsecase) ListErrors(start, end string, sites []string, status int, page, limit uint) ([]*WebsiteErrorLog, uint, error) {
return uc.repo.ListErrors(start, end, sites, status, page, limit)
}
func (uc *WebsiteStatUsecase) ListSiteStats(start, end string, sites []string) ([]*WebsiteStatSiteItem, error) {
return uc.repo.ListSiteStats(start, end, sites)
}
+36 -34
View File
@@ -1,6 +1,8 @@
package bootstrap package bootstrap
import ( import (
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/apps/apache" "github.com/acepanel/panel/v3/internal/apps/apache"
"github.com/acepanel/panel/v3/internal/apps/clickhouse" "github.com/acepanel/panel/v3/internal/apps/clickhouse"
"github.com/acepanel/panel/v3/internal/apps/codeserver" "github.com/acepanel/panel/v3/internal/apps/codeserver"
@@ -34,39 +36,39 @@ import (
"github.com/acepanel/panel/v3/pkg/apploader" "github.com/acepanel/panel/v3/pkg/apploader"
) )
func NewLoader( func NewLoader(i do.Injector) (*apploader.Loader, error) {
apache *apache.App,
clickhouse *clickhouse.App,
codeserver *codeserver.App,
docker *docker.App,
elasticsearch *elasticsearch.App,
fail2ban *fail2ban.App,
frp *frp.App,
gitea *gitea.App,
grafana *grafana.App,
kafka *kafka.App,
mariadb *mariadb.App,
memcached *memcached.App,
minio *minio.App,
mongodb *mongodb.App,
mysql *mysql.App,
nginx *nginx.App,
openresty *openresty.App,
opensearch *opensearch.App,
percona *percona.App,
phpmyadmin *phpmyadmin.App,
podman *podman.App,
postgresql *postgresql.App,
prometheus *prometheus.App,
pureftpd *pureftpd.App,
redis *redis.App,
rocketmq *rocketmq.App,
rsync *rsync.App,
s3fs *s3fs.App,
supervisor *supervisor.App,
valkey *valkey.App,
) *apploader.Loader {
loader := new(apploader.Loader) loader := new(apploader.Loader)
loader.Add(apache, clickhouse, codeserver, docker, elasticsearch, fail2ban, frp, gitea, grafana, kafka, mariadb, memcached, minio, mongodb, mysql, nginx, openresty, opensearch, percona, phpmyadmin, podman, postgresql, prometheus, pureftpd, redis, rocketmq, rsync, s3fs, supervisor, valkey) loader.Add(
return loader do.MustInvoke[*apache.App](i),
do.MustInvoke[*clickhouse.App](i),
do.MustInvoke[*codeserver.App](i),
do.MustInvoke[*docker.App](i),
do.MustInvoke[*elasticsearch.App](i),
do.MustInvoke[*fail2ban.App](i),
do.MustInvoke[*frp.App](i),
do.MustInvoke[*gitea.App](i),
do.MustInvoke[*grafana.App](i),
do.MustInvoke[*kafka.App](i),
do.MustInvoke[*mariadb.App](i),
do.MustInvoke[*memcached.App](i),
do.MustInvoke[*minio.App](i),
do.MustInvoke[*mongodb.App](i),
do.MustInvoke[*mysql.App](i),
do.MustInvoke[*nginx.App](i),
do.MustInvoke[*openresty.App](i),
do.MustInvoke[*opensearch.App](i),
do.MustInvoke[*percona.App](i),
do.MustInvoke[*phpmyadmin.App](i),
do.MustInvoke[*podman.App](i),
do.MustInvoke[*postgresql.App](i),
do.MustInvoke[*prometheus.App](i),
do.MustInvoke[*pureftpd.App](i),
do.MustInvoke[*redis.App](i),
do.MustInvoke[*rocketmq.App](i),
do.MustInvoke[*rsync.App](i),
do.MustInvoke[*s3fs.App](i),
do.MustInvoke[*supervisor.App](i),
do.MustInvoke[*valkey.App](i),
)
return loader, nil
} }
+24 -3
View File
@@ -1,10 +1,31 @@
package bootstrap package bootstrap
import ( import (
"github.com/google/wire" "github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/middleware"
"github.com/acepanel/panel/v3/pkg/websitestat" "github.com/acepanel/panel/v3/pkg/websitestat"
) )
// ProviderSet is bootstrap providers. // Package 装配基础设施层。
var ProviderSet = wire.NewSet(NewConf, NewT, NewLog, NewCli, NewRouter, NewTLSReloader, NewHttp, NewDB, NewMigrate, NewLoader, NewSession, NewCron, NewRunner, websitestat.NewAggregator) var Package = do.Package(
do.Lazy(NewConf),
do.Lazy(NewT),
do.Lazy(NewLogger),
do.Lazy(NewSlog),
do.Lazy(NewDB),
do.Lazy(NewMigrate),
do.Lazy(NewSession),
do.Lazy(NewRunner),
do.Lazy(NewValidator),
do.Lazy(middleware.NewMiddlewares),
do.Lazy(NewLoader),
do.Lazy(NewRouter),
do.Lazy(NewTLSReloader),
do.Lazy(NewHttp),
do.Lazy(NewCron),
do.Lazy(NewCli),
do.Lazy(func(i do.Injector) (*websitestat.Aggregator, error) {
return websitestat.NewAggregator(), nil
}),
)
+12 -4
View File
@@ -4,13 +4,16 @@ import (
"strings" "strings"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/route" "github.com/acepanel/panel/v3/internal/command"
) )
func NewCli(t *gotext.Locale, cmd *route.Cli) *cli.Command { func NewCli(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "NAME", t.Get("NAME")) cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "NAME", t.Get("NAME"))
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "USAGE", t.Get("USAGE")) cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "USAGE", t.Get("USAGE"))
cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "VERSION", t.Get("VERSION")) cli.RootCommandHelpTemplate = strings.ReplaceAll(cli.RootCommandHelpTemplate, "VERSION", t.Get("VERSION"))
@@ -34,10 +37,15 @@ func NewCli(t *gotext.Locale, cmd *route.Cli) *cli.Command {
cli.RootCommandHelpTemplate += "\n" + t.Get("Forumhttps://tom.moe") cli.RootCommandHelpTemplate += "\n" + t.Get("Forumhttps://tom.moe")
cli.RootCommandHelpTemplate += "\n" + t.Get("QQ Group12370907") + "\n" cli.RootCommandHelpTemplate += "\n" + t.Get("QQ Group12370907") + "\n"
cmds, err := command.Commands(i)
if err != nil {
return nil, err
}
return &cli.Command{ return &cli.Command{
Name: "acepanel", Name: "acepanel",
Usage: t.Get("AcePanel CLI Tool"), Usage: t.Get("AcePanel CLI Tool"),
Version: app.Version, Version: app.Version,
Commands: cmd.Commands(), Commands: cmds,
} }, nil
} }
+3 -1
View File
@@ -4,11 +4,13 @@ import (
"log" "log"
"time" "time"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
) )
func NewConf() (*config.Config, error) { func NewConf(i do.Injector) (*config.Config, error) {
conf, err := config.Load() conf, err := config.Load()
if err != nil { if err != nil {
return nil, err return nil, err
+5 -3
View File
@@ -5,16 +5,18 @@ import (
"github.com/libtnb/cron" "github.com/libtnb/cron"
"github.com/libtnb/cron/wrap" "github.com/libtnb/cron/wrap"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/job" "github.com/acepanel/panel/v3/internal/job"
) )
func NewCron(log *slog.Logger, jobs *job.Jobs) (*cron.Cron, error) { func NewCron(i do.Injector) (*cron.Cron, error) {
// 面板任务均为 5 段表达式,不启用 WithSecondsField
c := cron.New( c := cron.New(
cron.WithLogger(log), cron.WithLogger(do.MustInvoke[*slog.Logger](i)),
cron.WithChain(wrap.Recover(), wrap.SkipIfRunning()), cron.WithChain(wrap.Recover(), wrap.SkipIfRunning()),
) )
if err := jobs.Register(c); err != nil { if err := job.Register(i, c); err != nil {
return nil, err return nil, err
} }
+20 -13
View File
@@ -3,11 +3,13 @@ package bootstrap
import ( import (
"log/slog" "log/slog"
"path/filepath" "path/filepath"
"time"
"github.com/DeRuina/timberjack"
"github.com/go-gormigrate/gormigrate/v2" "github.com/go-gormigrate/gormigrate/v2"
"github.com/libtnb/logrotate"
"github.com/libtnb/sqlite" "github.com/libtnb/sqlite"
sloggorm "github.com/orandin/slog-gorm" sloggorm "github.com/orandin/slog-gorm"
"github.com/samber/do/v2"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
@@ -15,18 +17,22 @@ import (
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
) )
func NewDB(conf *config.Config) (*gorm.DB, error) { func NewDB(i do.Injector) (*gorm.DB, error) {
tjLogger := &timberjack.Logger{ conf := do.MustInvoke[*config.Config](i)
Filename: filepath.Join(app.Root, "panel/storage/logs/db.log"),
MaxSize: 10, // db 日志写入轮转文件
MaxAge: 30, w, err := logrotate.New(filepath.Join(app.Root, "panel/storage/logs/db.log"),
LocalTime: true, logrotate.WithMaxSize(10*logrotate.MB),
RotateAt: []string{"00:00"}, logrotate.WithMaxAge(30*logrotate.Day),
FileMode: 0o600, logrotate.WithRotateAt("00:00"),
Compression: "none", logrotate.WithFileMode(0o600),
logrotate.WithLocation(time.Local),
)
if err != nil {
return nil, err
} }
handler := slog.New(slog.NewJSONHandler(tjLogger, nil)).Handler() handler := slog.New(slog.NewJSONHandler(w, nil)).Handler()
options := []sloggorm.Option{sloggorm.WithHandler(handler)} options := []sloggorm.Option{sloggorm.WithHandler(handler)}
if conf.Database.Debug { if conf.Database.Debug {
options = append(options, sloggorm.WithTraceAll()) options = append(options, sloggorm.WithTraceAll())
@@ -52,8 +58,9 @@ func NewDB(conf *config.Config) (*gorm.DB, error) {
return db, nil return db, nil
} }
func NewMigrate(db *gorm.DB) *gormigrate.Gormigrate { func NewMigrate(i do.Injector) (*gormigrate.Gormigrate, error) {
db := do.MustInvoke[*gorm.DB](i)
return gormigrate.New(db, &gormigrate.Options{ return gormigrate.New(db, &gormigrate.Options{
UseTransaction: true, // Note: MySQL not support DDL transaction UseTransaction: true, // Note: MySQL not support DDL transaction
}, migration.Migrations) }, migration.Migrations), nil
} }
+132 -11
View File
@@ -1,36 +1,93 @@
package bootstrap package bootstrap
import ( import (
"bytes"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io"
"io/fs"
"mime"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strings"
"github.com/andybalholm/brotli"
"github.com/bddjr/hlfhr" "github.com/bddjr/hlfhr"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/libtnb/validator"
"github.com/libtnb/validator/contrib/openapi"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/internal/http/middleware" "github.com/acepanel/panel/v3/internal/middleware"
"github.com/acepanel/panel/v3/internal/route" "github.com/acepanel/panel/v3/internal/route"
"github.com/acepanel/panel/v3/pkg/apploader"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
"github.com/acepanel/panel/v3/pkg/embed"
"github.com/acepanel/panel/v3/pkg/tlscert" "github.com/acepanel/panel/v3/pkg/tlscert"
) )
func NewRouter(t *gotext.Locale, middlewares *middleware.Middlewares, http *route.Http, ws *route.Ws) (*chi.Mux, error) { func NewRouter(i do.Injector) (*chi.Mux, error) {
r := chi.NewRouter() t := do.MustInvoke[*gotext.Locale](i)
mws := do.MustInvoke[*middleware.Middlewares](i)
conf := do.MustInvoke[*config.Config](i)
loader := do.MustInvoke[*apploader.Loader](i)
// 供 service.Bind / route.SpecJSON 使用
validator.SetDefault(do.MustInvoke[*validator.Validator](i))
// add middleware // 数据驱动的登录白名单
r.Use(middlewares.Globals(t, r)...) public, err := route.PublicPaths(i)
// add http route if err != nil {
http.Register(r) return nil, err
// add ws route }
ws.Register(r)
r := chi.NewRouter()
r.Use(mws.Globals(t, r, public)...)
// 注册各域路由
if err := route.HTTP(i, r); err != nil {
return nil, err
}
// 动态应用子路由
r.Route("/api/apps", func(r chi.Router) {
loader.Register(r)
})
// 仅调试模式挂载 OpenAPI 文档
if conf.App.Debug {
spec, err := route.SpecJSON(i, "AcePanel")
if err != nil {
return nil, err
}
docs := openapi.DocsHTML("AcePanel", "/openapi.json")
r.Get("/openapi.json", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(spec)
})
r.Get("/docs", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, _ = w.Write(docs)
})
}
r.NotFound(func(w http.ResponseWriter, req *http.Request) {
// /api 开头的返回 404
if strings.HasPrefix(req.URL.Path, "/api") {
http.NotFound(w, req)
return
}
// 其他返回前端页面
frontend, _ := fs.Sub(embed.PublicFS, "frontend")
newPrecompressedSPAHandler(http.FS(frontend)).ServeHTTP(w, req)
})
return r, nil return r, nil
} }
func NewTLSReloader(conf *config.Config) (*tlscert.Reloader, error) { func NewTLSReloader(i do.Injector) (*tlscert.Reloader, error) {
conf := do.MustInvoke[*config.Config](i)
if !conf.HTTP.IsHTTPS() { if !conf.HTTP.IsHTTPS() {
return nil, nil return nil, nil
} }
@@ -44,7 +101,11 @@ func NewTLSReloader(conf *config.Config) (*tlscert.Reloader, error) {
return reloader, nil return reloader, nil
} }
func NewHttp(conf *config.Config, mux *chi.Mux, reloader *tlscert.Reloader) (*hlfhr.Server, error) { func NewHttp(i do.Injector) (*hlfhr.Server, error) {
conf := do.MustInvoke[*config.Config](i)
mux := do.MustInvoke[*chi.Mux](i)
reloader := do.MustInvoke[*tlscert.Reloader](i)
srv := hlfhr.New(&http.Server{ srv := hlfhr.New(&http.Server{
Addr: fmt.Sprintf(":%d", conf.HTTP.Port), Addr: fmt.Sprintf(":%d", conf.HTTP.Port),
Handler: mux, Handler: mux,
@@ -61,3 +122,63 @@ func NewHttp(conf *config.Config, mux *chi.Mux, reloader *tlscert.Reloader) (*hl
return srv, nil return srv, nil
} }
func newPrecompressedSPAHandler(fsys http.FileSystem) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
acceptBr := strings.Contains(r.Header.Get("Accept-Encoding"), "br")
if served := serveFileWithBr(w, r, fsys, path, acceptBr); served {
return
}
// 文件不存在,SPA fallback 到 index.html
serveFileWithBr(w, r, fsys, "/index.html", acceptBr)
}
}
func serveFileWithBr(w http.ResponseWriter, r *http.Request, fsys http.FileSystem, path string, acceptBr bool) bool {
name := filepath.Base(path)
// 尝试打开 .br 版本
if f, err := fsys.Open(path + ".br"); err == nil {
defer func(f http.File) { _ = f.Close() }(f)
fi, err := f.Stat()
if err != nil || fi.IsDir() {
return false
}
ct := mime.TypeByExtension(filepath.Ext(path))
if ct == "" {
ct = "application/octet-stream"
}
w.Header().Set("Content-Type", ct)
w.Header().Set("Vary", "Accept-Encoding")
if acceptBr {
// 客户端支持 br,直接透传
w.Header().Set("Content-Encoding", "br")
http.ServeContent(w, r, name, fi.ModTime(), f)
} else {
// 客户端不支持 br,解压后返回(由中间件处理 gzip)
decoded, err := io.ReadAll(brotli.NewReader(f))
if err != nil {
return false
}
http.ServeContent(w, r, name, fi.ModTime(), bytes.NewReader(decoded))
}
return true
}
// 回退到原始文件(字体、图片等未压缩的资源)
f, err := fsys.Open(path)
if err != nil {
return false
}
defer func(f http.File) { _ = f.Close() }(f)
fi, err := f.Stat()
if err != nil || fi.IsDir() {
return false
}
http.ServeContent(w, r, name, fi.ModTime(), f)
return true
}
+32 -12
View File
@@ -3,22 +3,37 @@ package bootstrap
import ( import (
"log/slog" "log/slog"
"path/filepath" "path/filepath"
"time"
"github.com/DeRuina/timberjack" "github.com/libtnb/logrotate"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/internal/app" "github.com/acepanel/panel/v3/internal/app"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
) )
func NewLog(conf *config.Config) *slog.Logger { type Logger struct {
tjLogger := &timberjack.Logger{ *slog.Logger
Filename: filepath.Join(app.Root, "panel/storage/logs/app.log"), close func() error
MaxSize: 10, }
MaxAge: 30,
LocalTime: true, func (l *Logger) Shutdown() error {
RotateAt: []string{"00:00"}, return l.close()
FileMode: 0o600, }
Compression: "none",
// NewLogger 构建写入轮转文件的应用日志。
func NewLogger(i do.Injector) (*Logger, error) {
conf := do.MustInvoke[*config.Config](i)
w, err := logrotate.New(filepath.Join(app.Root, "panel/storage/logs/app.log"),
logrotate.WithMaxSize(10*logrotate.MB),
logrotate.WithMaxAge(30*logrotate.Day),
logrotate.WithRotateAt("00:00"),
logrotate.WithFileMode(0o600),
logrotate.WithLocation(time.Local),
)
if err != nil {
return nil, err
} }
level := slog.LevelInfo level := slog.LevelInfo
@@ -26,10 +41,15 @@ func NewLog(conf *config.Config) *slog.Logger {
level = slog.LevelDebug level = slog.LevelDebug
} }
log := slog.New(slog.NewJSONHandler(tjLogger, &slog.HandlerOptions{ log := slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{
Level: level, Level: level,
})) }))
slog.SetDefault(log) slog.SetDefault(log)
return log return &Logger{Logger: log, close: w.Close}, nil
}
// NewSlog 解包出纯 *slog.Logger 供应用其余部分使用。
func NewSlog(i do.Injector) (*slog.Logger, error) {
return do.MustInvoke[*Logger](i).Logger, nil
} }
+3 -2
View File
@@ -3,6 +3,7 @@ package bootstrap
import ( import (
"log/slog" "log/slog"
"github.com/samber/do/v2"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/taskqueue" "github.com/acepanel/panel/v3/internal/taskqueue"
@@ -10,6 +11,6 @@ import (
) )
// NewRunner 创建任务运行器 // NewRunner 创建任务运行器
func NewRunner(db *gorm.DB, log *slog.Logger) types.TaskRunner { func NewRunner(i do.Injector) (types.TaskRunner, error) {
return taskqueue.NewRunner(db, log) return taskqueue.NewRunner(do.MustInvoke[*gorm.DB](i), do.MustInvoke[*slog.Logger](i)), nil
} }
+8 -2
View File
@@ -1,27 +1,33 @@
package bootstrap package bootstrap
import ( import (
"log/slog"
"github.com/libtnb/gormstore" "github.com/libtnb/gormstore"
"github.com/libtnb/sessions" "github.com/libtnb/sessions"
"github.com/samber/do/v2"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
) )
func NewSession(conf *config.Config, db *gorm.DB) (*sessions.Manager, error) { func NewSession(i do.Injector) (*sessions.Manager, error) {
conf := do.MustInvoke[*config.Config](i)
// initialize session manager // initialize session manager
manager, err := sessions.NewManager(&sessions.ManagerOptions{ manager, err := sessions.NewManager(&sessions.ManagerOptions{
Key: conf.App.Key, Key: conf.App.Key,
Lifetime: int(conf.Session.Lifetime), Lifetime: int(conf.Session.Lifetime),
GcInterval: 5, GcInterval: 5,
DisableDefaultDriver: true, DisableDefaultDriver: true,
Logger: do.MustInvoke[*slog.Logger](i),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
// extend gorm store driver // extend gorm store driver
store := gormstore.New(db) store := gormstore.New(do.MustInvoke[*gorm.DB](i))
if err = manager.Extend("default", store); err != nil { if err = manager.Extend("default", store); err != nil {
return nil, err return nil, err
} }
+4 -1
View File
@@ -2,12 +2,15 @@ package bootstrap
import ( import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
"github.com/acepanel/panel/v3/pkg/embed" "github.com/acepanel/panel/v3/pkg/embed"
) )
func NewT(conf *config.Config) (*gotext.Locale, error) { func NewT(i do.Injector) (*gotext.Locale, error) {
conf := do.MustInvoke[*config.Config](i)
l := gotext.NewLocaleFSWithPath(conf.App.Locale, embed.LocalesFS, "locales") l := gotext.NewLocaleFSWithPath(conf.App.Locale, embed.LocalesFS, "locales")
l.AddDomain("backend") l.AddDomain("backend")
@@ -1,17 +1,19 @@
package service package bootstrap
import ( import (
"github.com/libtnb/validator" "github.com/libtnb/validator"
"github.com/libtnb/validator/translations" "github.com/libtnb/validator/translations"
"github.com/samber/do/v2"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/acepanel/panel/v3/internal/http/rule" "github.com/acepanel/panel/v3/internal/rule"
"github.com/acepanel/panel/v3/pkg/config" "github.com/acepanel/panel/v3/pkg/config"
) )
var sharedValidator *validator.Validator // NewValidator 构建校验器
func NewValidator(i do.Injector) (*validator.Validator, error) {
conf := do.MustInvoke[*config.Config](i)
func NewValidator(conf *config.Config, db *gorm.DB) *validator.Validator {
opts := []validator.Option{validator.WithStrictRequired()} opts := []validator.Option{validator.WithStrictRequired()}
switch conf.App.Locale { switch conf.App.Locale {
case "zh_CN": case "zh_CN":
@@ -21,7 +23,7 @@ func NewValidator(conf *config.Config, db *gorm.DB) *validator.Validator {
} }
v := validator.NewValidator(opts...) v := validator.NewValidator(opts...)
rule.RegisterRules(v, db) rule.RegisterRules(v, do.MustInvoke[*gorm.DB](i))
sharedValidator = v
return v return v, nil
} }
+59
View File
@@ -0,0 +1,59 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// AppCommand 应用管理命令组
func AppCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "app",
Usage: t.Get("Application management"),
Commands: []*cli.Command{
{
Name: "install",
Usage: t.Get("Install application"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).AppInstall(ctx, cmd)
},
},
{
Name: "uninstall",
Usage: t.Get("Uninstall application"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).AppUnInstall(ctx, cmd)
},
},
{
Name: "update",
Usage: t.Get("Update application"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).AppUpdate(ctx, cmd)
},
},
{
Name: "write",
Usage: t.Get("Add panel application mark (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).AppWrite(ctx, cmd)
},
},
{
Name: "remove",
Usage: t.Get("Remove panel application mark (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).AppRemove(ctx, cmd)
},
},
},
}, nil
}
+128
View File
@@ -0,0 +1,128 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// BackupCommand 数据备份命令组
func BackupCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "backup",
Usage: t.Get("Data backup"),
Commands: []*cli.Command{
{
Name: "website",
Usage: t.Get("Backup website"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: t.Get("Website name"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BackupWebsite(ctx, cmd)
},
},
{
Name: "database",
Usage: t.Get("Backup database"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Usage: t.Get("Database type"),
Required: true,
},
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: t.Get("Database name"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BackupDatabase(ctx, cmd)
},
},
{
Name: "path",
Usage: t.Get("Backup directory"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Usage: t.Get("Directory path"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BackupPath(ctx, cmd)
},
},
{
Name: "panel",
Usage: t.Get("Backup panel"),
Flags: []cli.Flag{},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BackupPanel(ctx, cmd)
},
},
{
Name: "clear",
Usage: t.Get("Clear backups"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Usage: t.Get("Backup type"),
Required: true,
},
&cli.StringFlag{
Name: "file",
Aliases: []string{"f"},
Usage: t.Get("Backup file"),
Required: true,
},
&cli.UintFlag{
Name: "keep",
Aliases: []string{"k"},
Usage: t.Get("Number of backups to keep"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BackupClear(ctx, cmd)
},
},
},
}, nil
}
+30
View File
@@ -0,0 +1,30 @@
package command
import (
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/registry"
)
const Prefix = "commands:"
var Package = do.Package(
do.LazyNamed(Prefix+"status", StatusCommand), do.LazyNamed(Prefix+"restart", RestartCommand),
do.LazyNamed(Prefix+"stop", StopCommand), do.LazyNamed(Prefix+"start", StartCommand),
do.LazyNamed(Prefix+"update", UpdateCommand), do.LazyNamed(Prefix+"sync", SyncCommand),
do.LazyNamed(Prefix+"fix", FixCommand), do.LazyNamed(Prefix+"info", InfoCommand),
do.LazyNamed(Prefix+"port", PortCommand), do.LazyNamed(Prefix+"sync-time", SyncTimeCommand),
do.LazyNamed(Prefix+"clear-task", ClearTaskCommand), do.LazyNamed(Prefix+"init", InitCommand),
do.LazyNamed(Prefix+"user", UserCommand), do.LazyNamed(Prefix+"https", HttpsCommand),
do.LazyNamed(Prefix+"entrance", EntranceCommand), do.LazyNamed(Prefix+"bind-domain", BindDomainCommand),
do.LazyNamed(Prefix+"bind-ip", BindIPCommand), do.LazyNamed(Prefix+"bind-ua", BindUACommand),
do.LazyNamed(Prefix+"website", WebsiteCommand), do.LazyNamed(Prefix+"database", DatabaseCommand),
do.LazyNamed(Prefix+"backup", BackupCommand), do.LazyNamed(Prefix+"cutoff", CutoffCommand),
do.LazyNamed(Prefix+"app", AppCommand), do.LazyNamed(Prefix+"setting", SettingCommand),
)
// Commands 收集全部命令贡献。
func Commands(i do.Injector) ([]*cli.Command, error) {
return registry.Collect[*cli.Command](i, Prefix)
}
+94
View File
@@ -0,0 +1,94 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// CutoffCommand 日志切割命令组
func CutoffCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "cutoff",
Usage: t.Get("Log rotation"),
Commands: []*cli.Command{
{
Name: "website",
Usage: t.Get("Website"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: t.Get("Website name"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).CutoffWebsite(ctx, cmd)
},
},
{
Name: "container",
Usage: t.Get("Container"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: t.Get("Container name"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).CutoffContainer(ctx, cmd)
},
},
{
Name: "clear",
Usage: t.Get("Clear rotated logs"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Usage: t.Get("Rotation type"),
Required: true,
},
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: t.Get("Target name"),
Required: true,
},
&cli.UintFlag{
Name: "keep",
Aliases: []string{"k"},
Usage: t.Get("Number of logs to keep"),
Required: true,
},
&cli.UintFlag{
Name: "storage",
Aliases: []string{"s"},
Usage: t.Get("Storage ID (local storage if not filled)"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).CutoffClear(ctx, cmd)
},
},
},
}, nil
}
+78
View File
@@ -0,0 +1,78 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// DatabaseCommand 数据库管理命令组
func DatabaseCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "database",
Usage: t.Get("Database management"),
Commands: []*cli.Command{
{
Name: "add-server",
Usage: t.Get("Add database server"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Usage: t.Get("Server type"),
Required: true,
},
&cli.StringFlag{
Name: "name",
Usage: t.Get("Server name"),
Required: true,
},
&cli.StringFlag{
Name: "host",
Usage: t.Get("Server address"),
Required: true,
},
&cli.UintFlag{
Name: "port",
Usage: t.Get("Server port"),
Required: true,
},
&cli.StringFlag{
Name: "username",
Usage: t.Get("Server username"),
},
&cli.StringFlag{
Name: "password",
Usage: t.Get("Server password"),
},
&cli.StringFlag{
Name: "remark",
Usage: t.Get("Server remark"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).DatabaseAddServer(ctx, cmd)
},
},
{
Name: "delete-server",
Usage: t.Get("Delete database server"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: t.Get("Server name"),
Aliases: []string{"n"},
Required: true,
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).DatabaseDeleteServer(ctx, cmd)
},
},
},
}, nil
}
+90
View File
@@ -0,0 +1,90 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// EntranceCommand 访问入口管理命令组
func EntranceCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "entrance",
Usage: t.Get("Operate AcePanel access entrance"),
Commands: []*cli.Command{
{
Name: "on",
Usage: t.Get("Enable access entrance"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).EntranceOn(ctx, cmd)
},
},
{
Name: "off",
Usage: t.Get("Disable access entrance"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).EntranceOff(ctx, cmd)
},
},
},
}, nil
}
// BindDomainCommand 域名绑定管理命令组
func BindDomainCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "bind-domain",
Usage: t.Get("Operate AcePanel domain binding"),
Commands: []*cli.Command{
{
Name: "off",
Usage: t.Get("Disable domain binding"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BindDomainOff(ctx, cmd)
},
},
},
}, nil
}
// BindIPCommand IP 绑定管理命令组
func BindIPCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "bind-ip",
Usage: t.Get("Operate AcePanel IP binding"),
Commands: []*cli.Command{
{
Name: "off",
Usage: t.Get("Disable IP binding"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BindIPOff(ctx, cmd)
},
},
},
}, nil
}
// BindUACommand UA 绑定管理命令组
func BindUACommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "bind-ua",
Usage: t.Get("Operate AcePanel UA binding"),
Commands: []*cli.Command{
{
Name: "off",
Usage: t.Get("Disable UA binding"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).BindUAOff(ctx, cmd)
},
},
},
}, nil
}
+43
View File
@@ -0,0 +1,43 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// HttpsCommand 面板 HTTPS 管理命令组
func HttpsCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "https",
Usage: t.Get("Operate AcePanel HTTPS"),
Commands: []*cli.Command{
{
Name: "on",
Usage: t.Get("Enable HTTPS"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).HTTPSOn(ctx, cmd)
},
},
{
Name: "off",
Usage: t.Get("Disable HTTPS"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).HTTPSOff(ctx, cmd)
},
},
{
Name: "generate",
Usage: t.Get("Obtain a free certificate or generate a self-signed certificate"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).HTTPSGenerate(ctx, cmd)
},
},
},
}, nil
}
+116
View File
@@ -0,0 +1,116 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// UpdateCommand 更新面板
func UpdateCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "update",
Usage: t.Get("Update AcePanel to the latest version"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Update(ctx, cmd)
},
}, nil
}
// SyncCommand 同步云端缓存数据
func SyncCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "sync",
Usage: t.Get("Sync AcePanel cached data with cloud"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Sync(ctx, cmd)
},
}, nil
}
// FixCommand 修复升级问题
func FixCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "fix",
Usage: t.Get("Fix AcePanel upgrade issues"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Fix(ctx, cmd)
},
}, nil
}
// InfoCommand 输出面板基础信息
func InfoCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "info",
Usage: t.Get("Output AcePanel basic information"),
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Usage: t.Get("Force reset password"),
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Info(ctx, cmd)
},
}, nil
}
// PortCommand 修改监听端口
func PortCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "port",
Usage: t.Get("Change the AcePanel listening port"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Port(ctx, cmd)
},
}, nil
}
// SyncTimeCommand 通过 NTP 同步系统时间
func SyncTimeCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "sync-time",
Usage: t.Get("Sync server time with NTP"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).SyncTime(ctx, cmd)
},
}, nil
}
// ClearTaskCommand 清理卡住的任务队列
func ClearTaskCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "clear-task",
Usage: t.Get("Clear all tasks in the task queue if they are stuck (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).ClearTask(ctx, cmd)
},
}, nil
}
// InitCommand 初始化面板
func InitCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "init",
Usage: t.Get("Initialize AcePanel (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Init(ctx, cmd)
},
}, nil
}
+59
View File
@@ -0,0 +1,59 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// StatusCommand 查询服务状态
func StatusCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "status",
Usage: t.Get("Get AcePanel service status"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Status(ctx, cmd)
},
}, nil
}
// RestartCommand 重启服务
func RestartCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "restart",
Usage: t.Get("Restart AcePanel service"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Restart(ctx, cmd)
},
}, nil
}
// StopCommand 停止服务
func StopCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "stop",
Usage: t.Get("Stop AcePanel service"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Stop(ctx, cmd)
},
}, nil
}
// StartCommand 启动服务
func StartCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "start",
Usage: t.Get("Start AcePanel service"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).Start(ctx, cmd)
},
}, nil
}
+47
View File
@@ -0,0 +1,47 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// SettingCommand 面板设置管理命令组
func SettingCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "setting",
Usage: t.Get("Setting management"),
Hidden: true,
Commands: []*cli.Command{
{
Name: "get",
Usage: t.Get("Get panel setting (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).GetSetting(ctx, cmd)
},
},
{
Name: "write",
Usage: t.Get("Write panel setting (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).WriteSetting(ctx, cmd)
},
},
{
Name: "remove",
Usage: t.Get("Remove panel setting (use only under guidance)"),
Hidden: true,
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).RemoveSetting(ctx, cmd)
},
},
},
}, nil
}
+57
View File
@@ -0,0 +1,57 @@
package command
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/samber/do/v2"
"github.com/urfave/cli/v3"
"github.com/acepanel/panel/v3/internal/service"
)
// UserCommand 用户管理命令组
func UserCommand(i do.Injector) (*cli.Command, error) {
t := do.MustInvoke[*gotext.Locale](i)
return &cli.Command{
Name: "user",
Usage: t.Get("Operate AcePanel users"),
Commands: []*cli.Command{
{
Name: "list",
Usage: t.Get("List all users"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).UserList(ctx, cmd)
},
},
{
Name: "username",
Usage: t.Get("Change a user's username"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).UserName(ctx, cmd)
},
},
{
Name: "password",
Usage: t.Get("Change a user's password"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).UserPassword(ctx, cmd)
},
},
{
Name: "2fa",
Usage: t.Get("Toggle two-factor authentication for a user"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).UserTwoFA(ctx, cmd)
},
},
{
Name: "passkey",
Usage: t.Get("Clear all passkeys for a user"),
Action: func(ctx context.Context, cmd *cli.Command) error {
return do.MustInvoke[*service.CliService](i).UserPasskey(ctx, cmd)
},
},
},
}, nil
}

Some files were not shown because too many files have changed in this diff Show More