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