mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 07:57:21 +08:00
feat: 添加面板每日任务
This commit is contained in:
@@ -10,9 +10,11 @@ import (
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
|
||||
"panel/app/models"
|
||||
"panel/internal"
|
||||
"panel/internal/services"
|
||||
)
|
||||
|
||||
// CertRenew 证书续签
|
||||
type CertRenew struct {
|
||||
}
|
||||
|
||||
@@ -35,6 +37,10 @@ func (receiver *CertRenew) Extend() command.Extend {
|
||||
|
||||
// Handle Execute the console command.
|
||||
func (receiver *CertRenew) Handle(ctx console.Context) error {
|
||||
if internal.Status != internal.StatusNormal {
|
||||
return nil
|
||||
}
|
||||
|
||||
var certs []models.Cert
|
||||
err := facades.Orm().Query().With("Website").With("User").With("DNS").Find(&certs)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,10 +11,12 @@ import (
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"panel/app/models"
|
||||
"panel/internal"
|
||||
"panel/internal/services"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
// Monitoring 系统监控
|
||||
type Monitoring struct {
|
||||
}
|
||||
|
||||
@@ -37,6 +39,10 @@ func (receiver *Monitoring) Extend() command.Extend {
|
||||
|
||||
// Handle Execute the console command.
|
||||
func (receiver *Monitoring) Handle(ctx console.Context) error {
|
||||
if internal.Status != internal.StatusNormal {
|
||||
return nil
|
||||
}
|
||||
|
||||
var setting models.Setting
|
||||
monitor := services.NewSettingImpl().Get(models.SettingKeyMonitor)
|
||||
if !cast.ToBool(monitor) {
|
||||
|
||||
@@ -13,12 +13,14 @@ import (
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
"github.com/spf13/cast"
|
||||
"panel/internal"
|
||||
|
||||
"panel/app/models"
|
||||
"panel/internal/services"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
// Panel 面板命令行
|
||||
type Panel struct {
|
||||
}
|
||||
|
||||
@@ -92,12 +94,14 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tools.UpdatePanel(panel)
|
||||
if err != nil {
|
||||
internal.Status = internal.StatusUpgrade
|
||||
if err = tools.UpdatePanel(panel); err != nil {
|
||||
internal.Status = internal.StatusFailed
|
||||
color.Redln("更新失败: " + err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
internal.Status = internal.StatusNormal
|
||||
color.Greenln("更新成功")
|
||||
tools.RestartPanel()
|
||||
|
||||
|
||||
67
app/console/commands/panel_task.go
Normal file
67
app/console/commands/panel_task.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/console"
|
||||
"github.com/goravel/framework/contracts/console/command"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
|
||||
"panel/internal"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
// PanelTask 面板每日任务
|
||||
type PanelTask struct {
|
||||
}
|
||||
|
||||
// Signature The name and signature of the console command.
|
||||
func (receiver *PanelTask) Signature() string {
|
||||
return "panel:task"
|
||||
}
|
||||
|
||||
// Description The console command description.
|
||||
func (receiver *PanelTask) Description() string {
|
||||
return "[面板] 每日任务"
|
||||
}
|
||||
|
||||
// Extend The console command extend.
|
||||
func (receiver *PanelTask) Extend() command.Extend {
|
||||
return command.Extend{
|
||||
Category: "panel",
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Execute the console command.
|
||||
func (receiver *PanelTask) Handle(ctx console.Context) error {
|
||||
internal.Status = internal.StatusMaintain
|
||||
|
||||
// 优化数据库
|
||||
if _, err := facades.Orm().Query().Exec("VACUUM"); err != nil {
|
||||
facades.Log().Tags("面板", "每日任务").
|
||||
With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Error("优化面板数据库失败")
|
||||
return err
|
||||
}
|
||||
|
||||
// 备份面板
|
||||
if err := tools.Archive([]string{"/www/panel"}, "/www/backup/panel/panel-"+carbon.Now().ToShortDateTimeString()+".zip"); err != nil {
|
||||
facades.Log().Tags("面板", "每日任务").
|
||||
With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Error("备份面板失败")
|
||||
return err
|
||||
}
|
||||
|
||||
// 清理 7 天前的备份
|
||||
if _, err := tools.Exec(`find /www/backup/panel -mtime +7 -name "*.zip" -exec rm -rf {} \;`); err != nil {
|
||||
facades.Log().Tags("面板", "每日任务").
|
||||
With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Error("清理面板备份失败")
|
||||
return err
|
||||
}
|
||||
|
||||
internal.Status = internal.StatusNormal
|
||||
return nil
|
||||
}
|
||||
@@ -14,7 +14,8 @@ type Kernel struct {
|
||||
func (kernel *Kernel) Schedule() []schedule.Event {
|
||||
return []schedule.Event{
|
||||
facades.Schedule().Command("panel:monitoring").EveryMinute().SkipIfStillRunning(),
|
||||
facades.Schedule().Command("panel:cert-renew").Daily().SkipIfStillRunning(),
|
||||
facades.Schedule().Command("panel:cert-renew").DailyAt("04:00").SkipIfStillRunning(),
|
||||
facades.Schedule().Command("panel:task").Daily().SkipIfStillRunning(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +24,6 @@ func (kernel *Kernel) Commands() []console.Command {
|
||||
&commands.Panel{},
|
||||
&commands.Monitoring{},
|
||||
&commands.CertRenew{},
|
||||
&commands.PanelTask{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,14 +309,16 @@ func (r *InfoController) Update(ctx http.Context) http.Response {
|
||||
return Error(ctx, http.StatusInternalServerError, "获取最新版本失败")
|
||||
}
|
||||
|
||||
err = tools.UpdatePanel(panel)
|
||||
if err != nil {
|
||||
internal.Status = internal.StatusUpgrade
|
||||
if err = tools.UpdatePanel(panel); err != nil {
|
||||
internal.Status = internal.StatusFailed
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{
|
||||
"error": err.Error(),
|
||||
}).Info("更新面板失败")
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
internal.Status = internal.StatusNormal
|
||||
tools.RestartPanel()
|
||||
return Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package http
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
|
||||
"panel/app/http/middleware"
|
||||
)
|
||||
|
||||
type Kernel struct {
|
||||
@@ -10,5 +12,7 @@ type Kernel struct {
|
||||
// The application's global HTTP middleware stack.
|
||||
// These middleware are run during every request to your application.
|
||||
func (kernel Kernel) Middleware() []http.Middleware {
|
||||
return []http.Middleware{}
|
||||
return []http.Middleware{
|
||||
middleware.Status(),
|
||||
}
|
||||
}
|
||||
|
||||
42
app/http/middleware/status.go
Normal file
42
app/http/middleware/status.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
|
||||
"panel/internal"
|
||||
)
|
||||
|
||||
// Status 检查程序状态
|
||||
func Status() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
switch internal.Status {
|
||||
case internal.StatusUpgrade:
|
||||
ctx.Request().AbortWithStatusJson(http.StatusOK, http.Json{
|
||||
"code": 503,
|
||||
"message": "面板升级中,请稍后",
|
||||
})
|
||||
return
|
||||
case internal.StatusMaintain:
|
||||
ctx.Request().AbortWithStatusJson(http.StatusOK, http.Json{
|
||||
"code": 503,
|
||||
"message": "面板正在运行维护,请稍后",
|
||||
})
|
||||
return
|
||||
case internal.StatusClosed:
|
||||
ctx.Request().AbortWithStatusJson(http.StatusOK, http.Json{
|
||||
"code": 403,
|
||||
"message": "面板已关闭",
|
||||
})
|
||||
return
|
||||
case internal.StatusFailed:
|
||||
ctx.Request().AbortWithStatusJson(http.StatusOK, http.Json{
|
||||
"code": 500,
|
||||
"message": "面板运行出错,请检查排除或联系支持",
|
||||
})
|
||||
return
|
||||
default:
|
||||
ctx.Request().Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
12
internal/status.go
Normal file
12
internal/status.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package internal
|
||||
|
||||
// 定义面板状态常量
|
||||
const (
|
||||
StatusNormal = iota
|
||||
StatusMaintain
|
||||
StatusClosed
|
||||
StatusUpgrade
|
||||
StatusFailed
|
||||
)
|
||||
|
||||
var Status = StatusNormal
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
"github.com/goravel/framework/support/env"
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
@@ -403,11 +404,16 @@ func UpdatePanel(panelInfo PanelInfo) error {
|
||||
|
||||
color.Greenln("前置检查...")
|
||||
if Exists("/tmp/panel-storage.zip") || Exists("/tmp/panel.conf.bak") {
|
||||
color.Redln("检测到/tmp存在临时文件,可能是上次更新失败导致的,请谨慎排除后重试")
|
||||
return errors.New("检测到/tmp存在临时文件,可能是上次更新失败导致的,请谨慎排除后重试")
|
||||
color.Redln("检测到 /tmp 存在临时文件,可能是上次更新失败导致的,请谨慎排除后重试")
|
||||
return errors.New("检测到 /tmp 存在临时文件,可能是上次更新失败导致的,请谨慎排除后重试")
|
||||
}
|
||||
|
||||
color.Greenln("备份面板数据...")
|
||||
// 备份面板
|
||||
if err := Archive([]string{"/www/panel"}, "/www/backup/panel/panel-"+carbon.Now().ToShortDateTimeString()+".zip"); err != nil {
|
||||
color.Redln("备份面板失败")
|
||||
return err
|
||||
}
|
||||
if _, err := Exec("cd /www/panel/storage && zip -r /tmp/panel-storage.zip *"); err != nil {
|
||||
color.Redln("备份面板数据失败")
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user