mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 06:47:20 +08:00
feat(#419): 面板自动更新
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
@@ -51,30 +56,19 @@ 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("[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("[Panel Task] failed to update apps cache", 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("[Panel Task] failed to update rewrites cache", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 回收内存
|
||||
runtime.GC()
|
||||
@@ -82,3 +76,48 @@ 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
|
||||
}
|
||||
old, err := version.NewVersion(app.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
current, err := version.NewVersion(panel.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !current.GreaterThan(old) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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: "false"},
|
||||
}
|
||||
if err := s.db.Create(&settings).Error; err != nil {
|
||||
return fmt.Errorf("初始化失败:%v", err)
|
||||
|
||||
@@ -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