解析device和task的配置全部用内置方法处理
This commit is contained in:
@@ -77,7 +77,7 @@ func newDeviceResponse(device *models.Device) (*DeviceResponse, error) {
|
||||
|
||||
var props map[string]interface{}
|
||||
if len(device.Properties) > 0 && string(device.Properties) != "null" {
|
||||
if err := json.Unmarshal(device.Properties, &props); err != nil {
|
||||
if err := device.ParseProperties(&props); err != nil {
|
||||
return nil, fmt.Errorf("解析设备属性失败 (ID: %d): %w", device.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func TaskToResponse(task *models.Task) (TaskResponse, error) {
|
||||
|
||||
var params map[string]interface{}
|
||||
if len(task.Parameters) > 0 && string(task.Parameters) != "null" {
|
||||
if err := json.Unmarshal(task.Parameters, ¶ms); err != nil {
|
||||
if err := task.ParseParameters(¶ms); err != nil {
|
||||
return TaskResponse{}, fmt.Errorf("parsing task parameters failed (ID: %d): %w", task.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -46,7 +45,7 @@ func (d *DelayTask) parseParameters() error {
|
||||
}
|
||||
|
||||
var params DelayTaskParams
|
||||
err := json.Unmarshal(d.executionTask.Task.Parameters, ¶ms)
|
||||
err := d.executionTask.Task.ParseParameters(¶ms)
|
||||
if err != nil {
|
||||
d.logger.Errorf("任务 %v: 解析参数失败: %v", d.executionTask.TaskID, err)
|
||||
return fmt.Errorf("任务 %v: 解析参数失败: %v", d.executionTask.TaskID, err)
|
||||
|
||||
@@ -122,7 +122,7 @@ func (r *ReleaseFeedWeightTask) parseParameters() error {
|
||||
}
|
||||
|
||||
var params ReleaseFeedWeightTaskParams
|
||||
err := json.Unmarshal(r.claimedLog.Task.Parameters, ¶ms)
|
||||
err := r.claimedLog.Task.ParseParameters(¶ms)
|
||||
if err != nil {
|
||||
r.logger.Errorf("任务 %v: 解析参数失败: %v", r.claimedLog.TaskID, err)
|
||||
return fmt.Errorf("任务 %v: 解析参数失败: %v", r.claimedLog.TaskID, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -305,7 +304,7 @@ func (s *Scheduler) analysisPlan(claimedLog *models.TaskExecutionLog) error {
|
||||
var params struct {
|
||||
PlanID uint `json:"plan_id"`
|
||||
}
|
||||
if err := json.Unmarshal(claimedLog.Task.Parameters, ¶ms); err != nil {
|
||||
if err := claimedLog.Task.ParseParameters(¶ms); err != nil {
|
||||
s.logger.Errorf("解析任务参数中的计划ID失败,日志ID: %d, 错误: %v", claimedLog.ID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/utils"
|
||||
)
|
||||
|
||||
// DeviceType 定义了设备的高级类别
|
||||
@@ -139,20 +141,23 @@ func (d *Device) SelfCheck() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查通用属性是否存在
|
||||
has := func(key string) bool {
|
||||
_, ok := props[key]
|
||||
return ok
|
||||
// hasPureNumeric 检查一个key是否存在于map中,并且其值是纯数字(整数或可解析为整数的字符串)
|
||||
hasPureNumeric := func(key string) bool {
|
||||
val, ok := props[key]
|
||||
if !ok {
|
||||
return false // Key不存在
|
||||
}
|
||||
return utils.IsPureNumeric(val)
|
||||
}
|
||||
|
||||
// 根据子类型进行具体校验
|
||||
switch d.SubType {
|
||||
// 所有传感器类型都必须有 Command 和总线信息
|
||||
// 所有传感器类型都必须有 Command 和总线信息,且总线信息为纯数字
|
||||
case SubTypeSensorTemp, SubTypeSensorHumidity, SubTypeSensorWeight, SubTypeSensorAmmonia:
|
||||
return d.Command != "" && has(BusNumber) && has(BusAddress)
|
||||
// 所有开关类型都必须有继电器和总线信息
|
||||
return d.Command != "" && hasPureNumeric(BusNumber) && hasPureNumeric(BusAddress)
|
||||
// 所有开关类型都必须有继电器和总线信息,且都为纯数字
|
||||
case SubTypeFan, SubTypeWaterCurtain, SubTypeValveFeed:
|
||||
return has(BusNumber) && has(BusAddress) && has(RelayChannel)
|
||||
return hasPureNumeric(BusNumber) && hasPureNumeric(BusAddress) && hasPureNumeric(RelayChannel)
|
||||
// 如果是未知的子类型,或者没有子类型,则认为自检失败
|
||||
default:
|
||||
return false
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -172,3 +174,16 @@ type Task struct {
|
||||
func (Task) TableName() string {
|
||||
return "tasks"
|
||||
}
|
||||
|
||||
// ParseParameters 解析 JSON 属性到一个具体的结构体中。
|
||||
// 调用方需要传入一个指向目标结构体实例的指针。
|
||||
// 示例:
|
||||
//
|
||||
// var param LoraParameters
|
||||
// if err := task.ParseParameters(¶m); err != nil { ... }
|
||||
func (t Task) ParseParameters(v interface{}) error {
|
||||
if t.Parameters == nil {
|
||||
return errors.New("设备属性为空,无法解析")
|
||||
}
|
||||
return json.Unmarshal(t.Parameters, v)
|
||||
}
|
||||
|
||||
13
internal/infra/utils/validation.go
Normal file
13
internal/infra/utils/validation.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// IsPureNumeric 检查值是否纯数字(整数或可转换为整数的字符串)。
|
||||
func IsPureNumeric(val interface{}) bool {
|
||||
v := fmt.Sprintf("%v", val)
|
||||
_, err := strconv.Atoi(v)
|
||||
return err == nil
|
||||
}
|
||||
Reference in New Issue
Block a user