feat: add cmd task call

This commit is contained in:
duorameng
2026-05-13 17:17:50 +08:00
parent da2b003b83
commit f498c4fcd5
13 changed files with 619 additions and 58 deletions
+9 -2
View File
@@ -42,10 +42,17 @@ func InitBasic() *App {
return app
}
func (a *App) initConfig() {
a.initConfigWithPath(constant.ConfigPath)
// InitBasicForCmd 专为命令行工具定制的基础环境初始化入口
// 内部会调高控制台日志过滤级别以自动静默屏蔽刷屏的底层系统与组件启动 Info 日志
func InitBasicForCmd() *App {
logger.SetLevel("warn")
return InitBasic()
}
// func (a *App) initConfig() {
// a.initConfigWithPath(constant.ConfigPath)
// }
func (a *App) initConfigWithPath(path string) {
cfg, err := services.LoadConfig(path)
if err != nil {
+58
View File
@@ -0,0 +1,58 @@
package bootstrap
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/engigu/baihu-panel/internal/services"
)
// SendInternalRequest 向常驻后台主服务安全发送内部通信请求
// relPath 传入相对内部接口路径 (如: "/internal/tasks/execute/xxx"),方法内部会自动补充完整的协议、端口及 "/api/v1" 前缀,
// 并自动获取 security.secret 密钥种入 X-Internal-Token 头部。
func SendInternalRequest(method, relPath string, payload interface{}) ([]byte, int, error) {
appCfg := services.GetConfig()
if appCfg == nil {
return nil, 0, fmt.Errorf("加载系统配置失败")
}
relPath = strings.TrimPrefix(relPath, "/")
url := fmt.Sprintf("http://127.0.0.1:%d/api/v1/%s", appCfg.Server.Port, relPath)
var bodyReader io.Reader
if payload != nil {
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, 0, fmt.Errorf("序列化请求负载失败: %v", err)
}
bodyReader = bytes.NewBuffer(jsonData)
}
settings := services.NewSettingsService()
secret := settings.Get("security", "secret")
req, err := http.NewRequest(method, url, bodyReader)
if err != nil {
return nil, 0, fmt.Errorf("创建 HTTP 请求失败: %v", err)
}
if payload != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("X-Internal-Token", secret)
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, 0, fmt.Errorf("网络连接失败,请确保白虎面板常驻后台服务正在运行中: %v", err)
}
defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body)
return bodyBytes, resp.StatusCode, err
}
+4
View File
@@ -28,4 +28,8 @@ var Commands = []CommandInfo{
Name: "builtininstall",
Description: "为所有 mise 管理的 Node.js 和 Python 环境安装内建助手库",
},
{
Name: "task",
Description: "系统级任务的列表查询、触发运行、启停控制及状态查看",
},
}
+77
View File
@@ -619,3 +619,80 @@ func (tc *TaskController) SyncRepoTasks(c *gin.Context) {
tc.executorService.SyncRepoTasks(req.UpsertedIDs, req.DeletedIDs)
utils.SuccessMsg(c, "增量同步成功")
}
// ToggleTask 切换任务启用/禁用状态
func (tc *TaskController) ToggleTask(c *gin.Context) {
id := c.Param("id")
if id == "" {
utils.BadRequest(c, "无效的任务ID")
return
}
var req struct {
Enabled bool `json:"enabled"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.BadRequest(c, err.Error())
return
}
task := tc.taskService.GetTaskByID(id)
if task == nil {
utils.NotFound(c, "任务不存在")
return
}
// 获取旧 AgentID
var oldAgentID *string
oldAgentID = task.AgentID
// 构造更新参数,仅修改 Enabled
param := tasks.TaskParam{
Name: task.Name,
Remark: task.Remark,
Command: string(task.Command),
PreCommand: string(task.PreCommand),
PostCommand: string(task.PostCommand),
Tags: task.Tags,
Type: task.Type,
Config: string(task.Config),
Schedule: task.Schedule,
Timeout: task.Timeout,
WorkDir: task.WorkDir,
CleanConfig: task.CleanConfig,
Envs: string(task.Envs),
Languages: task.Languages,
AgentID: task.AgentID,
TriggerType: task.TriggerType,
RetryCount: task.RetryCount,
RetryInterval: task.RetryInterval,
RandomRange: task.RandomRange,
SourceID: task.SourceID,
PinType: task.PinType,
Enabled: req.Enabled,
}
updatedTask := tc.taskService.UpdateTask(id, &param)
if updatedTask == nil {
utils.NotFound(c, "任务不存在")
return
}
// 处理调度器更新
if updatedTask.AgentID != nil && *updatedTask.AgentID != "" {
tc.executorService.RemoveCronTask(updatedTask.ID)
tc.agentWSManager.BroadcastTasks(*updatedTask.AgentID)
} else {
if req.Enabled {
tc.executorService.AddCronTask(updatedTask)
} else {
tc.executorService.RemoveCronTask(updatedTask.ID)
}
if oldAgentID != nil && *oldAgentID != "" {
tc.agentWSManager.BroadcastTasks(*oldAgentID)
}
}
utils.Success(c, vo.ToTaskVO(updatedTask))
}
+2
View File
@@ -29,6 +29,8 @@ func initPublicAPIRoutes(api *gin.RouterGroup, c *Controllers) {
internalAPI.Use(middleware.LocalhostOnly())
{
internalAPI.POST("/tasks/sync-repo-status", c.Task.SyncRepoTasks)
internalAPI.POST("/tasks/execute/:id", c.Executor.ExecuteTask)
internalAPI.POST("/tasks/toggle/:id", c.Task.ToggleTask)
}
}