From 1ff391f055eebba57c069b10bb46dfc593b2b3e8 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 6 May 2026 12:34:50 +0800 Subject: [PATCH] feat: add resource_sync_all and resource_sync_one task types --- internal/service/task.go | 80 ++++++++++++++++++++++++++++++++++++++++ internal/web/ui.go | 8 ++++ 2 files changed, 88 insertions(+) diff --git a/internal/service/task.go b/internal/service/task.go index bd0d053..925c7c7 100644 --- a/internal/service/task.go +++ b/internal/service/task.go @@ -36,6 +36,7 @@ type TaskService struct { repo TaskRepository models *storage.ModelsRepo modelsDir string + resources *storage.ResourcesRepo stateRepo DeviceConfigStateRepository auditRepo AuditLogRepository tasks map[string]*models.Task @@ -66,6 +67,13 @@ func (s *TaskService) SetStandardModels(models *storage.ModelsRepo, dir string) s.modelsDir = filepath.Clean(dir) } +func (s *TaskService) SetStandardResources(repo *storage.ResourcesRepo) { + if s == nil { + return + } + s.resources = repo +} + func NewTaskService(cfg *config.Config, agent *AgentClient, registry *RegistryService, repo ...TaskRepository) *TaskService { var taskRepo TaskRepository if len(repo) > 0 { @@ -399,6 +407,22 @@ func (s *TaskService) executeOnDevice(task *models.Task, did string) { s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "") s.appendAuditLog(task, did, models.TaskSuccess, "") + case "resource_sync_one": + if err := s.syncResourceToDevice(task, dev, did, false); err != nil { + s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, err.Error()) + return + } + s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "") + s.appendAuditLog(task, did, models.TaskSuccess, "") + + case "resource_sync_all": + if err := s.syncResourceToDevice(task, dev, did, true); err != nil { + s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, err.Error()) + return + } + s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "") + s.appendAuditLog(task, did, models.TaskSuccess, "") + default: s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, "unsupported task type") } @@ -460,6 +484,62 @@ func (s *TaskService) syncModelToDevice(task *models.Task, dev *models.Device, d return nil } +func (s *TaskService) syncResourceToDevice(task *models.Task, dev *models.Device, did string, syncAll bool) error { + if s.resources == nil { + return fmt.Errorf("resources repo is not configured") + } + items, err := s.resources.List() + if err != nil { + return err + } + if len(items) == 0 { + return fmt.Errorf("no standard resources configured") + } + targets := items[:0] + if syncAll { + targets = append(targets, items...) + } else { + payload, _ := task.Payload.(map[string]any) + targetName := strings.TrimSpace(stringAny(payload["resource_name"])) + if targetName == "" { + return fmt.Errorf("resource_name is required") + } + for _, item := range items { + if strings.TrimSpace(item.Name) == targetName { + targets = append(targets, item) + break + } + } + if len(targets) == 0 { + return fmt.Errorf("standard resource %q not found", targetName) + } + } + for _, item := range targets { + if strings.TrimSpace(item.FilePath) == "" { + continue // metadata-only resource, nothing to push + } + file, err := os.Open(item.FilePath) + if err != nil { + return err + } + stat, err := file.Stat() + if err != nil { + file.Close() + return err + } + agentPath := fmt.Sprintf("/v1/resources/%s/%s", item.ResourceType, item.Name) + resp, code, err := s.agent.DoStream("PUT", dev.IP, dev.AgentPort, agentPath, file, "application/octet-stream", stat.Size()) + file.Close() + if err != nil { + return err + } + if code >= 400 { + return fmt.Errorf("agent error: %d %s", code, strings.TrimSpace(string(resp))) + } + } + return nil +} + func (s *TaskService) updateDeviceStatus(taskID, did string, status models.TaskStatus, progress float64, errStr string) { s.mu.RLock() task, ok := s.tasks[taskID] diff --git a/internal/web/ui.go b/internal/web/ui.go index cc37bf0..34695c8 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -252,6 +252,8 @@ func NewUI(discovery *service.DiscoveryService, registry *service.RegistryServic return "批量服务" case "reload", "rollback": return "设备操作" + case "resource_sync_one", "resource_sync_all": + return "资源同步" default: return "其他任务" } @@ -264,6 +266,10 @@ func NewUI(discovery *service.DiscoveryService, registry *service.RegistryServic return "更新单个模型" case "model_sync_all": return "更新全部模型" + case "resource_sync_one": + return "同步单个资源" + case "resource_sync_all": + return "同步全部资源" case "reload": return "重载识别服务" case "rollback": @@ -284,6 +290,8 @@ func NewUI(discovery *service.DiscoveryService, registry *service.RegistryServic return "pill run" case "model_sync_one", "model_sync_all": return "pill warn" + case "resource_sync_one", "resource_sync_all": + return "pill warn" case "media_start", "media_restart", "media_stop": return "pill ok" case "reload", "rollback":