mirror of
https://github.com/tnb-labs/panel.git
synced 2026-08-31 01:12:17 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6b016d5e8 | |||
| 645a6d2b98 | |||
| 7dc98096a5 | |||
| 4f5961d7f7 | |||
| 4beb040b3d | |||
| 092da898b8 | |||
| 818c5b466b | |||
| 5dc14ef1bb | |||
| 813a8f42cf | |||
| 47fbbe7134 | |||
| 50d988a62b | |||
| 8e3d929def | |||
| 3022c91eb3 |
+2
-1
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/apps"
|
||||
"github.com/tnb-labs/panel/internal/bootstrap"
|
||||
"github.com/tnb-labs/panel/internal/data"
|
||||
"github.com/tnb-labs/panel/internal/route"
|
||||
@@ -14,5 +15,5 @@ import (
|
||||
|
||||
// initCli init command line.
|
||||
func initCli() (*app.Cli, error) {
|
||||
panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, app.NewCli))
|
||||
panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, app.NewCli))
|
||||
}
|
||||
|
||||
+48
-1
@@ -8,6 +8,29 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/apps/benchmark"
|
||||
"github.com/tnb-labs/panel/internal/apps/docker"
|
||||
"github.com/tnb-labs/panel/internal/apps/fail2ban"
|
||||
"github.com/tnb-labs/panel/internal/apps/frp"
|
||||
"github.com/tnb-labs/panel/internal/apps/gitea"
|
||||
"github.com/tnb-labs/panel/internal/apps/memcached"
|
||||
"github.com/tnb-labs/panel/internal/apps/mysql"
|
||||
"github.com/tnb-labs/panel/internal/apps/nginx"
|
||||
"github.com/tnb-labs/panel/internal/apps/php74"
|
||||
"github.com/tnb-labs/panel/internal/apps/php80"
|
||||
"github.com/tnb-labs/panel/internal/apps/php81"
|
||||
"github.com/tnb-labs/panel/internal/apps/php82"
|
||||
"github.com/tnb-labs/panel/internal/apps/php83"
|
||||
"github.com/tnb-labs/panel/internal/apps/php84"
|
||||
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
|
||||
"github.com/tnb-labs/panel/internal/apps/podman"
|
||||
"github.com/tnb-labs/panel/internal/apps/postgresql"
|
||||
"github.com/tnb-labs/panel/internal/apps/pureftpd"
|
||||
"github.com/tnb-labs/panel/internal/apps/redis"
|
||||
"github.com/tnb-labs/panel/internal/apps/rsync"
|
||||
"github.com/tnb-labs/panel/internal/apps/s3fs"
|
||||
"github.com/tnb-labs/panel/internal/apps/supervisor"
|
||||
"github.com/tnb-labs/panel/internal/apps/toolbox"
|
||||
"github.com/tnb-labs/panel/internal/bootstrap"
|
||||
"github.com/tnb-labs/panel/internal/data"
|
||||
"github.com/tnb-labs/panel/internal/route"
|
||||
@@ -48,6 +71,30 @@ func initCli() (*app.Cli, error) {
|
||||
cli := route.NewCli(cliService)
|
||||
command := bootstrap.NewCli(cli)
|
||||
gormigrate := bootstrap.NewMigrate(db)
|
||||
appCli := app.NewCli(command, gormigrate)
|
||||
benchmarkApp := benchmark.NewApp()
|
||||
dockerApp := docker.NewApp()
|
||||
fail2banApp := fail2ban.NewApp(websiteRepo)
|
||||
frpApp := frp.NewApp()
|
||||
giteaApp := gitea.NewApp()
|
||||
memcachedApp := memcached.NewApp()
|
||||
mysqlApp := mysql.NewApp(settingRepo)
|
||||
nginxApp := nginx.NewApp()
|
||||
php74App := php74.NewApp(taskRepo)
|
||||
php80App := php80.NewApp(taskRepo)
|
||||
php81App := php81.NewApp(taskRepo)
|
||||
php82App := php82.NewApp(taskRepo)
|
||||
php83App := php83.NewApp(taskRepo)
|
||||
php84App := php84.NewApp(taskRepo)
|
||||
phpmyadminApp := phpmyadmin.NewApp()
|
||||
podmanApp := podman.NewApp()
|
||||
postgresqlApp := postgresql.NewApp()
|
||||
pureftpdApp := pureftpd.NewApp()
|
||||
redisApp := redis.NewApp()
|
||||
rsyncApp := rsync.NewApp()
|
||||
s3fsApp := s3fs.NewApp(settingRepo)
|
||||
supervisorApp := supervisor.NewApp()
|
||||
toolboxApp := toolbox.NewApp()
|
||||
loader := bootstrap.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, php74App, php80App, php81App, php82App, php83App, php84App, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
|
||||
appCli := app.NewCli(command, gormigrate, loader)
|
||||
return appCli, nil
|
||||
}
|
||||
|
||||
+13
-4
@@ -8,7 +8,6 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/apps"
|
||||
"github.com/tnb-labs/panel/internal/apps/benchmark"
|
||||
"github.com/tnb-labs/panel/internal/apps/docker"
|
||||
"github.com/tnb-labs/panel/internal/apps/fail2ban"
|
||||
@@ -17,7 +16,12 @@ import (
|
||||
"github.com/tnb-labs/panel/internal/apps/memcached"
|
||||
"github.com/tnb-labs/panel/internal/apps/mysql"
|
||||
"github.com/tnb-labs/panel/internal/apps/nginx"
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/apps/php74"
|
||||
"github.com/tnb-labs/panel/internal/apps/php80"
|
||||
"github.com/tnb-labs/panel/internal/apps/php81"
|
||||
"github.com/tnb-labs/panel/internal/apps/php82"
|
||||
"github.com/tnb-labs/panel/internal/apps/php83"
|
||||
"github.com/tnb-labs/panel/internal/apps/php84"
|
||||
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
|
||||
"github.com/tnb-labs/panel/internal/apps/podman"
|
||||
"github.com/tnb-labs/panel/internal/apps/postgresql"
|
||||
@@ -112,7 +116,12 @@ func initWeb() (*app.Web, error) {
|
||||
memcachedApp := memcached.NewApp()
|
||||
mysqlApp := mysql.NewApp(settingRepo)
|
||||
nginxApp := nginx.NewApp()
|
||||
phpApp := php.NewApp(taskRepo)
|
||||
php74App := php74.NewApp(taskRepo)
|
||||
php80App := php80.NewApp(taskRepo)
|
||||
php81App := php81.NewApp(taskRepo)
|
||||
php82App := php82.NewApp(taskRepo)
|
||||
php83App := php83.NewApp(taskRepo)
|
||||
php84App := php84.NewApp(taskRepo)
|
||||
phpmyadminApp := phpmyadmin.NewApp()
|
||||
podmanApp := podman.NewApp()
|
||||
postgresqlApp := postgresql.NewApp()
|
||||
@@ -122,7 +131,7 @@ func initWeb() (*app.Web, error) {
|
||||
s3fsApp := s3fs.NewApp(settingRepo)
|
||||
supervisorApp := supervisor.NewApp()
|
||||
toolboxApp := toolbox.NewApp()
|
||||
loader := apps.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, phpApp, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
|
||||
loader := bootstrap.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, php74App, php80App, php81App, php82App, php83App, php84App, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
|
||||
http := route.NewHttp(userService, dashboardService, taskService, websiteService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, cronService, processService, safeService, firewallService, sshService, containerService, containerNetworkService, containerImageService, containerVolumeService, fileService, monitorService, settingService, systemctlService, loader)
|
||||
wsService := service.NewWsService(koanf, sshRepo)
|
||||
ws := route.NewWs(wsService)
|
||||
|
||||
+3
-1
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/tnb-labs/panel/pkg/apploader"
|
||||
)
|
||||
|
||||
type Cli struct {
|
||||
@@ -14,7 +16,7 @@ type Cli struct {
|
||||
migrator *gormigrate.Gormigrate
|
||||
}
|
||||
|
||||
func NewCli(cmd *cli.Command, migrator *gormigrate.Gormigrate) *Cli {
|
||||
func NewCli(cmd *cli.Command, migrator *gormigrate.Gormigrate, _ *apploader.Loader) *Cli {
|
||||
IsCli = true
|
||||
return &Cli{
|
||||
cmd: cmd,
|
||||
|
||||
@@ -11,11 +11,11 @@ const (
|
||||
|
||||
// 面板全局变量
|
||||
var (
|
||||
Key string
|
||||
Root string
|
||||
Locale string
|
||||
IsCli bool
|
||||
Status = StatusNormal
|
||||
Key string // 密钥
|
||||
Root string // 根目录
|
||||
Locale string // 语言
|
||||
IsCli bool // 是否命令行
|
||||
Status = StatusNormal // 面板状态
|
||||
)
|
||||
|
||||
// 自动注入
|
||||
|
||||
+12
-127
@@ -1,11 +1,6 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/benchmark"
|
||||
@@ -16,7 +11,12 @@ import (
|
||||
"github.com/tnb-labs/panel/internal/apps/memcached"
|
||||
"github.com/tnb-labs/panel/internal/apps/mysql"
|
||||
"github.com/tnb-labs/panel/internal/apps/nginx"
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/apps/php74"
|
||||
"github.com/tnb-labs/panel/internal/apps/php80"
|
||||
"github.com/tnb-labs/panel/internal/apps/php81"
|
||||
"github.com/tnb-labs/panel/internal/apps/php82"
|
||||
"github.com/tnb-labs/panel/internal/apps/php83"
|
||||
"github.com/tnb-labs/panel/internal/apps/php84"
|
||||
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
|
||||
"github.com/tnb-labs/panel/internal/apps/podman"
|
||||
"github.com/tnb-labs/panel/internal/apps/postgresql"
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
)
|
||||
|
||||
var ProviderSet = wire.NewSet(
|
||||
NewLoader,
|
||||
benchmark.NewApp,
|
||||
docker.NewApp,
|
||||
fail2ban.NewApp,
|
||||
@@ -38,7 +37,12 @@ var ProviderSet = wire.NewSet(
|
||||
memcached.NewApp,
|
||||
mysql.NewApp,
|
||||
nginx.NewApp,
|
||||
php.NewApp,
|
||||
php74.NewApp,
|
||||
php80.NewApp,
|
||||
php81.NewApp,
|
||||
php82.NewApp,
|
||||
php83.NewApp,
|
||||
php84.NewApp,
|
||||
phpmyadmin.NewApp,
|
||||
podman.NewApp,
|
||||
postgresql.NewApp,
|
||||
@@ -49,122 +53,3 @@ var ProviderSet = wire.NewSet(
|
||||
supervisor.NewApp,
|
||||
toolbox.NewApp,
|
||||
)
|
||||
|
||||
var slugs []string
|
||||
|
||||
type Loader struct {
|
||||
benchmark *benchmark.App
|
||||
docker *docker.App
|
||||
fail2ban *fail2ban.App
|
||||
frp *frp.App
|
||||
gitea *gitea.App
|
||||
memcached *memcached.App
|
||||
mysql *mysql.App
|
||||
nginx *nginx.App
|
||||
php *php.App
|
||||
phpmyadmin *phpmyadmin.App
|
||||
podman *podman.App
|
||||
postgresql *postgresql.App
|
||||
pureftpd *pureftpd.App
|
||||
redis *redis.App
|
||||
rsync *rsync.App
|
||||
s3fs *s3fs.App
|
||||
supervisor *supervisor.App
|
||||
toolbox *toolbox.App
|
||||
}
|
||||
|
||||
func NewLoader(
|
||||
benchmark *benchmark.App,
|
||||
docker *docker.App,
|
||||
fail2ban *fail2ban.App,
|
||||
frp *frp.App,
|
||||
gitea *gitea.App,
|
||||
memcached *memcached.App,
|
||||
mysql *mysql.App,
|
||||
nginx *nginx.App,
|
||||
php *php.App,
|
||||
phpmyadmin *phpmyadmin.App,
|
||||
podman *podman.App,
|
||||
postgresql *postgresql.App,
|
||||
pureftpd *pureftpd.App,
|
||||
redis *redis.App,
|
||||
rsync *rsync.App,
|
||||
s3fs *s3fs.App,
|
||||
supervisor *supervisor.App,
|
||||
toolbox *toolbox.App,
|
||||
) *Loader {
|
||||
loader := &Loader{
|
||||
benchmark: benchmark,
|
||||
docker: docker,
|
||||
fail2ban: fail2ban,
|
||||
frp: frp,
|
||||
gitea: gitea,
|
||||
memcached: memcached,
|
||||
mysql: mysql,
|
||||
nginx: nginx,
|
||||
php: php,
|
||||
phpmyadmin: phpmyadmin,
|
||||
podman: podman,
|
||||
postgresql: postgresql,
|
||||
pureftpd: pureftpd,
|
||||
redis: redis,
|
||||
rsync: rsync,
|
||||
s3fs: s3fs,
|
||||
supervisor: supervisor,
|
||||
toolbox: toolbox,
|
||||
}
|
||||
|
||||
loader.initSlugs()
|
||||
return loader
|
||||
}
|
||||
|
||||
func (r *Loader) Register(mux chi.Router) {
|
||||
mux.Route("/benchmark", r.benchmark.Route)
|
||||
mux.Route("/docker", r.docker.Route)
|
||||
mux.Route("/fail2ban", r.fail2ban.Route)
|
||||
mux.Route("/frp", r.frp.Route)
|
||||
mux.Route("/gitea", r.gitea.Route)
|
||||
mux.Route("/memcached", r.memcached.Route)
|
||||
mux.Route("/mysql", r.mysql.Route)
|
||||
mux.Route("/nginx", r.nginx.Route)
|
||||
mux.Route("/php74", r.php.Route(74))
|
||||
mux.Route("/php80", r.php.Route(80))
|
||||
mux.Route("/php81", r.php.Route(81))
|
||||
mux.Route("/php82", r.php.Route(82))
|
||||
mux.Route("/php83", r.php.Route(83))
|
||||
mux.Route("/php84", r.php.Route(84))
|
||||
mux.Route("/phpmyadmin", r.phpmyadmin.Route)
|
||||
mux.Route("/podman", r.podman.Route)
|
||||
mux.Route("/postgresql", r.postgresql.Route)
|
||||
mux.Route("/pureftpd", r.pureftpd.Route)
|
||||
mux.Route("/redis", r.redis.Route)
|
||||
mux.Route("/rsync", r.rsync.Route)
|
||||
mux.Route("/s3fs", r.s3fs.Route)
|
||||
mux.Route("/supervisor", r.supervisor.Route)
|
||||
mux.Route("/toolbox", r.toolbox.Route)
|
||||
}
|
||||
|
||||
func (r *Loader) initSlugs() []string {
|
||||
if len(slugs) == 0 {
|
||||
v := reflect.Indirect(reflect.ValueOf(r))
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
slug := strings.ToLower(v.Type().Field(i).Name)
|
||||
if !field.IsNil() {
|
||||
slugs = append(slugs, slug)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理php
|
||||
slugs = slices.DeleteFunc(slugs, func(slug string) bool {
|
||||
return slug == "php"
|
||||
})
|
||||
slugs = append(slugs, "php74", "php80", "php81", "php82", "php83", "php84")
|
||||
}
|
||||
|
||||
return slugs
|
||||
}
|
||||
|
||||
func Slugs() []string {
|
||||
return slugs
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package php74
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(74)(r)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package php80
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(80)(r)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package php81
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(81)(r)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package php82
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(82)(r)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package php83
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(83)(r)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package php84
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps/php"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
php *php.App
|
||||
}
|
||||
|
||||
func NewApp(task biz.TaskRepo) *App {
|
||||
return &App{
|
||||
php: php.NewApp(task),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *App) Route(r chi.Router) {
|
||||
s.php.Route(84)(r)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
SettingKeyWebsitePath SettingKey = "website_path"
|
||||
SettingKeyMySQLRootPassword SettingKey = "mysql_root_password"
|
||||
SettingKeyOfflineMode SettingKey = "offline_mode"
|
||||
SettingKeyAutoUpdate SettingKey = "auto_update"
|
||||
)
|
||||
|
||||
type Setting struct {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/tnb-labs/panel/internal/apps/benchmark"
|
||||
"github.com/tnb-labs/panel/internal/apps/docker"
|
||||
"github.com/tnb-labs/panel/internal/apps/fail2ban"
|
||||
"github.com/tnb-labs/panel/internal/apps/frp"
|
||||
"github.com/tnb-labs/panel/internal/apps/gitea"
|
||||
"github.com/tnb-labs/panel/internal/apps/memcached"
|
||||
"github.com/tnb-labs/panel/internal/apps/mysql"
|
||||
"github.com/tnb-labs/panel/internal/apps/nginx"
|
||||
"github.com/tnb-labs/panel/internal/apps/php74"
|
||||
"github.com/tnb-labs/panel/internal/apps/php80"
|
||||
"github.com/tnb-labs/panel/internal/apps/php81"
|
||||
"github.com/tnb-labs/panel/internal/apps/php82"
|
||||
"github.com/tnb-labs/panel/internal/apps/php83"
|
||||
"github.com/tnb-labs/panel/internal/apps/php84"
|
||||
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
|
||||
"github.com/tnb-labs/panel/internal/apps/podman"
|
||||
"github.com/tnb-labs/panel/internal/apps/postgresql"
|
||||
"github.com/tnb-labs/panel/internal/apps/pureftpd"
|
||||
"github.com/tnb-labs/panel/internal/apps/redis"
|
||||
"github.com/tnb-labs/panel/internal/apps/rsync"
|
||||
"github.com/tnb-labs/panel/internal/apps/s3fs"
|
||||
"github.com/tnb-labs/panel/internal/apps/supervisor"
|
||||
"github.com/tnb-labs/panel/internal/apps/toolbox"
|
||||
"github.com/tnb-labs/panel/pkg/apploader"
|
||||
)
|
||||
|
||||
func NewLoader(
|
||||
benchmark *benchmark.App,
|
||||
docker *docker.App,
|
||||
fail2ban *fail2ban.App,
|
||||
frp *frp.App,
|
||||
gitea *gitea.App,
|
||||
memcached *memcached.App,
|
||||
mysql *mysql.App,
|
||||
nginx *nginx.App,
|
||||
php74 *php74.App,
|
||||
php80 *php80.App,
|
||||
php81 *php81.App,
|
||||
php82 *php82.App,
|
||||
php83 *php83.App,
|
||||
php84 *php84.App,
|
||||
phpmyadmin *phpmyadmin.App,
|
||||
podman *podman.App,
|
||||
postgresql *postgresql.App,
|
||||
pureftpd *pureftpd.App,
|
||||
redis *redis.App,
|
||||
rsync *rsync.App,
|
||||
s3fs *s3fs.App,
|
||||
supervisor *supervisor.App,
|
||||
toolbox *toolbox.App,
|
||||
) *apploader.Loader {
|
||||
loader := new(apploader.Loader)
|
||||
loader.Add(benchmark, docker, fail2ban, frp, gitea, memcached, mysql, nginx, php74, php80, php81, php82, php83, php84, phpmyadmin, podman, postgresql, pureftpd, redis, rsync, s3fs, supervisor, toolbox)
|
||||
return loader
|
||||
}
|
||||
@@ -3,4 +3,4 @@ package bootstrap
|
||||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSet is bootstrap providers.
|
||||
var ProviderSet = wire.NewSet(NewConf, NewLog, NewCli, NewValidator, NewRouter, NewHttp, NewDB, NewMigrate, NewSession, NewCron, NewQueue)
|
||||
var ProviderSet = wire.NewSet(NewConf, NewLog, NewCli, NewValidator, NewRouter, NewHttp, NewDB, NewMigrate, NewLoader, NewSession, NewCron, NewQueue)
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/apps"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
"github.com/tnb-labs/panel/pkg/api"
|
||||
"github.com/tnb-labs/panel/pkg/apploader"
|
||||
)
|
||||
|
||||
type cacheRepo struct {
|
||||
@@ -57,8 +57,8 @@ func (r *cacheRepo) UpdateApps() error {
|
||||
}
|
||||
|
||||
// 去除本地不存在的应用
|
||||
*remote = slices.Clip(slices.DeleteFunc(*remote, func(app *api.App) bool {
|
||||
return !slices.Contains(apps.Slugs(), app.Slug)
|
||||
*remote = slices.Clip(slices.DeleteFunc(*remote, func(item *api.App) bool {
|
||||
return !slices.Contains(apploader.Slugs(), item.Slug)
|
||||
}))
|
||||
|
||||
encoded, err := json.Marshal(remote)
|
||||
|
||||
@@ -93,7 +93,11 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offlineMode, err := r.Get(biz.SettingKeyOfflineMode)
|
||||
offlineMode, err := r.GetBool(biz.SettingKeyOfflineMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
autoUpdate, err := r.GetBool(biz.SettingKeyAutoUpdate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,7 +129,8 @@ func (r *settingRepo) GetPanelSetting(ctx context.Context) (*request.PanelSettin
|
||||
Name: name,
|
||||
Locale: r.conf.String("app.locale"),
|
||||
Entrance: r.conf.String("http.entrance"),
|
||||
OfflineMode: cast.ToBool(offlineMode),
|
||||
OfflineMode: offlineMode,
|
||||
AutoUpdate: autoUpdate,
|
||||
WebsitePath: websitePath,
|
||||
BackupPath: backupPath,
|
||||
Username: user.Username,
|
||||
@@ -144,6 +149,9 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
|
||||
if err := r.Set(biz.SettingKeyOfflineMode, cast.ToString(setting.OfflineMode)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := r.Set(biz.SettingKeyAutoUpdate, cast.ToString(setting.AutoUpdate)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := r.Set(biz.SettingKeyWebsitePath, setting.WebsitePath); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ type PanelSetting struct {
|
||||
Locale string `json:"locale" validate:"required"`
|
||||
Entrance string `json:"entrance" validate:"required"`
|
||||
OfflineMode bool `json:"offline_mode"`
|
||||
AutoUpdate bool `json:"auto_update"`
|
||||
WebsitePath string `json:"website_path" validate:"required"`
|
||||
BackupPath string `json:"backup_path" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
|
||||
@@ -33,7 +33,7 @@ func (r *CertRenew) Run() {
|
||||
|
||||
var certs []biz.Cert
|
||||
if err := r.db.Preload("Website").Preload("Account").Preload("DNS").Find(&certs).Error; err != nil {
|
||||
r.log.Warn("获取证书失败", slog.Any("err", err))
|
||||
r.log.Warn("[Cert Renew] failed to get certs", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -48,14 +48,13 @@ func (r *CertRenew) Run() {
|
||||
}
|
||||
|
||||
// 结束时间大于 7 天的证书不续签
|
||||
now := time.Now()
|
||||
if decode.NotAfter.Sub(now).Hours() > 24*7 {
|
||||
if time.Until(decode.NotAfter) > 24*7*time.Hour {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = r.certRepo.Renew(cert.ID)
|
||||
if err != nil {
|
||||
r.log.Warn("续签证书失败", slog.Any("err", err))
|
||||
r.log.Warn("[Cert Renew] failed to renew cert", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (r *Monitoring) Run() {
|
||||
}
|
||||
|
||||
if err = r.db.Create(&biz.Monitor{Info: info}).Error; err != nil {
|
||||
r.log.Warn("记录系统监控失败", slog.Any("err", err))
|
||||
r.log.Warn("[Monitor] failed to create monitor record", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func (r *Monitoring) Run() {
|
||||
return
|
||||
}
|
||||
if err = r.db.Where("created_at < ?", time.Now().AddDate(0, 0, -day).Format(time.DateTime)).Delete(&biz.Monitor{}).Error; err != nil {
|
||||
r.log.Warn("删除过期系统监控失败", slog.Any("err", err))
|
||||
r.log.Warn("[Monitor] failed to delete monitor record", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+64
-21
@@ -7,14 +7,18 @@ import (
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/go-rat/utils/collect"
|
||||
"github.com/hashicorp/go-version"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
"github.com/tnb-labs/panel/pkg/api"
|
||||
)
|
||||
|
||||
// PanelTask 面板每日任务
|
||||
type PanelTask struct {
|
||||
api *api.API
|
||||
db *gorm.DB
|
||||
log *slog.Logger
|
||||
backupRepo biz.BackupRepo
|
||||
@@ -24,6 +28,7 @@ type PanelTask struct {
|
||||
|
||||
func NewPanelTask(db *gorm.DB, log *slog.Logger, backup biz.BackupRepo, cache biz.CacheRepo, setting biz.SettingRepo) *PanelTask {
|
||||
return &PanelTask{
|
||||
api: api.NewAPI(app.Version),
|
||||
db: db,
|
||||
log: log,
|
||||
backupRepo: backup,
|
||||
@@ -38,11 +43,13 @@ func (r *PanelTask) Run() {
|
||||
// 优化数据库
|
||||
if err := r.db.Exec("VACUUM").Error; err != nil {
|
||||
app.Status = app.StatusFailed
|
||||
r.log.Warn("优化面板数据库失败", slog.Any("err", err))
|
||||
r.log.Warn("[Panel Task] failed to vacuum database", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
if err := r.db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error; err != nil {
|
||||
app.Status = app.StatusFailed
|
||||
r.log.Warn("优化面板数据库失败", slog.Any("err", err))
|
||||
r.log.Warn("[Panel Task] failed to wal checkpoint database", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 备份面板
|
||||
@@ -51,30 +58,20 @@ func (r *PanelTask) Run() {
|
||||
}
|
||||
|
||||
// 清理备份
|
||||
path, err := r.backupRepo.GetPath("panel")
|
||||
if err == nil {
|
||||
if path, err := r.backupRepo.GetPath("panel"); err == nil {
|
||||
if err = r.backupRepo.ClearExpired(path, "panel_", 10); err != nil {
|
||||
r.log.Warn("清理面板备份失败", slog.Any("err", err))
|
||||
r.log.Warn("[Panel Task] failed to clear backup", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
|
||||
// 更新商店缓存
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = r.cacheRepo.UpdateApps(); err != nil {
|
||||
r.log.Warn("更新商店缓存失败", slog.Any("err", err))
|
||||
}
|
||||
// 非离线模式下任务
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
r.updateApps()
|
||||
r.updateRewrites()
|
||||
if autoUpdate, err := r.settingRepo.GetBool(biz.SettingKeyAutoUpdate); err == nil && autoUpdate {
|
||||
r.updatePanel()
|
||||
}
|
||||
})
|
||||
|
||||
// 更新伪静态缓存
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = r.cacheRepo.UpdateRewrites(); err != nil {
|
||||
r.log.Warn("更新伪静态缓存失败", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 回收内存
|
||||
runtime.GC()
|
||||
@@ -82,3 +79,49 @@ func (r *PanelTask) Run() {
|
||||
|
||||
app.Status = app.StatusNormal
|
||||
}
|
||||
|
||||
// 更新商店缓存
|
||||
func (r *PanelTask) updateApps() {
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if err := r.cacheRepo.UpdateApps(); err != nil {
|
||||
r.log.Warn("[Panel Task] failed to update apps cache", slog.Any("err", err))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新伪静态缓存
|
||||
func (r *PanelTask) updateRewrites() {
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if err := r.cacheRepo.UpdateRewrites(); err != nil {
|
||||
r.log.Warn("[Panel Task] failed to update rewrites cache", slog.Any("err", err))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新面板
|
||||
func (r *PanelTask) updatePanel() {
|
||||
// 加 300 秒确保在缓存更新后才更新面板
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second+300*time.Second, func() {
|
||||
panel, err := r.api.LatestVersion()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
current, err := version.NewVersion(app.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
latest, err := version.NewVersion(panel.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if current.GreaterThanOrEqual(latest) {
|
||||
return
|
||||
}
|
||||
if download := collect.First(panel.Downloads); download != nil {
|
||||
if err = r.backupRepo.UpdatePanel(panel.Version, download.URL, download.Checksum); err != nil {
|
||||
r.log.Warn("[Panel Task] failed to update panel", slog.Any("err", err))
|
||||
_ = r.backupRepo.FixPanel()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/apps"
|
||||
"github.com/tnb-labs/panel/internal/embed"
|
||||
"github.com/tnb-labs/panel/internal/http/middleware"
|
||||
"github.com/tnb-labs/panel/internal/service"
|
||||
"github.com/tnb-labs/panel/pkg/apploader"
|
||||
)
|
||||
|
||||
type Http struct {
|
||||
@@ -40,7 +40,7 @@ type Http struct {
|
||||
monitor *service.MonitorService
|
||||
setting *service.SettingService
|
||||
systemctl *service.SystemctlService
|
||||
apps *apps.Loader
|
||||
apps *apploader.Loader
|
||||
}
|
||||
|
||||
func NewHttp(
|
||||
@@ -69,7 +69,7 @@ func NewHttp(
|
||||
monitor *service.MonitorService,
|
||||
setting *service.SettingService,
|
||||
systemctl *service.SystemctlService,
|
||||
apps *apps.Loader,
|
||||
apps *apploader.Loader,
|
||||
) *Http {
|
||||
return &Http{
|
||||
user: user,
|
||||
|
||||
@@ -99,9 +99,8 @@ func (s *CliService) Update(ctx context.Context, cmd *cli.Command) error {
|
||||
if download == nil {
|
||||
return fmt.Errorf("下载地址为空")
|
||||
}
|
||||
ver, url, checksum := panel.Version, download.URL, download.Checksum
|
||||
|
||||
return s.backupRepo.UpdatePanel(ver, url, checksum)
|
||||
return s.backupRepo.UpdatePanel(panel.Version, download.URL, download.Checksum)
|
||||
}
|
||||
|
||||
func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error {
|
||||
@@ -820,11 +819,13 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
|
||||
|
||||
settings := []biz.Setting{
|
||||
{Key: biz.SettingKeyName, Value: "耗子面板"},
|
||||
{Key: biz.SettingKeyMonitor, Value: "1"},
|
||||
{Key: biz.SettingKeyMonitor, Value: "true"},
|
||||
{Key: biz.SettingKeyMonitorDays, Value: "30"},
|
||||
{Key: biz.SettingKeyBackupPath, Value: filepath.Join(app.Root, "backup")},
|
||||
{Key: biz.SettingKeyWebsitePath, Value: filepath.Join(app.Root, "wwwroot")},
|
||||
{Key: biz.SettingKeyVersion, Value: app.Version},
|
||||
{Key: biz.SettingKeyOfflineMode, Value: "false"},
|
||||
{Key: biz.SettingKeyAutoUpdate, Value: "true"},
|
||||
}
|
||||
if err := s.db.Create(&settings).Error; err != nil {
|
||||
return fmt.Errorf("初始化失败:%v", err)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package apploader
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/tnb-labs/panel/pkg/types"
|
||||
)
|
||||
|
||||
var apps sync.Map
|
||||
|
||||
type Loader struct{}
|
||||
|
||||
func (r *Loader) Add(app ...types.App) {
|
||||
for item := range slices.Values(app) {
|
||||
slug := getSlug(item)
|
||||
apps.Store(slug, item)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Loader) Register(mux chi.Router) {
|
||||
/*for slug, item := range r.Apps {
|
||||
mux.Route("/"+slug, item.Route)
|
||||
}*/
|
||||
|
||||
apps.Range(func(key, value any) bool {
|
||||
app := value.(types.App)
|
||||
mux.Route("/"+key.(string), app.Route)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func Slugs() []string {
|
||||
var slugs []string
|
||||
apps.Range(func(key, value any) bool {
|
||||
slugs = append(slugs, key.(string))
|
||||
return true
|
||||
})
|
||||
return slugs
|
||||
}
|
||||
|
||||
func getSlug(app types.App) string {
|
||||
if app == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(app)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
pkgPath := t.PkgPath()
|
||||
if pkgPath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
parts := strings.Split(pkgPath, "/")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
+45
-13
@@ -4,6 +4,7 @@ import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@@ -95,10 +96,12 @@ func EncodeKey(key crypto.Signer) ([]byte, error) {
|
||||
|
||||
// GenerateSelfSigned 生成自签名证书
|
||||
func GenerateSelfSigned(names []string) (cert []byte, key []byte, err error) {
|
||||
rootPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
// 生成根密钥对
|
||||
rootPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var ips []net.IP
|
||||
ip := false
|
||||
for _, item := range names {
|
||||
@@ -113,43 +116,59 @@ func GenerateSelfSigned(names []string) (cert []byte, key []byte, err error) {
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "Rat Panel Root CA"},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(40, 0, 0),
|
||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
KeyUsage: x509.KeyUsageCertSign,
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
|
||||
}
|
||||
|
||||
rootCertBytes, _ := x509.CreateCertificate(rand.Reader, &rootTemplate, &rootTemplate, &rootPrivateKey.PublicKey, rootPrivateKey)
|
||||
rootCertBytes, err := x509.CreateCertificate(rand.Reader, &rootTemplate, &rootTemplate, &rootPrivateKey.PublicKey, rootPrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rootCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: rootCertBytes,
|
||||
}
|
||||
|
||||
interPrivateKey, _ := rsa.GenerateKey(rand.Reader, 4096)
|
||||
// 生成中间证书密钥对
|
||||
interPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
interTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(2),
|
||||
Subject: pkix.Name{CommonName: "Rat Panel CA"},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(30, 0, 0),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
KeyUsage: x509.KeyUsageCertSign,
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
interCertBytes, _ := x509.CreateCertificate(rand.Reader, &interTemplate, &rootTemplate, &interPrivateKey.PublicKey, rootPrivateKey)
|
||||
interCertBytes, err := x509.CreateCertificate(rand.Reader, &interTemplate, &rootTemplate, &interPrivateKey.PublicKey, rootPrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
interCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: interCertBytes,
|
||||
}
|
||||
|
||||
clientPrivateKey, _ := rsa.GenerateKey(rand.Reader, 4096)
|
||||
// 生成客户端证书密钥对
|
||||
clientPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
clientTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(3),
|
||||
Subject: pkix.Name{CommonName: "Rat Panel"},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
if ip {
|
||||
@@ -158,16 +177,29 @@ func GenerateSelfSigned(names []string) (cert []byte, key []byte, err error) {
|
||||
clientTemplate.DNSNames = names
|
||||
}
|
||||
|
||||
clientCertBytes, _ := x509.CreateCertificate(rand.Reader, &clientTemplate, &interTemplate, &clientPrivateKey.PublicKey, interPrivateKey)
|
||||
clientCertBytes, err := x509.CreateCertificate(rand.Reader, &clientTemplate, &interTemplate, &clientPrivateKey.PublicKey, interPrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
clientCertBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: clientCertBytes,
|
||||
}
|
||||
|
||||
// 拼接证书链
|
||||
cert = append(cert, pem.EncodeToMemory(clientCertBlock)...)
|
||||
cert = append(cert, pem.EncodeToMemory(interCertBlock)...)
|
||||
cert = append(cert, pem.EncodeToMemory(rootCertBlock)...)
|
||||
key = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientPrivateKey)})
|
||||
|
||||
// 编码私钥
|
||||
privateKeyBytes, err := x509.MarshalECPrivateKey(clientPrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
key = pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: privateKeyBytes,
|
||||
})
|
||||
|
||||
return cert, key, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package db
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
|
||||
@@ -20,8 +19,6 @@ type MySQL struct {
|
||||
}
|
||||
|
||||
func NewMySQL(username, password, address string, typ ...string) (*MySQL, error) {
|
||||
username = url.QueryEscape(username)
|
||||
password = url.QueryEscape(password)
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s)/", username, password, address)
|
||||
if len(typ) > 0 && typ[0] == "unix" {
|
||||
dsn = fmt.Sprintf("%s:%s@unix(%s)/", username, password, address)
|
||||
|
||||
+3
-4
@@ -2,10 +2,9 @@ package types
|
||||
|
||||
import "github.com/go-chi/chi/v5"
|
||||
|
||||
// App 应用元数据结构
|
||||
type App struct {
|
||||
Slug string `json:"slug"` // 应用标识
|
||||
Route func(r chi.Router) `json:"-"` // 路由
|
||||
// App 应用接口
|
||||
type App interface {
|
||||
Route(r chi.Router)
|
||||
}
|
||||
|
||||
// AppCenter 应用中心结构
|
||||
|
||||
@@ -17,6 +17,7 @@ const model = ref<Setting>({
|
||||
port: 8888,
|
||||
entrance: '',
|
||||
offline_mode: false,
|
||||
auto_update: false,
|
||||
website_path: '',
|
||||
backup_path: '',
|
||||
https: false,
|
||||
@@ -103,6 +104,9 @@ onMounted(() => {
|
||||
<n-form-item :label="$t('settingIndex.edit.fields.offline.label')">
|
||||
<n-switch v-model:value="model.offline_mode" />
|
||||
</n-form-item>
|
||||
<n-form-item label="自动更新">
|
||||
<n-switch v-model:value="model.auto_update" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('settingIndex.edit.fields.path.label')">
|
||||
<n-input
|
||||
v-model:value="model.website_path"
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface Setting {
|
||||
port: number
|
||||
entrance: string
|
||||
offline_mode: boolean
|
||||
auto_update: boolean
|
||||
website_path: string
|
||||
backup_path: string
|
||||
https: boolean
|
||||
|
||||
Reference in New Issue
Block a user