调整告警图片展示
This commit is contained in:
parent
83a50fa245
commit
011694d7a7
2
.gitignore
vendored
2
.gitignore
vendored
@ -42,7 +42,7 @@ tables/
|
|||||||
*.pprof
|
*.pprof
|
||||||
*.test
|
*.test
|
||||||
snap/*
|
snap/*
|
||||||
|
*buf264/*
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
# 连续分析帧数(2-64), 默认为10, 最大为 64
|
# 连续分析帧数(2-64), 默认为10, 最大为 64
|
||||||
FrmNum = 10
|
FrmNum = 10
|
||||||
# 是否使用深度学习版本, 默认使用深度学习版本
|
# 是否使用深度学习版本, 默认使用深度学习版本
|
||||||
IsDeepLearn = false
|
IsDeepLearn = true
|
||||||
|
|
||||||
[VqdLgtDark]
|
[VqdLgtDark]
|
||||||
# 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
# 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
||||||
|
|||||||
@ -111,69 +111,69 @@ type VqdConfig struct {
|
|||||||
|
|
||||||
// 亮度检测
|
// 亮度检测
|
||||||
type VqdLgtDark struct {
|
type VqdLgtDark struct {
|
||||||
DarkThr float64 `json:"dark_thr" comment:"默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6"`
|
DarkThr float32 `json:"dark_thr" comment:"默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6"`
|
||||||
LgtThr float64 `json:"lgt_thr" comment:"默认 0.1, 取值范围: 0~1, 建议范围: 0.1~0.5"`
|
LgtThr float32 `json:"lgt_thr" comment:"默认 0.1, 取值范围: 0~1, 建议范围: 0.1~0.5"`
|
||||||
LgtDarkAbnNumRatio float64 `json:"lgt_dark_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
LgtDarkAbnNumRatio float32 `json:"lgt_dark_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 蓝屏检查
|
// 蓝屏检查
|
||||||
type VqdBlue struct {
|
type VqdBlue struct {
|
||||||
BlueThr float64 `json:"blue_thr" comment:"默认为 0.6, 取值范围: 0~1, 建议范围 0.4~0.9"`
|
BlueThr float32 `json:"blue_thr" comment:"默认为 0.6, 取值范围: 0~1, 建议范围 0.4~0.9"`
|
||||||
BlueAbnNumRatio float64 `json:"blue_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
BlueAbnNumRatio float32 `json:"blue_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清晰度检查
|
// 清晰度检查
|
||||||
type VqdClarity struct {
|
type VqdClarity struct {
|
||||||
ClarityThr float64 `json:"clarity_thr" comment:"默认为0.4, 取值范围: 0~1, 建议范围: 0.3~0.99"`
|
ClarityThr float32 `json:"clarity_thr" comment:"默认为0.4, 取值范围: 0~1, 建议范围: 0.3~0.99"`
|
||||||
ClarityAbnNumRatio float64 `json:"clarity_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
ClarityAbnNumRatio float32 `json:"clarity_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 抖动检查
|
// 抖动检查
|
||||||
type VqdShark struct {
|
type VqdShark struct {
|
||||||
SharkThr float64 `json:"shark_thr" comment:"默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.8"`
|
SharkThr float32 `json:"shark_thr" comment:"默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.8"`
|
||||||
SharkAbnNumRatio float64 `json:"shark_abn_num_ratio" comment:"默认为0.2, 取值范围: 0~1, 建议范围: 0.1~0.6"`
|
SharkAbnNumRatio float32 `json:"shark_abn_num_ratio" comment:"默认为0.2, 取值范围: 0~1, 建议范围: 0.1~0.6"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 冻结检测
|
// 冻结检测
|
||||||
type VqdFreeze struct {
|
type VqdFreeze struct {
|
||||||
FreezeThr float64 `json:"freeze_thr" comment:"默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6"`
|
FreezeThr float32 `json:"freeze_thr" comment:"默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6"`
|
||||||
FreezeAbnNumRatio float64 `json:"freeze_abn_num_ratio" comment:"默认为0.99, 取值范围: 0.8~1, 建议范围: 0.95~1"`
|
FreezeAbnNumRatio float32 `json:"freeze_abn_num_ratio" comment:"默认为0.99, 取值范围: 0.8~1, 建议范围: 0.95~1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 偏色检测
|
// 偏色检测
|
||||||
type VqdColor struct {
|
type VqdColor struct {
|
||||||
ColorThr float64 `json:"color_thr" comment:"默认为0.18, 取值范围: 0~1, 建议范围: 0.1~0.5"`
|
ColorThr float32 `json:"color_thr" comment:"默认为0.18, 取值范围: 0~1, 建议范围: 0.1~0.5"`
|
||||||
ColorAbnNumRatio float64 `json:"color_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
ColorAbnNumRatio float32 `json:"color_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遮挡检测
|
// 遮挡检测
|
||||||
type VqdOcclusion struct {
|
type VqdOcclusion struct {
|
||||||
OcclusionThr float64 `json:"occlusion_thr" comment:"默认为0.1, 取值范围: 0~1, 建议范围: 0.05~0.5"`
|
OcclusionThr float32 `json:"occlusion_thr" comment:"默认为0.1, 取值范围: 0~1, 建议范围: 0.05~0.5"`
|
||||||
OcclusionAbnNumRatio float64 `json:"occlusion_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
OcclusionAbnNumRatio float32 `json:"occlusion_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 噪声检测
|
// 噪声检测
|
||||||
type VqdNoise struct {
|
type VqdNoise struct {
|
||||||
NoiseThr float64 `json:"noise_thr" comment:"默认为 0.3, 取值范围: 0~1, 建议范围: 0.2~0.8"`
|
NoiseThr float32 `json:"noise_thr" comment:"默认为 0.3, 取值范围: 0~1, 建议范围: 0.2~0.8"`
|
||||||
NoiseAbnNumRatio float64 `json:"noise_abn_num_ratio" comment:"默认为0.6, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
NoiseAbnNumRatio float32 `json:"noise_abn_num_ratio" comment:"默认为0.6, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对比度检测
|
// 对比度检测
|
||||||
type VqdContrast struct {
|
type VqdContrast struct {
|
||||||
CtraLowThr float64 `json:"ctra_low_thr" comment:"默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.3"`
|
CtraLowThr float32 `json:"ctra_low_thr" comment:"默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.3"`
|
||||||
CtraHighThr float64 `json:"ctra_high_thr" comment:"默认为 0.8, 取值范围: 0~1, 建议范围: 0.7~0.9"`
|
CtraHighThr float32 `json:"ctra_high_thr" comment:"默认为 0.8, 取值范围: 0~1, 建议范围: 0.7~0.9"`
|
||||||
CtraAbnNumRatio float64 `json:"ctra_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
CtraAbnNumRatio float32 `json:"ctra_abn_num_ratio" comment:"默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 马赛克检测
|
// 马赛克检测
|
||||||
type VqdMosaic struct {
|
type VqdMosaic struct {
|
||||||
MosaicThr float64 `json:"mosaic_thr" comment:"默认为 0.1 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
MosaicThr float32 `json:"mosaic_thr" comment:"默认为 0.1 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
MosaicAbnNumRatio float64 `json:"mosaic_abn_num_ratio" comment:"默认为0.5,取值范围: 0~1, 建议范围: 0.3"`
|
MosaicAbnNumRatio float32 `json:"mosaic_abn_num_ratio" comment:"默认为0.5,取值范围: 0~1, 建议范围: 0.3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 花屏检测
|
// 花屏检测
|
||||||
type VqdFlower struct {
|
type VqdFlower struct {
|
||||||
FlowerThr float64 `json:"flower_thr" comment:"默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
FlowerThr float32 `json:"flower_thr" comment:"默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
FlowerAbnNumRatio float64 `json:"flower_abn_num_ratio" comment:"默认为0.6, 取值范围: 0~1, 建议范围: 0.3"`
|
FlowerAbnNumRatio float32 `json:"flower_abn_num_ratio" comment:"默认为0.6, 取值范围: 0~1, 建议范围: 0.3"`
|
||||||
MosaicThr float64 `json:"mosaic_thr" comment:"默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
MosaicThr float32 `json:"mosaic_thr" comment:"默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,8 +52,8 @@ func NewCore(cfg *conf.Bootstrap) *Core {
|
|||||||
}
|
}
|
||||||
sdk.AddResponseHandler("stop", core.stop)
|
sdk.AddResponseHandler("stop", core.stop)
|
||||||
sdk.AddResponseHandler("ping", core.ping)
|
sdk.AddResponseHandler("ping", core.ping)
|
||||||
|
|
||||||
// 这部分都是收到响应后的回调
|
// 这部分都是收到响应后的回调
|
||||||
|
sdk.AddResponseHandler("play", core.playRespH)
|
||||||
sdk.AddResponseHandler("findDevices", core.findDevicesRespH)
|
sdk.AddResponseHandler("findDevices", core.findDevicesRespH)
|
||||||
sdk.AddResponseHandler("findChannels", core.findChannelsRespH)
|
sdk.AddResponseHandler("findChannels", core.findChannelsRespH)
|
||||||
sdk.AddResponseHandler("getBaseConfig", core.getBaseConfigRespH)
|
sdk.AddResponseHandler("getBaseConfig", core.getBaseConfigRespH)
|
||||||
@ -102,6 +102,11 @@ func (c Core) findTalkUrlRespH(requestID string, args json.RawMessage) (interfac
|
|||||||
slog.Debug("Received 'findTalkUrl' from host", "request_id", requestID, "args", args)
|
slog.Debug("Received 'findTalkUrl' from host", "request_id", requestID, "args", args)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
func (c Core) playRespH(requestID string, args json.RawMessage) (interface{}, error) {
|
||||||
|
slog.Debug("Received 'play' from host", "request_id", requestID, "args", args)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c Core) iframeDataRespH(requestID string, args json.RawMessage) (interface{}, error) {
|
func (c Core) iframeDataRespH(requestID string, args json.RawMessage) (interface{}, error) {
|
||||||
slog.Debug("Received 'iframeData' from host", "request_id", requestID, "args", args)
|
slog.Debug("Received 'iframeData' from host", "request_id", requestID, "args", args)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|||||||
24
internal/core/host/play.go
Normal file
24
internal/core/host/play.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package host
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c Core) Play(ctx context.Context, in *PlayInput) (*PlayOutput, error) {
|
||||||
|
marshal, err := json.Marshal(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, err := c.Plugin.CallHost("play", marshal)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := PlayOutput{}
|
||||||
|
if err = json.Unmarshal(result, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
40
internal/core/host/play.param.go
Normal file
40
internal/core/host/play.param.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package host
|
||||||
|
|
||||||
|
type PlayInput struct {
|
||||||
|
ChannelID string `json:"channel_id"`
|
||||||
|
Stream string `json:"stream"` // 主子码流 MAIN/SUB
|
||||||
|
Protocol string `json:"protocol"` // hls/webrtc/flv 等播放协议
|
||||||
|
Network string `json:"network"` // LAN:内网;WAN:公网(rtsp/rtmp 返回的地址)
|
||||||
|
ActiveSecond int `json:"active_second"` // 流活跃时间
|
||||||
|
TimeS int `form:"time_s" json:"time_s"` // 秒
|
||||||
|
|
||||||
|
IsRecord bool `json:"-"` // 是否由录像拉起
|
||||||
|
Reason string `json:"-"` // 调用原因
|
||||||
|
Domain string `json:"-"` // 域名
|
||||||
|
RequestHost string `json:"-"` // 请求 url 上的 host,用于自适应返回播放地址
|
||||||
|
Host string `json:"-"`
|
||||||
|
|
||||||
|
// 在未来的版本中,将废弃
|
||||||
|
IsHTTPS bool `json:"-"` // 是否是 https 请求
|
||||||
|
Auth bool `json:"-"` // 是否是 auth 请求
|
||||||
|
}
|
||||||
|
type PlayOutput struct {
|
||||||
|
ChannelID string `json:"channel_id"`
|
||||||
|
StreamID string `json:"stream_id"`
|
||||||
|
Address map[string]string `json:"address"`
|
||||||
|
Routes []Route `json:"routes"` // 多线路
|
||||||
|
Img []byte `json:"img"`
|
||||||
|
ImgType string `json:"img_type"`
|
||||||
|
ImgCreateAt int64 `json:"img_created_at"`
|
||||||
|
}
|
||||||
|
type Route struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
|
||||||
|
HTTPFLV string `json:"http_flv"`
|
||||||
|
WSFLV string `json:"ws_flv"`
|
||||||
|
HLS string `json:"hls"`
|
||||||
|
RTMP string `json:"rtmp"`
|
||||||
|
RTSP string `json:"rtsp"`
|
||||||
|
WebRTC string `json:"webrtc"`
|
||||||
|
}
|
||||||
@ -60,9 +60,9 @@ func (i *VqdConfig) Scan(input interface{}) error {
|
|||||||
// 亮度检测
|
// 亮度检测
|
||||||
type VqdLgtDark struct {
|
type VqdLgtDark struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
DarkThr float64 `gorm:"column:dark_thr;notNull;default:0;comment:过暗阈值" json:"dark_thr"` // 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
DarkThr float32 `gorm:"column:dark_thr;notNull;default:0;comment:过暗阈值" json:"dark_thr"` // 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
||||||
LgtThr float64 `gorm:"column:lgt_thr;notNull;default:0;comment:过亮阈值" json:"lgt_thr"` // 默认 0.1, 取值范围: 0~1, 建议范围: 0.1~0.5
|
LgtThr float32 `gorm:"column:lgt_thr;notNull;default:0;comment:过亮阈值" json:"lgt_thr"` // 默认 0.1, 取值范围: 0~1, 建议范围: 0.1~0.5
|
||||||
LgtDarkAbnNumRatio float64 `gorm:"column:lgt_dark_abn_num_ratio;notNull;default:0;comment:偏暗或者偏亮次数比例" json:"lgt_dark_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
LgtDarkAbnNumRatio float32 `gorm:"column:lgt_dark_abn_num_ratio;notNull;default:0;comment:偏暗或者偏亮次数比例" json:"lgt_dark_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdLgtDark) Value() (driver.Value, error) {
|
func (a VqdLgtDark) Value() (driver.Value, error) {
|
||||||
@ -75,8 +75,8 @@ func (i *VqdLgtDark) Scan(input interface{}) error {
|
|||||||
// 蓝屏检查
|
// 蓝屏检查
|
||||||
type VqdBlue struct {
|
type VqdBlue struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
BlueThr float64 `gorm:"column:blue_thr;notNull;default:0;comment:蓝屏判断阈值" json:"blue_thr"` // 默认为 0.6, 取值范围: 0~1, 建议范围 0.4~0.9
|
BlueThr float32 `gorm:"column:blue_thr;notNull;default:0;comment:蓝屏判断阈值" json:"blue_thr"` // 默认为 0.6, 取值范围: 0~1, 建议范围 0.4~0.9
|
||||||
BlueAbnNumRatio float64 `gorm:"column:blue_abn_num_ratio;notNull;default:0;comment:蓝屏次数比例" json:"blue_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
BlueAbnNumRatio float32 `gorm:"column:blue_abn_num_ratio;notNull;default:0;comment:蓝屏次数比例" json:"blue_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdBlue) Value() (driver.Value, error) {
|
func (a VqdBlue) Value() (driver.Value, error) {
|
||||||
@ -89,8 +89,8 @@ func (i *VqdBlue) Scan(input interface{}) error {
|
|||||||
// 清晰度检查
|
// 清晰度检查
|
||||||
type VqdClarity struct {
|
type VqdClarity struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
ClarityThr float64 `gorm:"column:clarity_thr;notNull;default:0;comment:清晰度判断阈值" json:"clarity_thr"` // 默认为0.4, 取值范围: 0~1, 建议范围: 0.3~0.99
|
ClarityThr float32 `gorm:"column:clarity_thr;notNull;default:0;comment:清晰度判断阈值" json:"clarity_thr"` // 默认为0.4, 取值范围: 0~1, 建议范围: 0.3~0.99
|
||||||
ClarityAbnNumRatio float64 `gorm:"column:clarity_abn_num_ratio;notNull;default:0;comment:清晰度异常次数比例" json:"clarity_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
ClarityAbnNumRatio float32 `gorm:"column:clarity_abn_num_ratio;notNull;default:0;comment:清晰度异常次数比例" json:"clarity_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdClarity) Value() (driver.Value, error) {
|
func (a VqdClarity) Value() (driver.Value, error) {
|
||||||
@ -103,8 +103,8 @@ func (i *VqdClarity) Scan(input interface{}) error {
|
|||||||
// 抖动检查
|
// 抖动检查
|
||||||
type VqdShark struct {
|
type VqdShark struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
SharkThr float64 `gorm:"column:shark_thr;notNull;default:0;comment:抖动阈值参数" json:"shark_thr"` // 默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.8
|
SharkThr float32 `gorm:"column:shark_thr;notNull;default:0;comment:抖动阈值参数" json:"shark_thr"` // 默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.8
|
||||||
SharkAbnNumRatio float64 `gorm:"column:shark_abn_num_ratio;notNull;default:0;comment:出现抖动次数的比例" json:"shark_abn_num_ratio"` // 默认为0.2, 取值范围: 0~1, 建议范围: 0.1~0.6
|
SharkAbnNumRatio float32 `gorm:"column:shark_abn_num_ratio;notNull;default:0;comment:出现抖动次数的比例" json:"shark_abn_num_ratio"` // 默认为0.2, 取值范围: 0~1, 建议范围: 0.1~0.6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdShark) Value() (driver.Value, error) {
|
func (a VqdShark) Value() (driver.Value, error) {
|
||||||
@ -117,8 +117,8 @@ func (i *VqdShark) Scan(input interface{}) error {
|
|||||||
// 冻结检测
|
// 冻结检测
|
||||||
type VqdFreeze struct {
|
type VqdFreeze struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
FreezeThr float64 `gorm:"column:freeze_thr;notNull;default:0;comment:冻结阈值参数" json:"freeze_thr"` // 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
FreezeThr float32 `gorm:"column:freeze_thr;notNull;default:0;comment:冻结阈值参数" json:"freeze_thr"` // 默认 0.4, 取值范围: 0~1, 建议范围: 0.2~0.6
|
||||||
FreezeAbnNumRatio float64 `gorm:"column:freeze_abn_num_ratio;notNull;default:0;comment:冻结帧数占得比例" json:"freeze_abn_num_ratio"` // 默认为0.99, 取值范围: 0.8~1, 建议范围: 0.95~1
|
FreezeAbnNumRatio float32 `gorm:"column:freeze_abn_num_ratio;notNull;default:0;comment:冻结帧数占得比例" json:"freeze_abn_num_ratio"` // 默认为0.99, 取值范围: 0.8~1, 建议范围: 0.95~1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdFreeze) Value() (driver.Value, error) {
|
func (a VqdFreeze) Value() (driver.Value, error) {
|
||||||
@ -131,8 +131,8 @@ func (i *VqdFreeze) Scan(input interface{}) error {
|
|||||||
// 偏色检测
|
// 偏色检测
|
||||||
type VqdColor struct {
|
type VqdColor struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
ColorThr float64 `gorm:"column:color_thr;notNull;default:0;comment:偏色判断值" json:"color_thr"` // 默认为0.18, 取值范围: 0~1, 建议范围: 0.1~0.5
|
ColorThr float32 `gorm:"column:color_thr;notNull;default:0;comment:偏色判断值" json:"color_thr"` // 默认为0.18, 取值范围: 0~1, 建议范围: 0.1~0.5
|
||||||
ColorAbnNumRatio float64 `gorm:"column:color_abn_num_ratio;notNull;default:0;comment:偏色次数比例" json:"color_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
ColorAbnNumRatio float32 `gorm:"column:color_abn_num_ratio;notNull;default:0;comment:偏色次数比例" json:"color_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdColor) Value() (driver.Value, error) {
|
func (a VqdColor) Value() (driver.Value, error) {
|
||||||
@ -145,8 +145,8 @@ func (i *VqdColor) Scan(input interface{}) error {
|
|||||||
// 遮挡检测
|
// 遮挡检测
|
||||||
type VqdOcclusion struct {
|
type VqdOcclusion struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
OcclusionThr float64 `gorm:"column:occlusion_thr;notNull;default:0;comment:遮挡判断阈值" json:"occlusion_thr"` // 默认为0.1, 取值范围: 0~1, 建议范围: 0.05~0.5
|
OcclusionThr float32 `gorm:"column:occlusion_thr;notNull;default:0;comment:遮挡判断阈值" json:"occlusion_thr"` // 默认为0.1, 取值范围: 0~1, 建议范围: 0.05~0.5
|
||||||
OcclusionAbnNumRatio float64 `gorm:"column:occlusion_abn_num_ratio;notNull;default:0;comment:遮挡次数比例" json:"occlusion_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
OcclusionAbnNumRatio float32 `gorm:"column:occlusion_abn_num_ratio;notNull;default:0;comment:遮挡次数比例" json:"occlusion_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdOcclusion) Value() (driver.Value, error) {
|
func (a VqdOcclusion) Value() (driver.Value, error) {
|
||||||
@ -159,8 +159,8 @@ func (i *VqdOcclusion) Scan(input interface{}) error {
|
|||||||
// 噪声检测
|
// 噪声检测
|
||||||
type VqdNoise struct {
|
type VqdNoise struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
NoiseThr float64 `gorm:"column:noise_thr;notNull;default:0;comment:噪声判断阈值" json:"noise_thr"` // 默认为 0.3, 取值范围: 0~1, 建议范围: 0.2~0.8
|
NoiseThr float32 `gorm:"column:noise_thr;notNull;default:0;comment:噪声判断阈值" json:"noise_thr"` // 默认为 0.3, 取值范围: 0~1, 建议范围: 0.2~0.8
|
||||||
NoiseAbnNumRatio float64 `gorm:"column:noise_abn_num_ratio;notNull;default:0;comment:噪声次数比例" json:"noise_abn_num_ratio"` // 默认为0.6, 取值范围: 0~1, 建议范围: 0.3~0.9
|
NoiseAbnNumRatio float32 `gorm:"column:noise_abn_num_ratio;notNull;default:0;comment:噪声次数比例" json:"noise_abn_num_ratio"` // 默认为0.6, 取值范围: 0~1, 建议范围: 0.3~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdNoise) Value() (driver.Value, error) {
|
func (a VqdNoise) Value() (driver.Value, error) {
|
||||||
@ -173,9 +173,9 @@ func (i *VqdNoise) Scan(input interface{}) error {
|
|||||||
// 对比度检测
|
// 对比度检测
|
||||||
type VqdContrast struct {
|
type VqdContrast struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
CtraLowThr float64 `gorm:"column:ctra_low_thr;notNull;default:0;comment:低对比度判断阈值" json:"ctra_low_thr"` // 默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.3
|
CtraLowThr float32 `gorm:"column:ctra_low_thr;notNull;default:0;comment:低对比度判断阈值" json:"ctra_low_thr"` // 默认为 0.2, 取值范围: 0~1, 建议范围: 0.1~0.3
|
||||||
CtraHighThr float64 `gorm:"column:ctra_high_thr;notNull;default:0;comment:高对比度判断阈值" json:"ctra_high_thr"` // 默认为 0.8, 取值范围: 0~1, 建议范围: 0.7~0.9
|
CtraHighThr float32 `gorm:"column:ctra_high_thr;notNull;default:0;comment:高对比度判断阈值" json:"ctra_high_thr"` // 默认为 0.8, 取值范围: 0~1, 建议范围: 0.7~0.9
|
||||||
CtraAbnNumRatio float64 `gorm:"column:ctra_abn_num_ratio;notNull;default:0;comment:对比度异常次数比例" json:"ctra_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
CtraAbnNumRatio float32 `gorm:"column:ctra_abn_num_ratio;notNull;default:0;comment:对比度异常次数比例" json:"ctra_abn_num_ratio"` // 默认为0.5, 取值范围: 0~1, 建议范围: 0.3~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdContrast) Value() (driver.Value, error) {
|
func (a VqdContrast) Value() (driver.Value, error) {
|
||||||
@ -188,8 +188,8 @@ func (i *VqdContrast) Scan(input interface{}) error {
|
|||||||
// 马赛克检测
|
// 马赛克检测
|
||||||
type VqdMosaic struct {
|
type VqdMosaic struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
MosaicThr float64 `gorm:"column:mosaic_thr;notNull;default:0;comment:马赛克阈值参数" json:"mosaic_thr"` // 默认为 0.1 取值范围: 0~1, 建议范围: 0.1~0.9
|
MosaicThr float32 `gorm:"column:mosaic_thr;notNull;default:0;comment:马赛克阈值参数" json:"mosaic_thr"` // 默认为 0.1 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
MosaicAbnNumRatio float64 `gorm:"column:mosaic_abn_num_ratio;notNull;default:0;comment:马赛克次数比例" json:"mosaic_abn_num_ratio"` // 默认为0.5,取值范围: 0~1, 建议范围: 0.3
|
MosaicAbnNumRatio float32 `gorm:"column:mosaic_abn_num_ratio;notNull;default:0;comment:马赛克次数比例" json:"mosaic_abn_num_ratio"` // 默认为0.5,取值范围: 0~1, 建议范围: 0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdMosaic) Value() (driver.Value, error) {
|
func (a VqdMosaic) Value() (driver.Value, error) {
|
||||||
@ -202,9 +202,9 @@ func (i *VqdMosaic) Scan(input interface{}) error {
|
|||||||
// 花屏检测
|
// 花屏检测
|
||||||
type VqdFlower struct {
|
type VqdFlower struct {
|
||||||
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
Enable bool `gorm:"column:enable;notNull;default:FALSE;comment:启用" json:"enable"` // 启用
|
||||||
FlowerThr float64 `gorm:"column:flower_thr;notNull;default:0;comment:花屏阈值参数" json:"flower_thr"` // 默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9
|
FlowerThr float32 `gorm:"column:flower_thr;notNull;default:0;comment:花屏阈值参数" json:"flower_thr"` // 默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
FlowerAbnNumRatio float64 `gorm:"column:flower_abn_num_ratio;notNull;default:0;comment:花屏次数比例" json:"flower_abn_num_ratio"` // 默认为0.6, 取值范围: 0~1, 建议范围: 0.3
|
FlowerAbnNumRatio float32 `gorm:"column:flower_abn_num_ratio;notNull;default:0;comment:花屏次数比例" json:"flower_abn_num_ratio"` // 默认为0.6, 取值范围: 0~1, 建议范围: 0.3
|
||||||
MosaicThr float64 `gorm:"column:mosaic_thr;notNull;default:0;comment:阈值" json:"mosaic_thr"` // 默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9
|
MosaicThr float32 `gorm:"column:mosaic_thr;notNull;default:0;comment:阈值" json:"mosaic_thr"` // 默认为 0.3 取值范围: 0~1, 建议范围: 0.1~0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdFlower) Value() (driver.Value, error) {
|
func (a VqdFlower) Value() (driver.Value, error) {
|
||||||
@ -252,18 +252,50 @@ func (*VqdTimeTemplate) TableName() string {
|
|||||||
return "vqd_time_template"
|
return "vqd_time_template"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Abnormal struct {
|
||||||
|
Value float32 `json:"value"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Abnormals []Abnormal
|
||||||
|
|
||||||
|
func (a Abnormals) Value() (driver.Value, error) {
|
||||||
|
return json.Marshal(a)
|
||||||
|
}
|
||||||
|
func (i *Abnormals) Scan(input interface{}) error {
|
||||||
|
return orm.JsonUnmarshal(input, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultValue struct {
|
||||||
|
Thr1 float32 `json:"thr1"`
|
||||||
|
Name1 string `json:"name1"`
|
||||||
|
Thr2 float32 `json:"thr2"`
|
||||||
|
Name2 string `json:"name2"`
|
||||||
|
Ratio float32 `json:"ratio"` //比例
|
||||||
|
}
|
||||||
|
type DefaultValues []DefaultValue
|
||||||
|
|
||||||
|
func (a DefaultValues) Value() (driver.Value, error) {
|
||||||
|
return json.Marshal(a)
|
||||||
|
}
|
||||||
|
func (i *DefaultValues) Scan(input interface{}) error {
|
||||||
|
return orm.JsonUnmarshal(input, i)
|
||||||
|
}
|
||||||
|
|
||||||
type VqdAlarm struct {
|
type VqdAlarm struct {
|
||||||
orm.Model
|
orm.Model
|
||||||
AlarmName string `gorm:"column:alarm_name;notNull;default:'';comment:告警名称" json:"alarm_name"` // 告警名称
|
IsDeep bool `gorm:"column:is_deep;notNull;default:FALSE;comment:启用" json:"is_deep"`
|
||||||
AlarmValue string `gorm:"column:alarm_value;notNull;default:'';comment:告警参数" json:"alarm_value"` // 告警参数
|
ChannelID string `gorm:"column:channel_id;notNull;default:'';comment:关联通道" json:"channel_id"` // 关联通道
|
||||||
ChannelID string `gorm:"column:channel_id;notNull;default:'';comment:关联通道" json:"channel_id"` // 关联通道
|
ChannelName string `gorm:"column:channel_name;notNull;default:'';comment:关联通道名称" json:"channel_name"` // 关联通道名称
|
||||||
ChannelName string `gorm:"column:channel_name;notNull;default:'';comment:关联通道名称" json:"channel_name"` // 关联通道名称
|
PlanID int64 `gorm:"column:plan_id;notNull;default:0;comment:关联计划" json:"plan_id"` // 关联计划
|
||||||
TaskTemplateID int64 `gorm:"column:task_template_id;notNull;default:0;comment:关联模板" json:"task_template_id"` //关联模板
|
PlanName string `gorm:"column:plan_name;notNull;default:0;comment:关联计划名称" json:"plan_name"` // 关联计划名称
|
||||||
TaskTemplateName string `gorm:"column:task_template_name;notNull;default:0;comment:关联模板名称" json:"task_template_name"` //关联模板名称
|
TaskTemplateID int64 `gorm:"column:task_template_id;notNull;default:0;comment:关联模板" json:"task_template_id"` // 关联模板
|
||||||
TaskID int64 `gorm:"column:task_id;notNull;default:0;comment:关联任务" json:"task_id"` // 关联任务名称
|
TaskTemplateName string `gorm:"column:task_template_name;notNull;default:0;comment:关联模板名称" json:"task_template_name"` // 关联模板名称
|
||||||
TaskName string `gorm:"column:task_name;notNull;default:'';comment:关联任务名称" json:"task_name"` // 任务名称
|
TaskID int64 `gorm:"column:task_id;notNull;default:0;comment:关联任务" json:"task_id"` // 关联任务名称
|
||||||
FilePath string `gorm:"column:file_path;notNull;default:'';comment:文件路径" json:"file_path"` // 文件路径
|
TaskName string `gorm:"column:task_name;notNull;default:'';comment:关联任务名称" json:"task_name"` // 任务名称
|
||||||
|
FilePath string `gorm:"column:file_path;notNull;default:'';comment:文件路径" json:"file_path"` // 文件路径
|
||||||
|
Abnormals Abnormals `gorm:"column:abnormals;type:jsonb;notNull;default:'{}';comment:告警异常列表" json:"abnormals"` // 告警异常列表
|
||||||
|
DefaultValues DefaultValues `gorm:"column:default_values;type:jsonb;notNull;default:'{}';comment:设置的默认阈值" json:"default_values"` // 设置的默认阈值
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName database table name
|
// TableName database table name
|
||||||
|
|||||||
@ -34,9 +34,9 @@ func (c Core) FindVqdAlarmAll() ([]*VqdAlarm, int64, error) {
|
|||||||
// FindVqdAlarm Paginated search
|
// FindVqdAlarm Paginated search
|
||||||
func (c Core) FindVqdAlarm(ctx context.Context, in *FindVqdAlarmInput) ([]*VqdAlarm, int64, error) {
|
func (c Core) FindVqdAlarm(ctx context.Context, in *FindVqdAlarmInput) ([]*VqdAlarm, int64, error) {
|
||||||
items := make([]*VqdAlarm, 0)
|
items := make([]*VqdAlarm, 0)
|
||||||
if in.AlarmName != "" {
|
if in.Name != "" {
|
||||||
query := orm.NewQuery(8).
|
query := orm.NewQuery(8).
|
||||||
Where("audio_name like ? OR channel_id like ? OR channel_name like ?", "%"+in.AlarmName+"%", "%"+in.AlarmName+"%", "%"+in.AlarmName+"%").OrderBy("created_at DESC")
|
Where("channel_name like ? OR channel_id like ? OR channel_name like ? OR plan_name like ? OR task_template_name like ? OR task_name like ? ", "%"+in.Name+"%", "%"+in.Name+"%", "%"+in.Name+"%", "%"+in.Name+"%", "%"+in.Name+"%", "%"+in.Name+"%").OrderBy("created_at DESC")
|
||||||
total, err := c.store.VqdAlarm().Find(ctx, &items, in, query.Encode()...)
|
total, err := c.store.VqdAlarm().Find(ctx, &items, in, query.Encode()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
|
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
type FindVqdAlarmInput struct {
|
type FindVqdAlarmInput struct {
|
||||||
web.PagerFilter
|
web.PagerFilter
|
||||||
AlarmName string `form:"alarm_name"` // 名称
|
Name string `form:"name"` // 名称
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditVqdAlarmInput struct {
|
type EditVqdAlarmInput struct {
|
||||||
@ -15,15 +15,18 @@ type EditVqdAlarmInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddVqdAlarmInput struct {
|
type AddVqdAlarmInput struct {
|
||||||
AlarmName string `json:"alarm_name"` // 告警名称
|
PlanID int64 `json:"plan_id"` // 关联计划
|
||||||
AlarmValue string `json:"alarm_value"` // 告警参数
|
PlanName string `json:"plan_name"` // 关联计划名称
|
||||||
ChannelID string `json:"channel_id"` // 关联通道
|
ChannelID string `json:"channel_id"` // 关联通道
|
||||||
ChannelName string `json:"channel_name"` // 关联通道名称
|
ChannelName string `json:"channel_name"` // 关联通道名称
|
||||||
TaskTemplateID int64 `json:"task_template_id"` // 关联模板
|
TaskTemplateID int64 `json:"task_template_id"` // 关联模板
|
||||||
TaskTemplateName string `json:"task_template_name"` // 关联模板名称
|
TaskTemplateName string `json:"task_template_name"` // 关联模板名称
|
||||||
TaskID int64 `json:"task_id"` // 关联任务名称
|
TaskID int64 `json:"task_id"` // 关联任务名称
|
||||||
TaskName string `json:"task_name"` // 任务名称
|
TaskName string `json:"task_name"` // 任务名称
|
||||||
FilePath string `json:"file_path"` // 文件路径
|
FilePath string `json:"file_path"` // 文件路径
|
||||||
|
IsDeep bool `json:"is_deep"`
|
||||||
|
Abnormals Abnormals `json:"abnormals"` // 告警异常列表
|
||||||
|
DefaultValues DefaultValues `json:"default_values"` // 设置的默认阈值
|
||||||
}
|
}
|
||||||
type DelVqdAlarmInput struct {
|
type DelVqdAlarmInput struct {
|
||||||
IDs []int `json:"ids"` // id
|
IDs []int `json:"ids"` // id
|
||||||
|
|||||||
@ -31,6 +31,34 @@ func (c Core) FindVqdTaskAll() ([]*VqdTask, int64, error) {
|
|||||||
return items, total, nil
|
return items, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindVqdTemplateID Paginated search
|
||||||
|
func (c Core) FindVqdPlanID(ctx context.Context, id int) ([]*VqdTask, int64, error) {
|
||||||
|
items := make([]*VqdTask, 0)
|
||||||
|
in := &FindVqdTaskInput{}
|
||||||
|
in.Size = 99999
|
||||||
|
in.Page = 1
|
||||||
|
query := orm.NewQuery(2).Where("time_template_id = ?", id)
|
||||||
|
total, err := c.store.VqdTask().Find(ctx, &items, in, query.Encode()...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return items, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindVqdTemplateID Paginated search
|
||||||
|
func (c Core) FindVqdTemplateID(ctx context.Context, id int) ([]*VqdTask, int64, error) {
|
||||||
|
items := make([]*VqdTask, 0)
|
||||||
|
in := &FindVqdTaskInput{}
|
||||||
|
in.Size = 99999
|
||||||
|
in.Page = 1
|
||||||
|
query := orm.NewQuery(2).Where("task_template_id = ?", id)
|
||||||
|
total, err := c.store.VqdTask().Find(ctx, &items, in, query.Encode()...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return items, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindVqdTask Paginated search
|
// FindVqdTask Paginated search
|
||||||
func (c Core) FindVqdTask(ctx context.Context, in *FindVqdTaskInput) ([]*VqdTask, int64, error) {
|
func (c Core) FindVqdTask(ctx context.Context, in *FindVqdTaskInput) ([]*VqdTask, int64, error) {
|
||||||
items := make([]*VqdTask, 0)
|
items := make([]*VqdTask, 0)
|
||||||
@ -64,6 +92,18 @@ func (c Core) FindVqdTaskTemplateID(ctx context.Context, id int) (*VqdTask, erro
|
|||||||
return &out, nil
|
return &out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindVqdTaskPlanID Query a single object
|
||||||
|
func (c Core) FindVqdTaskPlanID(ctx context.Context, id int) (*VqdTask, error) {
|
||||||
|
var out VqdTask
|
||||||
|
if err := c.store.VqdTask().Get(ctx, &out, orm.Where("time_template_id=?", id)); err != nil {
|
||||||
|
if orm.IsErrRecordNotFound(err) {
|
||||||
|
return nil, reason.ErrNotFound.Withf(`Get err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return nil, reason.ErrDB.Withf(`Get err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetVqdTask Query a single object
|
// GetVqdTask Query a single object
|
||||||
func (c Core) GetVqdTask(ctx context.Context, id int) (*VqdTask, error) {
|
func (c Core) GetVqdTask(ctx context.Context, id int) (*VqdTask, error) {
|
||||||
var out VqdTask
|
var out VqdTask
|
||||||
@ -86,6 +126,16 @@ func (c Core) GetNameVqdTask(ctx context.Context, name string) (*VqdTask, error)
|
|||||||
}
|
}
|
||||||
return &out, nil
|
return &out, nil
|
||||||
}
|
}
|
||||||
|
func (c Core) GetNameVqdTaskChannelID(ctx context.Context, name string) (*VqdTask, error) {
|
||||||
|
var out VqdTask
|
||||||
|
if err := c.store.VqdTask().Get(ctx, &out, orm.Where("channel_id=?", name)); err != nil {
|
||||||
|
if orm.IsErrRecordNotFound(err) {
|
||||||
|
return nil, reason.ErrNotFound.Withf(`Get err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return nil, reason.ErrDB.Withf(`Get err[%s]`, err.Error())
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddVqdTask Insert into database
|
// AddVqdTask Insert into database
|
||||||
func (c Core) AddVqdTask(ctx context.Context, in *AddVqdTaskInput) (*VqdTask, error) {
|
func (c Core) AddVqdTask(ctx context.Context, in *AddVqdTaskInput) (*VqdTask, error) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package vqdtask
|
package vqdtask
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"easyvqd/pkg/vqdcms"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@ -12,7 +13,6 @@ import (
|
|||||||
// 配置参数
|
// 配置参数
|
||||||
const (
|
const (
|
||||||
// 要清理的目标目录(请替换为你实际的目录路径)
|
// 要清理的目标目录(请替换为你实际的目录路径)
|
||||||
cleanDir = "/snap"
|
|
||||||
// 定时任务执行间隔(每天执行一次)
|
// 定时任务执行间隔(每天执行一次)
|
||||||
interval = 24 * time.Hour
|
interval = 24 * time.Hour
|
||||||
// 批量删除大小(避免单次删除过多锁表)
|
// 批量删除大小(避免单次删除过多锁表)
|
||||||
@ -195,10 +195,10 @@ func (c Core) cleanExpiredFiles() error {
|
|||||||
expireDays = 1
|
expireDays = 1
|
||||||
}
|
}
|
||||||
expireTime := time.Now().Add(-expireDays * 24 * time.Hour)
|
expireTime := time.Now().Add(-expireDays * 24 * time.Hour)
|
||||||
slog.Info(fmt.Sprintf("开始清理目录 [%s] 中超过 %d 天的文件,过期时间阈值:%s", cleanDir, expireDays, expireTime.Format(time.RFC3339)))
|
slog.Info(fmt.Sprintf("开始清理目录 [%s] 中超过 %d 天的文件,过期时间阈值:%s", vqdcms.VQD_IMAGES_DIR, expireDays, expireTime.Format(time.RFC3339)))
|
||||||
|
|
||||||
dir, _ := os.Getwd()
|
dir, _ := os.Getwd()
|
||||||
rootDir := filepath.Join(dir, cleanDir)
|
rootDir := filepath.Join(dir, vqdcms.VQD_IMAGES_DIR)
|
||||||
dateDirs, err := os.ReadDir(rootDir)
|
dateDirs, err := os.ReadDir(rootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("访问根目录路径失败", "path", rootDir, "err", err)
|
slog.Error("访问根目录路径失败", "path", rootDir, "err", err)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package vqdtask
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"easyvqd/internal/conf"
|
"easyvqd/internal/conf"
|
||||||
"easyvqd/internal/core/host"
|
"easyvqd/internal/core/host"
|
||||||
"easyvqd/internal/core/vqd"
|
"easyvqd/internal/core/vqd"
|
||||||
@ -19,6 +20,7 @@ type Core struct {
|
|||||||
HostCore *host.Core
|
HostCore *host.Core
|
||||||
VqdTaskCore *vqd.Core
|
VqdTaskCore *vqd.Core
|
||||||
Cfg *conf.Bootstrap
|
Cfg *conf.Bootstrap
|
||||||
|
ResultCb vqdcms.VQDResultCB
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -31,142 +33,173 @@ func NewCore(HostCore *host.Core, VqdTaskCore *vqd.Core, Cfg *conf.Bootstrap) *C
|
|||||||
VqdTaskCore: VqdTaskCore,
|
VqdTaskCore: VqdTaskCore,
|
||||||
Cfg: Cfg,
|
Cfg: Cfg,
|
||||||
}
|
}
|
||||||
core.HostCore.CbIFrame = func(s string, data []byte, codes int) {
|
core.ResultCb = func(v vqdcms.AbnormalModel) {
|
||||||
//fmt.Println("res", s, codes, len(data))
|
|
||||||
v, ok := VqdTaskMap.LoadTaskMap(s)
|
in := &vqd.AddVqdAlarmInput{
|
||||||
if ok {
|
ChannelName: v.ChannelName,
|
||||||
v.SendData(data, codes)
|
TaskTemplateName: v.TemplateName,
|
||||||
|
TaskName: v.TaskName,
|
||||||
|
PlanName: v.PlanName,
|
||||||
|
TaskID: int64(v.ID),
|
||||||
|
TaskTemplateID: int64(v.TemplateID),
|
||||||
|
PlanID: int64(v.PlanID),
|
||||||
|
IsDeep: v.IsDeep,
|
||||||
|
FilePath: v.FilePath,
|
||||||
|
}
|
||||||
|
var Abnormals vqd.Abnormals
|
||||||
|
if len(v.Abnormals) > 0 {
|
||||||
|
for _, abnormal := range v.Abnormals {
|
||||||
|
item := vqd.Abnormal{
|
||||||
|
Value: abnormal.Value,
|
||||||
|
Name: abnormal.Name,
|
||||||
|
}
|
||||||
|
Abnormals = append(Abnormals, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.Abnormals = Abnormals
|
||||||
|
|
||||||
|
var DefaultValues vqd.DefaultValues
|
||||||
|
if len(v.DefaultValues) > 0 {
|
||||||
|
for _, defaultValue := range v.DefaultValues {
|
||||||
|
item := vqd.DefaultValue{
|
||||||
|
Thr1: defaultValue.Thr1,
|
||||||
|
Name1: defaultValue.Name1,
|
||||||
|
Thr2: defaultValue.Thr2,
|
||||||
|
Name2: defaultValue.Name2,
|
||||||
|
Ratio: defaultValue.Ratio,
|
||||||
|
}
|
||||||
|
DefaultValues = append(DefaultValues, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.DefaultValues = DefaultValues
|
||||||
|
_, err := core.VqdTaskCore.AddVqdAlarm(context.TODO(), in)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("add alarm", "err", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
core.HostCore.CbIFrame = func(s string, data []byte, codes int) {
|
||||||
|
v, ok := VqdTaskMap.LoadTaskMap(s)
|
||||||
|
if ok {
|
||||||
|
v.SendData(data, VIDEO_CODEC_H265)
|
||||||
|
}
|
||||||
|
//slog.Debug("cb IFrame", "name", s, "codes", codes)
|
||||||
|
}
|
||||||
time.AfterFunc(time.Duration(5)*time.Second, func() {
|
time.AfterFunc(time.Duration(5)*time.Second, func() {
|
||||||
//in := &vqd.AddVqdAlarmInput{
|
|
||||||
// AlarmName: "遮挡告警",
|
|
||||||
// AlarmValue: "",
|
|
||||||
// ChannelID: "",
|
|
||||||
// ChannelName: "",
|
|
||||||
// TaskTemplateID: 0,
|
|
||||||
// TaskTemplateName: "",
|
|
||||||
// TaskID: 0,
|
|
||||||
// TaskName: "",
|
|
||||||
// FilePath: "",
|
|
||||||
//}
|
|
||||||
//for i := 0; i < 2; i++ {
|
|
||||||
// core.VqdTaskCore.AddVqdAlarm(context.TODO(), in)
|
|
||||||
//}
|
|
||||||
|
|
||||||
// 启用诊断分析
|
// 启用诊断分析
|
||||||
core.InitVqdTask()
|
core.InitVqdTask()
|
||||||
core.AddTaskVqd(1, "PVWPQBPIv32UI_01")
|
|
||||||
})
|
})
|
||||||
// 启用定时清理任务
|
// 启用定时清理任务
|
||||||
go core.scheduleCleanTask()
|
go core.scheduleCleanTask()
|
||||||
// 测试
|
|
||||||
//go core.OpenStartVqd()
|
|
||||||
// 启用任务管理器
|
// 启用任务管理器
|
||||||
return core
|
return core
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Core) InitVqdTask() {
|
func (c *Core) InitVqdTask() {
|
||||||
err := vqdcms.VQDInit()
|
err := vqdcms.VQDInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("vqd cms open", "err", err.Error())
|
slog.Error("vqd cms open", "err", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
all, _, err := c.VqdTaskCore.FindVqdTaskAll()
|
||||||
|
if err == nil {
|
||||||
|
for _, vqdTask := range all {
|
||||||
|
c.AddTaskVqd(vqdTask.ID)
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (c Core) UnVqdTask() {
|
func (c *Core) UnVqdTask() {
|
||||||
|
VqdTaskMap.DeleteTaskMapAll()
|
||||||
vqdcms.VQDUnInit()
|
vqdcms.VQDUnInit()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (c Core) AddTaskVqd(taskId int, chnId string) {
|
func (c *Core) AddTaskVqd(taskId int) error {
|
||||||
cb := func(res vqdcms.AbnormalModel) {
|
|
||||||
fmt.Println("res", res)
|
|
||||||
}
|
|
||||||
para := vqdcms.NewVQDPara()
|
|
||||||
v := vqdcms.NewVQDHandle(cb, taskId, chnId).Create(para)
|
|
||||||
VqdTaskMap.StoreChildMap(fmt.Sprintf("%s", chnId), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
//func (c Core) OpenStartVqd() {
|
task, err := c.VqdTaskCore.GetVqdTask(context.TODO(), taskId)
|
||||||
//
|
if err != nil {
|
||||||
// err := vqdcms.VQDInit()
|
slog.Error("vqd add task find", "err", err.Error())
|
||||||
// if err != nil {
|
return err
|
||||||
// fmt.Println("程序异常", err.Error())
|
}
|
||||||
// return
|
taskTemplate, err := c.VqdTaskCore.GetIDVqdTaskTemplate(context.TODO(), task.TaskTemplateID)
|
||||||
// }
|
if err != nil {
|
||||||
// dir, _ := os.Getwd()
|
slog.Error("vqd add task find template", "err", err.Error())
|
||||||
// rootPath := filepath.Join(dir, "gbs_buf264") // 你的H.264裸流文件路径
|
return err
|
||||||
//
|
}
|
||||||
// v := vqdcms.NewVQDHandle(nil, 1)
|
taskPlan, err := c.VqdTaskCore.GetVqdTimeTemplate(context.TODO(), int(task.TimeTemplateID))
|
||||||
//
|
if err != nil {
|
||||||
// para := vqdcms.NewVQDPara()
|
slog.Error("vqd add task find plan", "err", err.Error())
|
||||||
// v.SetVQDConfig(para)
|
return err
|
||||||
// v.Create(para)
|
}
|
||||||
// entries, err := os.ReadDir(rootPath)
|
chnId := task.ChannelID
|
||||||
// if err != nil {
|
|
||||||
// fmt.Printf("读取目录失败: %v\n", err)
|
para := vqdcms.NewVQDPara(taskTemplate)
|
||||||
// return
|
info := vqdcms.VQDHandleInfo{
|
||||||
// }
|
ChannelID: chnId,
|
||||||
//
|
ChannelName: task.ChannelName,
|
||||||
// fmt.Printf("目录 %s 下的内容:\n", dir)
|
TaskID: task.ID,
|
||||||
// for _, entry := range entries {
|
TaskName: task.Name,
|
||||||
// if entry.IsDir() {
|
TemplateID: taskTemplate.ID,
|
||||||
// fmt.Printf("[目录] %s\n", entry.Name())
|
TemplateName: taskTemplate.Name,
|
||||||
// } else {
|
PlanID: taskPlan.ID,
|
||||||
// h264Paths := filepath.Join(rootPath, entry.Name()) // 你的H.264裸流文件路径
|
PlanName: taskPlan.Name,
|
||||||
// fmt.Println(h264Paths)
|
Plans: taskPlan.Plans,
|
||||||
// data, err := os.ReadFile(h264Paths)
|
}
|
||||||
// if err == nil {
|
v := vqdcms.NewVQDHandle(c.ResultCb, c.HostCore, info).Create(para, taskPlan.Plans)
|
||||||
// datap := GetIFramePointer(data)
|
|
||||||
// width, height, buf, err := v.de.PushDataEx(uintptr(datap.Pointer), datap.Length, VIDEO_CODEC_H264)
|
VqdTaskMap.StoreChildMap(fmt.Sprintf("%s", chnId), v)
|
||||||
// if err == nil {
|
return nil
|
||||||
// v.SendData(buf, width, height)
|
}
|
||||||
// slog.Info("I帧转YUV成功: ", "h264Paths", h264Paths)
|
func (c *Core) UpdateTaskVqd(taskId int) error {
|
||||||
// } else {
|
task, err := c.VqdTaskCore.GetVqdTask(context.TODO(), taskId)
|
||||||
// //slog.Error("I帧转YUV失败: ", "h264Paths", h264Paths )
|
if err != nil {
|
||||||
// }
|
slog.Error("vqd update task find", "err", err.Error())
|
||||||
// }
|
return err
|
||||||
// }
|
}
|
||||||
// }
|
v, ok := VqdTaskMap.LoadTaskMap(task.ChannelID)
|
||||||
//
|
if ok {
|
||||||
// return
|
taskTemplate, err := c.VqdTaskCore.GetIDVqdTaskTemplate(context.TODO(), task.TaskTemplateID)
|
||||||
//}
|
if err != nil {
|
||||||
//
|
slog.Error("vqd update task find template", "err", err.Error())
|
||||||
//// H264IFrameData 封装I帧数据和指针信息
|
return err
|
||||||
//type H264IFrameData struct {
|
}
|
||||||
// Data []byte // I帧原始字节数据
|
taskPlan, err := c.VqdTaskCore.GetVqdTimeTemplate(context.TODO(), int(task.TimeTemplateID))
|
||||||
// Pointer unsafe.Pointer // 指向数据的原始指针
|
if err != nil {
|
||||||
// Length int // 数据长度(字节数)
|
slog.Error("vqd add task find plan", "err", err.Error())
|
||||||
// IsValid bool // 指针是否有效
|
return err
|
||||||
//}
|
}
|
||||||
//
|
para := vqdcms.NewVQDPara(taskTemplate)
|
||||||
//// GetIFramePointer 将字节切片转换为原始指针
|
info := vqdcms.VQDHandleInfo{
|
||||||
//// 注意:unsafe包的使用会绕过Go的内存安全检查,需谨慎
|
ChannelID: task.ChannelID,
|
||||||
//func GetIFramePointer(data []byte) *H264IFrameData {
|
ChannelName: task.ChannelName,
|
||||||
// if len(data) == 0 {
|
TaskID: task.ID,
|
||||||
// return &H264IFrameData{
|
TaskName: task.Name,
|
||||||
// IsValid: false,
|
TemplateID: taskTemplate.ID,
|
||||||
// Length: 0,
|
TemplateName: taskTemplate.Name,
|
||||||
// }
|
PlanID: taskPlan.ID,
|
||||||
// }
|
PlanName: taskPlan.Name,
|
||||||
//
|
Plans: taskPlan.Plans,
|
||||||
// // 方式1:直接通过unsafe获取切片底层数组的指针(推荐,高效)
|
}
|
||||||
// // 切片的底层结构是:指向数组的指针 + 长度 + 容量
|
errs := v.SetVQDConfig(para, info)
|
||||||
// ptr := unsafe.Pointer(&data[0])
|
if errs != nil {
|
||||||
//
|
slog.Error("vqd update set config err", "err", errs.Error())
|
||||||
// // 方式2:通过reflect获取指针(更直观展示切片结构,可选)
|
return err
|
||||||
// // sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
}
|
||||||
// // ptr := unsafe.Pointer(sliceHeader.Data)
|
VqdTaskMap.StoreChildMap(fmt.Sprintf("%s", task.ChannelID), v)
|
||||||
//
|
}
|
||||||
// return &H264IFrameData{
|
return nil
|
||||||
// Data: data,
|
|
||||||
// Pointer: ptr,
|
}
|
||||||
// Length: len(data),
|
func (c *Core) DelTaskVqd(taskId int, chnId string) {
|
||||||
// IsValid: true,
|
v, ok := VqdTaskMap.LoadTaskMap(chnId)
|
||||||
// }
|
if ok {
|
||||||
//}
|
v.Destroy()
|
||||||
|
}
|
||||||
|
VqdTaskMap.DeleteTaskMap(chnId)
|
||||||
|
}
|
||||||
|
|
||||||
// 测试i帧数据是否可以转为图片文件
|
// 测试i帧数据是否可以转为图片文件
|
||||||
func CheckIFramesToJpg() {
|
func CheckIFramesToJpg() {
|
||||||
|
|||||||
@ -4,3 +4,5 @@ const (
|
|||||||
VIDEO_CODEC_H264 = 0x1C
|
VIDEO_CODEC_H264 = 0x1C
|
||||||
VIDEO_CODEC_H265 = 0xAE
|
VIDEO_CODEC_H265 = 0xAE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//status
|
||||||
|
|||||||
@ -56,8 +56,8 @@ func setupRouter(r *gin.Engine, uc *Usecase) {
|
|||||||
r.GET("/app/metrics/api", web.WrapH(uc.getMetricsAPI))
|
r.GET("/app/metrics/api", web.WrapH(uc.getMetricsAPI))
|
||||||
//快照
|
//快照
|
||||||
dir, _ := os.Getwd()
|
dir, _ := os.Getwd()
|
||||||
uploadsDir := filepath.Join(dir, "uploads")
|
uploadsDir := filepath.Join(dir, "snap")
|
||||||
r.Use(statics.Serve("/uploads", statics.LocalFile(uploadsDir, true)))
|
r.Use(statics.Serve("/snap", statics.LocalFile(uploadsDir, true)))
|
||||||
|
|
||||||
versionapi.Register(r, uc.Version, auth)
|
versionapi.Register(r, uc.Version, auth)
|
||||||
registerConfig(r, ConfigAPI{uc: uc, cfg: uc.Conf})
|
registerConfig(r, ConfigAPI{uc: uc, cfg: uc.Conf})
|
||||||
@ -77,9 +77,9 @@ func setupRouter(r *gin.Engine, uc *Usecase) {
|
|||||||
ctx.Redirect(http.StatusTemporaryRedirect, target)
|
ctx.Redirect(http.StatusTemporaryRedirect, target)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(p, "/uploads/") {
|
if strings.HasPrefix(p, "/snap/") {
|
||||||
q := ctx.Request.URL.RawQuery
|
q := ctx.Request.URL.RawQuery
|
||||||
target := "/uploads/"
|
target := "/snap/"
|
||||||
if q != "" {
|
if q != "" {
|
||||||
target = target + "?" + q
|
target = target + "?" + q
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,15 +16,18 @@ func (a VqdTaskAPI) findVqdAlarm(c *gin.Context, in *vqd.FindVqdAlarmInput) (any
|
|||||||
//row := structs.Map(item)
|
//row := structs.Map(item)
|
||||||
row := make(map[string]interface{})
|
row := make(map[string]interface{})
|
||||||
row["id"] = item.ID
|
row["id"] = item.ID
|
||||||
row["alarm_name"] = item.AlarmName
|
row["is_deep"] = item.IsDeep
|
||||||
row["alarm_value"] = item.AlarmValue
|
|
||||||
row["channel_id"] = item.ChannelID
|
row["channel_id"] = item.ChannelID
|
||||||
row["channel_name"] = item.ChannelName
|
row["channel_name"] = item.ChannelName
|
||||||
|
row["plan_id"] = item.PlanID
|
||||||
|
row["plan_name"] = item.PlanName
|
||||||
row["task_template_id"] = item.TaskTemplateID
|
row["task_template_id"] = item.TaskTemplateID
|
||||||
row["task_template_name"] = item.TaskTemplateName
|
row["task_template_name"] = item.TaskTemplateName
|
||||||
row["task_id"] = item.TaskID
|
row["task_id"] = item.TaskID
|
||||||
row["task_name"] = item.TaskName
|
row["task_name"] = item.TaskName
|
||||||
row["file_path"] = item.FilePath
|
row["file_path"] = item.FilePath
|
||||||
|
row["abnormals"] = item.Abnormals
|
||||||
|
row["default_values"] = item.DefaultValues
|
||||||
row["created_at"] = item.CreatedAt
|
row["created_at"] = item.CreatedAt
|
||||||
row["updated_at"] = item.UpdatedAt
|
row["updated_at"] = item.UpdatedAt
|
||||||
|
|
||||||
@ -42,15 +45,18 @@ func (a VqdTaskAPI) getVqdAlarm(c *gin.Context, _ *struct{}) (any, error) {
|
|||||||
row := make(map[string]interface{})
|
row := make(map[string]interface{})
|
||||||
|
|
||||||
row["id"] = item.ID
|
row["id"] = item.ID
|
||||||
row["alarm_name"] = item.AlarmName
|
row["is_deep"] = item.IsDeep
|
||||||
row["alarm_value"] = item.AlarmValue
|
|
||||||
row["channel_id"] = item.ChannelID
|
row["channel_id"] = item.ChannelID
|
||||||
row["channel_name"] = item.ChannelName
|
row["channel_name"] = item.ChannelName
|
||||||
|
row["plan_id"] = item.PlanID
|
||||||
|
row["plan_name"] = item.PlanName
|
||||||
row["task_template_id"] = item.TaskTemplateID
|
row["task_template_id"] = item.TaskTemplateID
|
||||||
row["task_template_name"] = item.TaskTemplateName
|
row["task_template_name"] = item.TaskTemplateName
|
||||||
row["task_id"] = item.TaskID
|
row["task_id"] = item.TaskID
|
||||||
row["task_name"] = item.TaskName
|
row["task_name"] = item.TaskName
|
||||||
row["file_path"] = item.FilePath
|
row["file_path"] = item.FilePath
|
||||||
|
row["abnormals"] = item.Abnormals
|
||||||
|
row["default_values"] = item.DefaultValues
|
||||||
row["created_at"] = item.CreatedAt
|
row["created_at"] = item.CreatedAt
|
||||||
row["updated_at"] = item.UpdatedAt
|
row["updated_at"] = item.UpdatedAt
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,13 @@ func (a VqdTaskAPI) findVqdTask(c *gin.Context, in *vqd.FindVqdTaskInput) (any,
|
|||||||
if errs == nil && template != nil {
|
if errs == nil && template != nil {
|
||||||
row["time_template_name"] = timeTemplate.Name
|
row["time_template_name"] = timeTemplate.Name
|
||||||
}
|
}
|
||||||
|
row["error_msg"] = ""
|
||||||
|
row["status"] = 0
|
||||||
|
v, ok := vqdtask.VqdTaskMap.LoadTaskMap(item.ChannelID)
|
||||||
|
if ok {
|
||||||
|
row["error_msg"] = v.ErrorMsg
|
||||||
|
row["status"] = v.Status
|
||||||
|
}
|
||||||
row["created_at"] = item.CreatedAt
|
row["created_at"] = item.CreatedAt
|
||||||
row["updated_at"] = item.UpdatedAt
|
row["updated_at"] = item.UpdatedAt
|
||||||
|
|
||||||
@ -115,6 +122,13 @@ func (a VqdTaskAPI) getVqdTask(c *gin.Context, _ *struct{}) (any, error) {
|
|||||||
if errs == nil && template != nil {
|
if errs == nil && template != nil {
|
||||||
row["time_template_name"] = timeTemplate.Name
|
row["time_template_name"] = timeTemplate.Name
|
||||||
}
|
}
|
||||||
|
row["error_msg"] = ""
|
||||||
|
row["status"] = 0
|
||||||
|
v, ok := vqdtask.VqdTaskMap.LoadTaskMap(item.ChannelID)
|
||||||
|
if ok {
|
||||||
|
row["error_msg"] = v.ErrorMsg
|
||||||
|
row["status"] = v.Status
|
||||||
|
}
|
||||||
row["created_at"] = item.CreatedAt
|
row["created_at"] = item.CreatedAt
|
||||||
row["updated_at"] = item.UpdatedAt
|
row["updated_at"] = item.UpdatedAt
|
||||||
|
|
||||||
@ -122,34 +136,62 @@ func (a VqdTaskAPI) getVqdTask(c *gin.Context, _ *struct{}) (any, error) {
|
|||||||
return gin.H{"data": row}, err
|
return gin.H{"data": row}, err
|
||||||
}
|
}
|
||||||
func (a VqdTaskAPI) addVqdTask(c *gin.Context, in *vqd.AddVqdTaskInput) (any, error) {
|
func (a VqdTaskAPI) addVqdTask(c *gin.Context, in *vqd.AddVqdTaskInput) (any, error) {
|
||||||
_, err := a.core.AddVqdTask(c.Request.Context(), in)
|
taskChn, err := a.core.GetNameVqdTaskChannelID(c.Request.Context(), in.ChannelID)
|
||||||
|
if err == nil && taskChn != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`通道任务已存在 [%s] `, taskChn.ChannelID))
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err := a.core.AddVqdTask(c.Request.Context(), in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
err = a.vqdSdkCore.AddTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add task err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdTaskAPI) editVqdTask(c *gin.Context, in *vqd.EditVqdTaskInput) (any, error) {
|
func (a VqdTaskAPI) editVqdTask(c *gin.Context, in *vqd.EditVqdTaskInput) (any, error) {
|
||||||
ID, _ := strconv.Atoi(c.Param("id"))
|
ID, _ := strconv.Atoi(c.Param("id"))
|
||||||
_, err := a.core.GetVqdTask(c.Request.Context(), ID)
|
task, err := a.core.GetVqdTask(c.Request.Context(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
}
|
}
|
||||||
|
if task.ChannelID != in.ChannelID {
|
||||||
_, err = a.core.EditVqdTask(c.Request.Context(), in, ID)
|
taskChn, errs := a.core.GetNameVqdTaskChannelID(c.Request.Context(), in.ChannelID)
|
||||||
|
if errs == nil && taskChn != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`通道任务已存在 [%s] `, taskChn.ChannelID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info, err := a.core.EditVqdTask(c.Request.Context(), in, ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
if task.Enable == false && in.Enable {
|
||||||
|
err = a.vqdSdkCore.AddTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add task err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if info.Enable {
|
||||||
|
err = a.vqdSdkCore.UpdateTaskVqd(ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`update task err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a.vqdSdkCore.DelTaskVqd(ID, info.ChannelID)
|
||||||
|
}
|
||||||
|
}
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdTaskAPI) delVqdTask(c *gin.Context, _ *struct{}) (any, error) {
|
func (a VqdTaskAPI) delVqdTask(c *gin.Context, _ *struct{}) (any, error) {
|
||||||
ID, _ := strconv.Atoi(c.Param("id"))
|
ID, _ := strconv.Atoi(c.Param("id"))
|
||||||
_, err := a.core.DelVqdTask(c.Request.Context(), ID)
|
task, err := a.core.DelVqdTask(c.Request.Context(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
}
|
}
|
||||||
|
a.vqdSdkCore.DelTaskVqd(ID, task.ChannelID)
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,17 +69,27 @@ func (a VqdTaskAPI) getVqdTaskTemplate(c *gin.Context, _ *struct{}) (any, error)
|
|||||||
return gin.H{"data": row}, err
|
return gin.H{"data": row}, err
|
||||||
}
|
}
|
||||||
func (a VqdTaskAPI) addVqdTaskTemplate(c *gin.Context, in *vqd.AddVqdTaskTemplateInput) (any, error) {
|
func (a VqdTaskAPI) addVqdTaskTemplate(c *gin.Context, in *vqd.AddVqdTaskTemplateInput) (any, error) {
|
||||||
_, err := a.core.AddVqdTaskTemplate(c.Request.Context(), in)
|
template, err := a.core.AddVqdTaskTemplate(c.Request.Context(), in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
out, _, err := a.core.FindVqdTemplateID(c.Request.Context(), template.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find template all err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
for _, task := range out {
|
||||||
|
err = a.vqdSdkCore.UpdateTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdTaskAPI) editVqdTaskTemplate(c *gin.Context, in *vqd.EditVqdTaskTemplateInput) (any, error) {
|
func (a VqdTaskAPI) editVqdTaskTemplate(c *gin.Context, in *vqd.EditVqdTaskTemplateInput) (any, error) {
|
||||||
ID, _ := strconv.Atoi(c.Param("id"))
|
ID, _ := strconv.Atoi(c.Param("id"))
|
||||||
_, err := a.core.GetVqdTaskTemplate(c.Request.Context(), ID)
|
template, err := a.core.GetVqdTaskTemplate(c.Request.Context(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
}
|
}
|
||||||
@ -88,6 +98,16 @@ func (a VqdTaskAPI) editVqdTaskTemplate(c *gin.Context, in *vqd.EditVqdTaskTempl
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
out, _, err := a.core.FindVqdTemplateID(c.Request.Context(), template.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find template all err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
for _, task := range out {
|
||||||
|
err = a.vqdSdkCore.UpdateTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,17 +49,27 @@ func (a VqdTaskAPI) getVqdTimeTemplate(c *gin.Context, _ *struct{}) (any, error)
|
|||||||
return gin.H{"data": row}, err
|
return gin.H{"data": row}, err
|
||||||
}
|
}
|
||||||
func (a VqdTaskAPI) addVqdTimeTemplate(c *gin.Context, in *vqd.AddVqdTimeTemplateInput) (any, error) {
|
func (a VqdTaskAPI) addVqdTimeTemplate(c *gin.Context, in *vqd.AddVqdTimeTemplateInput) (any, error) {
|
||||||
_, err := a.core.AddVqdTimeTemplate(c.Request.Context(), in)
|
plan, err := a.core.AddVqdTimeTemplate(c.Request.Context(), in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out, _, err := a.core.FindVqdPlanID(c.Request.Context(), plan.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find plan all err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
for _, task := range out {
|
||||||
|
err = a.vqdSdkCore.UpdateTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a VqdTaskAPI) editVqdTimeTemplate(c *gin.Context, in *vqd.EditVqdTimeTemplateInput) (any, error) {
|
func (a VqdTaskAPI) editVqdTimeTemplate(c *gin.Context, in *vqd.EditVqdTimeTemplateInput) (any, error) {
|
||||||
ID, _ := strconv.Atoi(c.Param("id"))
|
ID, _ := strconv.Atoi(c.Param("id"))
|
||||||
_, err := a.core.GetVqdTimeTemplate(c.Request.Context(), ID)
|
plan, err := a.core.GetVqdTimeTemplate(c.Request.Context(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
}
|
}
|
||||||
@ -68,6 +78,16 @@ func (a VqdTaskAPI) editVqdTimeTemplate(c *gin.Context, in *vqd.EditVqdTimeTempl
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`edit vqdcms err [%s]`, err.Error()))
|
||||||
}
|
}
|
||||||
|
out, _, err := a.core.FindVqdPlanID(c.Request.Context(), plan.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find plan all err [%s]`, err.Error()))
|
||||||
|
}
|
||||||
|
for _, task := range out {
|
||||||
|
err = a.vqdSdkCore.UpdateTaskVqd(task.ID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
return gin.H{"data": "OK!"}, err
|
return gin.H{"data": "OK!"}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,14 +98,14 @@ func (a VqdTaskAPI) delVqdTimeTemplate(c *gin.Context, _ *struct{}) (any, error)
|
|||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
}
|
}
|
||||||
if info.IsDefault {
|
if info.IsDefault {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`默认模板不支持删除 [%s] `, info.Name))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`计划模板不支持删除 [%s] `, info.Name))
|
||||||
|
}
|
||||||
|
planInfo, err := a.core.FindVqdTaskPlanID(c.Request.Context(), ID)
|
||||||
|
if err == nil {
|
||||||
|
if planInfo != nil {
|
||||||
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`计划关联【%s】任务,需先清理【%s】任务后才能删除模板!`, planInfo.Name, planInfo.Name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//templateInfo, err := a.core.FindVqdTimeTemplateID(c.Request.Context(), ID)
|
|
||||||
//if err == nil {
|
|
||||||
// if templateInfo != nil {
|
|
||||||
// return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`模板关联【%s】任务,需先清理【%s】任务后才能删除模板!`, templateInfo.Name, templateInfo.Name))
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
_, err = a.core.DelVqdTimeTemplate(c.Request.Context(), ID)
|
_, err = a.core.DelVqdTimeTemplate(c.Request.Context(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqdcms [%d] err [%s]`, ID, err.Error()))
|
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqdcms [%d] err [%s]`, ID, err.Error()))
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -29,14 +28,6 @@ type VideoDecoder struct {
|
|||||||
handle C.EZ_DECODER_HANDLE
|
handle C.EZ_DECODER_HANDLE
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
IsStart bool
|
IsStart bool
|
||||||
|
|
||||||
file *os.File
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VideoDecoder) WriteFile(data string) {
|
|
||||||
if v.file != nil {
|
|
||||||
v.file.WriteString(data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VideoDecoder) Create() error {
|
func (v *VideoDecoder) Create() error {
|
||||||
@ -45,16 +36,6 @@ func (v *VideoDecoder) Create() error {
|
|||||||
if v.IsStart {
|
if v.IsStart {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
//if v.file == nil {
|
|
||||||
// filename := filepath.Join(utils.CWD(), "logs", fmt.Sprintf("%016p_decoder.log", v))
|
|
||||||
// file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm)
|
|
||||||
// if err == nil {
|
|
||||||
// v.file = file
|
|
||||||
// v.file.WriteString("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\r\n")
|
|
||||||
// } else {
|
|
||||||
// llog.Info("创建文件失败:%s", filename)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
ret := int(C.ez_decoder_create(&v.handle))
|
ret := int(C.ez_decoder_create(&v.handle))
|
||||||
v.IsStart = true
|
v.IsStart = true
|
||||||
return IsReturnErrorf(ret, "ez_decoder_create")
|
return IsReturnErrorf(ret, "ez_decoder_create")
|
||||||
@ -67,43 +48,29 @@ func (v *VideoDecoder) Destroy() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
v.IsStart = false
|
v.IsStart = false
|
||||||
if v.file != nil {
|
|
||||||
v.file.WriteString("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\r\n")
|
|
||||||
v.file.Close()
|
|
||||||
v.file = nil
|
|
||||||
}
|
|
||||||
slog.Info("====>>ez_decoder_destroy", "v", v)
|
slog.Info("====>>ez_decoder_destroy", "v", v)
|
||||||
ret := int(C.ez_decoder_destroy(&v.handle))
|
ret := int(C.ez_decoder_destroy(&v.handle))
|
||||||
return IsReturnErrorf(ret, "ez_decoder_destroy")
|
return IsReturnErrorf(ret, "ez_decoder_destroy")
|
||||||
}
|
}
|
||||||
func (v *VideoDecoder) PushDataEx(buf uintptr, size, codec int) (w, h int, data []byte, err error) {
|
func (v *VideoDecoder) PushDataEx(buf []byte, codec int) (w, h int, data []byte, err error) {
|
||||||
v.Lock()
|
v.Lock()
|
||||||
defer v.Unlock()
|
defer v.Unlock()
|
||||||
if !v.IsStart {
|
if !v.IsStart {
|
||||||
return 0, 0, nil, fmt.Errorf("decoder fail")
|
return 0, 0, nil, fmt.Errorf("decoder fail")
|
||||||
}
|
}
|
||||||
if v.file != nil {
|
cBytes := C.CBytes(buf)
|
||||||
v.file.WriteString(fmt.Sprintf("[start] function:PushData;buf len:%d; codec:%x\r\n", size, codec))
|
defer C.free(unsafe.Pointer(cBytes)) // 必须手动释放
|
||||||
}
|
|
||||||
info := &C.EZDecoderInfo{}
|
info := &C.EZDecoderInfo{}
|
||||||
var out_data *C.uchar
|
var out_data *C.uchar
|
||||||
//llog.Info("=======================>>>>>>:%v:%d", buf, size)
|
ret := int(C.ez_decoder_push_data(v.handle, (*C.uchar)(cBytes), C.int(len(buf)), C.int(codec), &out_data, info))
|
||||||
ret := int(C.ez_decoder_push_data(v.handle, (*C.uchar)(unsafe.Pointer(buf)), C.int(size), C.int(codec), &out_data, info))
|
|
||||||
//var out_data uintptr
|
|
||||||
//ret := int(C.ez_decoder_push_data(v.handle, (*C.char)(unsafe.Pointer(buf)), C.int(size), C.int(codec), (**C.char)(unsafe.Pointer(&out_data)), info))
|
|
||||||
if v.file != nil {
|
|
||||||
v.file.WriteString(fmt.Sprintf("[end] function:PushData;buf len:%d; codec:%x; ret:%d\r\n", size, codec, ret))
|
|
||||||
}
|
|
||||||
//return 0, 0, nil, fmt.Errorf("test") // 252
|
//return 0, 0, nil, fmt.Errorf("test") // 252
|
||||||
if ret == 0 {
|
if ret == 0 {
|
||||||
data_size := int(info.data_size)
|
data_size := int(info.data_size)
|
||||||
_w := int(info.width)
|
_w := int(info.width)
|
||||||
_h := int(info.height)
|
_h := int(info.height)
|
||||||
//llog.Info("=======================>>>>>>789:%v:%p:%d", out_data, v, data_size)
|
|
||||||
yuv := C.GoBytes(unsafe.Pointer(out_data), info.data_size)
|
yuv := C.GoBytes(unsafe.Pointer(out_data), info.data_size)
|
||||||
_data := make([]byte, data_size)
|
_data := make([]byte, data_size)
|
||||||
copy(_data, yuv)
|
copy(_data, yuv)
|
||||||
//llog.Info("=======================>>>>>>22222")
|
|
||||||
return _w, _h, _data, nil
|
return _w, _h, _data, nil
|
||||||
|
|
||||||
//_data := make([]byte, data_size)
|
//_data := make([]byte, data_size)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type VqdTaskMap struct {
|
|||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读出相应Key的子Map
|
// 读出相应Key的Map
|
||||||
func (m *VqdTaskMap) LoadTaskMap(key string) (value *VQDHandle, ok bool) {
|
func (m *VqdTaskMap) LoadTaskMap(key string) (value *VQDHandle, ok bool) {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
@ -17,16 +17,25 @@ func (m *VqdTaskMap) LoadTaskMap(key string) (value *VQDHandle, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除相应Key的子Map
|
// 删除相应Key的Map
|
||||||
func (m *VqdTaskMap) DeleteTaskMap(key string) {
|
func (m *VqdTaskMap) DeleteTaskMap(key string) {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
delete(m.M, key)
|
delete(m.M, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加或修改相应Key的子Map
|
// 增加或修改相应Key的Map
|
||||||
func (m *VqdTaskMap) StoreChildMap(key string, value *VQDHandle) {
|
func (m *VqdTaskMap) StoreChildMap(key string, value *VQDHandle) {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
m.M[key] = value
|
m.M[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除全部的Map
|
||||||
|
func (m *VqdTaskMap) DeleteTaskMapAll() {
|
||||||
|
m.RLock()
|
||||||
|
defer m.RUnlock()
|
||||||
|
for _, handle := range m.M {
|
||||||
|
handle.Destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,10 +2,13 @@ package vqdcms
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"easyvqd/internal/core/vqd"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const VQD_IMAGES_DIR = "snap"
|
||||||
|
|
||||||
type Abnormal struct {
|
type Abnormal struct {
|
||||||
Value float32 `json:"value"`
|
Value float32 `json:"value"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -43,11 +46,13 @@ func (r defaultValue) Value() (driver.Value, error) {
|
|||||||
|
|
||||||
type AbnormalModel struct {
|
type AbnormalModel struct {
|
||||||
ID int `gorm:"primary_key" json:"id"`
|
ID int `gorm:"primary_key" json:"id"`
|
||||||
|
TaskName string `json:"task_name"`
|
||||||
ChannelID string `json:"channel_id"`
|
ChannelID string `json:"channel_id"`
|
||||||
ChannelName string `json:"channel_name"`
|
ChannelName string `json:"channel_name"`
|
||||||
AlgoID int `json:"algo_id"`
|
PlanID int `json:"plan_id"`
|
||||||
AlgoName string `json:"algo_name"`
|
PlanName string `json:"plan_name"`
|
||||||
TaskName string `json:"task_name"`
|
TemplateID int `json:"template_id"`
|
||||||
|
TemplateName string `json:"template_name"`
|
||||||
FilePath string `json:"file_path"`
|
FilePath string `json:"file_path"`
|
||||||
IsDeep bool `json:"is_deep"`
|
IsDeep bool `json:"is_deep"`
|
||||||
Abnormals abnormal `gorm:"type:json" json:"abnormals"`
|
Abnormals abnormal `gorm:"type:json" json:"abnormals"`
|
||||||
@ -267,58 +272,95 @@ type VQDPara struct {
|
|||||||
FlowerPara VQDFlowerPara /* 花屏检测 */
|
FlowerPara VQDFlowerPara /* 花屏检测 */
|
||||||
}
|
}
|
||||||
|
|
||||||
// config cvrdo.VQDAlgoConfig
|
// config
|
||||||
func NewVQDPara() VQDPara {
|
func NewVQDPara(tem *vqd.VqdTaskTemplate) VQDPara {
|
||||||
|
var strFunc []string
|
||||||
|
if tem.VqdConfig.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_config")
|
||||||
|
}
|
||||||
|
if tem.VqdLgtDark.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_lgt_dark")
|
||||||
|
}
|
||||||
|
if tem.VqdBlue.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_blue")
|
||||||
|
}
|
||||||
|
if tem.VqdClarity.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_clarity")
|
||||||
|
}
|
||||||
|
if tem.VqdShark.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_shark")
|
||||||
|
}
|
||||||
|
if tem.VqdFreeze.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_freeze")
|
||||||
|
}
|
||||||
|
if tem.VqdColor.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_color")
|
||||||
|
}
|
||||||
|
if tem.VqdOcclusion.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_occlusion")
|
||||||
|
}
|
||||||
|
if tem.VqdNoise.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_noise")
|
||||||
|
}
|
||||||
|
if tem.VqdContrast.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_contrast")
|
||||||
|
}
|
||||||
|
if tem.VqdMosaic.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_mosaic")
|
||||||
|
}
|
||||||
|
if tem.VqdFlower.Enable {
|
||||||
|
strFunc = append(strFunc, "vqd_flower")
|
||||||
|
}
|
||||||
|
EnableFunc := GetAlgoEnable(strFunc)
|
||||||
return VQDPara{
|
return VQDPara{
|
||||||
VecFrmNum: 2,
|
VecFrmNum: int(tem.VqdConfig.FrmNum),
|
||||||
UseDeepLearning: true,
|
UseDeepLearning: tem.VqdConfig.IsDeepLearn,
|
||||||
EnableFunc: GetAlgoEnable([]string{"vqd_config", "vqd_lgt_dark", "vqd_blue", "vqd_clarity", "vqd_shark", "vqd_freeze",
|
EnableFunc: EnableFunc,
|
||||||
"vqd_color", "vqd_occlusion", "vqd_noise", "vqd_contrast", "vqd_mosaic", "vqd_flower"}),
|
|
||||||
ColorPara: VQDColorPara{
|
ColorPara: VQDColorPara{
|
||||||
ColorThr: 0.3,
|
ColorThr: tem.VqdColor.ColorThr,
|
||||||
ColorAbnNumRatio: 0.6,
|
ColorAbnNumRatio: tem.VqdColor.ColorAbnNumRatio,
|
||||||
},
|
},
|
||||||
LgtDarkPara: VQDLgtDarkPara{
|
LgtDarkPara: VQDLgtDarkPara{
|
||||||
LightThr: 0.3,
|
LightThr: tem.VqdLgtDark.LgtThr,
|
||||||
DarkThr: 0.4,
|
DarkThr: tem.VqdLgtDark.DarkThr,
|
||||||
LgtDarkAbnNumRatio: 0.6,
|
LgtDarkAbnNumRatio: tem.VqdLgtDark.LgtDarkAbnNumRatio,
|
||||||
},
|
},
|
||||||
ClarityPara: VQDClarityPara{
|
ClarityPara: VQDClarityPara{
|
||||||
ClarityThr: 0.5,
|
ClarityThr: tem.VqdClarity.ClarityThr,
|
||||||
ClarityAbnNumRatio: 0.6,
|
ClarityAbnNumRatio: tem.VqdClarity.ClarityAbnNumRatio,
|
||||||
},
|
},
|
||||||
NoisePara: VQDNoisePara{
|
NoisePara: VQDNoisePara{
|
||||||
NoiseThr: 0.3,
|
NoiseThr: tem.VqdNoise.NoiseThr,
|
||||||
NoiseAbnNumRatio: 0.6,
|
NoiseAbnNumRatio: tem.VqdNoise.NoiseAbnNumRatio,
|
||||||
},
|
},
|
||||||
ContrastPara: VQDContrastPara{
|
ContrastPara: VQDContrastPara{
|
||||||
CtraLowThr: 0.3,
|
CtraLowThr: tem.VqdContrast.CtraLowThr,
|
||||||
CtraHighThr: 0.8,
|
CtraHighThr: tem.VqdContrast.CtraHighThr,
|
||||||
CtraAbnNumRatio: 0.6,
|
CtraAbnNumRatio: tem.VqdContrast.CtraAbnNumRatio,
|
||||||
},
|
},
|
||||||
OcclusionPara: VQDOcclusionPara{
|
OcclusionPara: VQDOcclusionPara{
|
||||||
OcclusionThr: 0.1,
|
OcclusionThr: tem.VqdOcclusion.OcclusionThr,
|
||||||
OcclusionAbnNumRatio: 0.6,
|
OcclusionAbnNumRatio: tem.VqdOcclusion.OcclusionAbnNumRatio,
|
||||||
},
|
},
|
||||||
BluePara: VQDBluePara{
|
BluePara: VQDBluePara{
|
||||||
BlueThr: 0.3,
|
BlueThr: tem.VqdBlue.BlueThr,
|
||||||
BlueAbnNumRatio: 0.6,
|
BlueAbnNumRatio: tem.VqdBlue.BlueAbnNumRatio,
|
||||||
},
|
},
|
||||||
SharkPara: VQDSharkPara{
|
SharkPara: VQDSharkPara{
|
||||||
SharkThr: 0.2,
|
SharkThr: tem.VqdShark.SharkThr,
|
||||||
SharkAbnNumRatio: 0.2,
|
SharkAbnNumRatio: tem.VqdShark.SharkAbnNumRatio,
|
||||||
},
|
},
|
||||||
FreezePara: VQDFreezePara{
|
FreezePara: VQDFreezePara{
|
||||||
FreezeThr: 0.999,
|
FreezeThr: tem.VqdFreeze.FreezeThr,
|
||||||
FreezeAbnNumRatio: 0.99,
|
FreezeAbnNumRatio: tem.VqdFreeze.FreezeAbnNumRatio,
|
||||||
},
|
},
|
||||||
MosaicPara: VQDMosaicPara{
|
MosaicPara: VQDMosaicPara{
|
||||||
MosaicThr: 0.3,
|
MosaicThr: tem.VqdMosaic.MosaicThr,
|
||||||
MosaicAbnNumRatio: 0.6,
|
MosaicAbnNumRatio: tem.VqdMosaic.MosaicAbnNumRatio,
|
||||||
},
|
},
|
||||||
FlowerPara: VQDFlowerPara{
|
FlowerPara: VQDFlowerPara{
|
||||||
FlowerThr: 0.3,
|
FlowerThr: tem.VqdFlower.FlowerThr,
|
||||||
FlowerAbnNumRatio: 0.6,
|
FlowerAbnNumRatio: tem.VqdFlower.FlowerAbnNumRatio,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
package vqdcms
|
package vqdcms
|
||||||
|
|
||||||
|
type VqdTaskStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TaskStatusStopped VqdTaskStatus = iota
|
||||||
|
TaskStatusRunning
|
||||||
|
TaskStatusFailed
|
||||||
|
)
|
||||||
const NXU_VQD_DISABLE_ALL = 0x00000000 /* 所有功能关闭 */
|
const NXU_VQD_DISABLE_ALL = 0x00000000 /* 所有功能关闭 */
|
||||||
const NXU_VQD_ENABLE_COLOR = 0x00000001 /* 偏色检测 */
|
const NXU_VQD_ENABLE_COLOR = 0x00000001 /* 偏色检测 */
|
||||||
const NXU_VQD_ENABLE_LGTDARK = 0x00000002 /* 过亮过暗检测 */
|
const NXU_VQD_ENABLE_LGTDARK = 0x00000002 /* 过亮过暗检测 */
|
||||||
|
|||||||
@ -7,9 +7,10 @@ package vqdcms
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"easyvqd/internal/core/host"
|
||||||
"easyvqd/pkg/decoder"
|
"easyvqd/pkg/decoder"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shirou/gopsutil/v4/mem"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -29,20 +30,33 @@ type VideoInfoVQD struct {
|
|||||||
Params VQDPara
|
Params VQDPara
|
||||||
IsCreateSuccess bool
|
IsCreateSuccess bool
|
||||||
}
|
}
|
||||||
|
type VQDHandleInfo struct {
|
||||||
|
TaskID int
|
||||||
|
Plans string
|
||||||
|
TaskName string
|
||||||
|
ChannelID string
|
||||||
|
ChannelName string
|
||||||
|
PlanID int
|
||||||
|
PlanName string
|
||||||
|
TemplateID int
|
||||||
|
TemplateName string
|
||||||
|
}
|
||||||
type VQDHandle struct {
|
type VQDHandle struct {
|
||||||
running uint32
|
running uint32
|
||||||
TaskID int // 标识ID
|
ID int // 标识ID
|
||||||
ChnID string // 通道ID
|
info VQDHandleInfo
|
||||||
Plans string // 任务计划
|
plansLock sync.RWMutex
|
||||||
data chan ChanData
|
playTicker *Scheduler
|
||||||
dataLock sync.RWMutex
|
ErrorMsg string
|
||||||
cb VQDResultCB
|
data chan ChanData
|
||||||
handle *VideoInfoVQD
|
dataLock sync.RWMutex
|
||||||
name string // 算法名称
|
cb VQDResultCB
|
||||||
file *os.File
|
handle *VideoInfoVQD
|
||||||
decoder *decoder.VideoDecoder
|
name string // 算法名称
|
||||||
fileLock sync.RWMutex
|
decoder *decoder.VideoDecoder
|
||||||
|
fileLock sync.RWMutex
|
||||||
|
hostCore *host.Core
|
||||||
|
Status VqdTaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type VQDResultCB func(AbnormalModel)
|
type VQDResultCB func(AbnormalModel)
|
||||||
@ -54,53 +68,91 @@ type ChanData struct {
|
|||||||
now time.Time
|
now time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsCurTimeInRecordPlan(recordPlanNew string, now time.Time) bool {
|
// IsCurTimeInRecordPlan 根据一周每天每小时的开关状态判断当前时间是否为开启状态
|
||||||
|
func IsCurTimeInRecordPlan(schedule string, now time.Time) bool {
|
||||||
|
if len(schedule) != 7*24 {
|
||||||
|
slog.Error("schedule length is not 7*24", "schedule", schedule)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
dayOfWeek := int(now.Weekday()+6) % 7 // 调整为0-6,对应周一至周日
|
||||||
|
hourOfDay := now.Hour()
|
||||||
|
|
||||||
|
// 计算位置索引
|
||||||
|
index := (dayOfWeek * 24) + hourOfDay
|
||||||
|
|
||||||
|
// 检查索引位置的字符是否为'1'
|
||||||
|
if index >= 0 && index < len(schedule) && schedule[index] == '1' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVQDHandle(cb VQDResultCB, taskId int, chnId string) *VQDHandle {
|
func NewVQDHandle(cb VQDResultCB, hostCore *host.Core, info VQDHandleInfo) *VQDHandle {
|
||||||
v := &VQDHandle{
|
v := &VQDHandle{
|
||||||
running: 0,
|
running: 0,
|
||||||
decoder: &decoder.VideoDecoder{},
|
decoder: &decoder.VideoDecoder{},
|
||||||
ChnID: chnId,
|
info: info,
|
||||||
TaskID: taskId,
|
ID: info.TaskID,
|
||||||
data: make(chan ChanData, MAX_STREAM_CHAN_NUM),
|
data: make(chan ChanData, MAX_STREAM_CHAN_NUM),
|
||||||
cb: cb,
|
cb: cb,
|
||||||
handle: &VideoInfoVQD{},
|
handle: &VideoInfoVQD{},
|
||||||
|
playTicker: NewScheduler(),
|
||||||
|
hostCore: hostCore,
|
||||||
|
Status: TaskStatusStopped,
|
||||||
}
|
}
|
||||||
err := v.decoder.Create()
|
err := v.decoder.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("decoder Create ", "taskId", chnId, "err", err)
|
slog.Error("decoder Create ", "taskId", info.ChannelID, "err", err)
|
||||||
}
|
}
|
||||||
|
v.StartPlay()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VQDHandle) SetVQDConfig(params VQDPara) error {
|
func (v *VQDHandle) SetVQDConfig(params VQDPara, info VQDHandleInfo) error {
|
||||||
|
v.plansLock.Lock()
|
||||||
|
v.info = info
|
||||||
|
v.plansLock.Unlock()
|
||||||
return v.handle.Config(params, params.EnableFunc, 10)
|
return v.handle.Config(params, params.EnableFunc, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VQDHandle) GetHandle() *VideoInfoVQD {
|
func (v *VQDHandle) GetHandle() *VideoInfoVQD {
|
||||||
return v.handle
|
return v.handle
|
||||||
}
|
}
|
||||||
func (v *VQDHandle) Create(params VQDPara) *VQDHandle {
|
func (v *VQDHandle) StartPlay() {
|
||||||
|
v.Play()
|
||||||
|
v.playTicker.Start(25*time.Second, func() {
|
||||||
|
v.Play()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (v *VQDHandle) Play() {
|
||||||
|
if IsCurTimeInRecordPlan(v.info.Plans, time.Now()) {
|
||||||
|
//slog.Info("vqd cms play", "taskId", v.TaskID, "chnId", v.ChnID)
|
||||||
|
_, errs := v.hostCore.Play(context.TODO(), &host.PlayInput{
|
||||||
|
ChannelID: v.info.ChannelID,
|
||||||
|
ActiveSecond: 0,
|
||||||
|
})
|
||||||
|
if errs != nil {
|
||||||
|
slog.Debug("vqd cms play", "taskId", v.info.TaskID, "chnId", v.info.ChannelID, "err", errs)
|
||||||
|
v.ErrorMsg = errs.Error()
|
||||||
|
v.Status = TaskStatusFailed
|
||||||
|
} else {
|
||||||
|
v.ErrorMsg = ""
|
||||||
|
v.Status = TaskStatusRunning
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.Status = TaskStatusStopped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (v *VQDHandle) Create(params VQDPara, plan string) *VQDHandle {
|
||||||
|
v.plansLock.Lock()
|
||||||
|
v.info.Plans = plan
|
||||||
|
v.plansLock.Unlock()
|
||||||
if atomic.LoadUint32(&v.running) == 1 {
|
if atomic.LoadUint32(&v.running) == 1 {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
//if v.file == nil {
|
|
||||||
// filename := filepath.Join(utils.CWD(), "logs", fmt.Sprintf("%016p_vqdhandle.log", v))
|
|
||||||
// file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm)
|
|
||||||
// if err == nil {
|
|
||||||
// v.fileLock.Lock()
|
|
||||||
// v.file = file
|
|
||||||
// v.file.WriteString("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\r\n")
|
|
||||||
// v.fileLock.Unlock()
|
|
||||||
// } else {
|
|
||||||
// llog.Info("创建文件失败:%s", filename)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
err := v.handle.Create(params, params.EnableFunc, 10)
|
err := v.handle.Create(params, params.EnableFunc, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//llog.Info("vqd create fail:%s", err.Error())
|
slog.Error("vqd create", "taskId", v.info.TaskID, "chnId", v.info.ChannelID, "fail", err)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
atomic.StoreUint32(&v.running, 1)
|
atomic.StoreUint32(&v.running, 1)
|
||||||
@ -109,16 +161,17 @@ func (v *VQDHandle) Create(params VQDPara) *VQDHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *VQDHandle) Destroy() {
|
func (v *VQDHandle) Destroy() {
|
||||||
if v.file != nil {
|
|
||||||
v.fileLock.Lock()
|
|
||||||
v.file.WriteString("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\r\n")
|
|
||||||
v.file.Close()
|
|
||||||
v.file = nil
|
|
||||||
v.fileLock.Unlock()
|
|
||||||
}
|
|
||||||
if v.data != nil {
|
if v.data != nil {
|
||||||
close(v.data)
|
close(v.data)
|
||||||
}
|
}
|
||||||
|
if v.decoder != nil {
|
||||||
|
err := v.decoder.Destroy()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("vqd decoder destroy", "taskId", v.info.TaskID, "chnId", v.info.ChannelID, "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.decoder = nil
|
||||||
|
v.playTicker.Stop()
|
||||||
v.data = nil
|
v.data = nil
|
||||||
if atomic.LoadUint32(&v.running) == 1 {
|
if atomic.LoadUint32(&v.running) == 1 {
|
||||||
atomic.StoreUint32(&v.running, 0)
|
atomic.StoreUint32(&v.running, 0)
|
||||||
@ -133,10 +186,10 @@ func (v *VQDHandle) RunFrame() {
|
|||||||
print(fmt.Sprintf("%s\n", string(debug.Stack())))
|
print(fmt.Sprintf("%s\n", string(debug.Stack())))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
cvqdImgsDir := filepath.Join(CWD(), "vqd_images", fmt.Sprintf("%d", v.TaskID))
|
cvqdImgsDir := filepath.Join(CWD(), VQD_IMAGES_DIR, fmt.Sprintf("%d", v.info.TaskID))
|
||||||
cvqdImgsDir = filepath.ToSlash(cvqdImgsDir)
|
cvqdImgsDir = filepath.ToSlash(cvqdImgsDir)
|
||||||
if err := os.MkdirAll(cvqdImgsDir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(cvqdImgsDir, os.ModePerm); err != nil {
|
||||||
//llog.Info("%s:%s", cvqdImgsDir, err.Error())
|
slog.Error("vqd create img dir", "taskId", v.info.TaskID, "chnId", v.info.ChannelID, "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hyper := 0
|
hyper := 0
|
||||||
@ -149,7 +202,7 @@ func (v *VQDHandle) RunFrame() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(v.data) >= (MAX_STREAM_CHAN_NUM - 6) {
|
if len(v.data) >= (MAX_STREAM_CHAN_NUM - 6) {
|
||||||
//llog.Info("vqd channel num >= %d", MAX_STREAM_CHAN_NUM)
|
slog.Error("vqd channel num", "taskId", v.info.TaskID, "chnId", v.info.ChannelID, ">= ", MAX_STREAM_CHAN_NUM)
|
||||||
hyper = MAX_STREAM_CHAN_NUM / 10
|
hyper = MAX_STREAM_CHAN_NUM / 10
|
||||||
}
|
}
|
||||||
if hyper > 0 {
|
if hyper > 0 {
|
||||||
@ -157,16 +210,11 @@ func (v *VQDHandle) RunFrame() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
cdata = data
|
cdata = data
|
||||||
//if !IsCurTimeInRecordPlan(v.analysisTime, cdata.now) {
|
if !IsCurTimeInRecordPlan(v.info.Plans, cdata.now) {
|
||||||
// continue
|
continue
|
||||||
//}
|
|
||||||
if v.file != nil {
|
|
||||||
v.fileLock.Lock()
|
|
||||||
v.file.WriteString(fmt.Sprintf("vqd START data[%d] w[%d] h[%d]\r\n", len(cdata.data), cdata.w, cdata.h))
|
|
||||||
v.fileLock.Unlock()
|
|
||||||
}
|
}
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
fpath := filepath.Join(cvqdImgsDir, fmt.Sprintf("%d_%s_%d.jpg", v.TaskID, v.ChnID, now))
|
fpath := filepath.Join(cvqdImgsDir, fmt.Sprintf("%s_%d_%d_%d.jpg", v.info.ChannelID, v.info.TemplateID, v.info.PlanID, now))
|
||||||
fpath = filepath.ToSlash(fpath)
|
fpath = filepath.ToSlash(fpath)
|
||||||
result := VQDResult{}
|
result := VQDResult{}
|
||||||
ret := v.handle.Frame(cdata.data, cdata.w, cdata.h, index, fpath, &result)
|
ret := v.handle.Frame(cdata.data, cdata.w, cdata.h, index, fpath, &result)
|
||||||
@ -174,8 +222,15 @@ func (v *VQDHandle) RunFrame() {
|
|||||||
index = 0
|
index = 0
|
||||||
if value, b := v.parseVQD(result); b {
|
if value, b := v.parseVQD(result); b {
|
||||||
value.FilePath = strings.TrimPrefix(filepath.ToSlash(fpath), filepath.ToSlash(CWD()))
|
value.FilePath = strings.TrimPrefix(filepath.ToSlash(fpath), filepath.ToSlash(CWD()))
|
||||||
value.ChannelID = v.ChnID
|
value.TaskName = v.info.TaskName
|
||||||
value.AlgoName = v.name
|
value.ID = v.info.TaskID
|
||||||
|
value.ChannelID = v.info.ChannelID
|
||||||
|
value.ChannelName = v.info.ChannelName
|
||||||
|
value.PlanID = v.info.PlanID
|
||||||
|
value.PlanName = v.info.PlanName
|
||||||
|
value.TemplateID = v.info.TemplateID
|
||||||
|
value.TemplateName = v.info.TemplateName
|
||||||
|
|
||||||
if v.cb != nil {
|
if v.cb != nil {
|
||||||
v.cb(value)
|
v.cb(value)
|
||||||
} else {
|
} else {
|
||||||
@ -184,18 +239,6 @@ func (v *VQDHandle) RunFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.file != nil {
|
|
||||||
me, err := mem.VirtualMemory()
|
|
||||||
if err != nil {
|
|
||||||
v.fileLock.Lock()
|
|
||||||
v.file.WriteString(fmt.Sprintf("vqd END ret[%d] mem is nil\r\n", ret))
|
|
||||||
v.fileLock.Unlock()
|
|
||||||
} else {
|
|
||||||
v.fileLock.Lock()
|
|
||||||
v.file.WriteString(fmt.Sprintf("vqd END ret[%d] mem[%.2f%s]\r\n", ret, me.UsedPercent, "%"))
|
|
||||||
v.fileLock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//C.free(fp)
|
//C.free(fp)
|
||||||
//C.free(yuvBuf)
|
//C.free(yuvBuf)
|
||||||
index++
|
index++
|
||||||
@ -368,14 +411,10 @@ func (v *VQDHandle) parseVQD(result VQDResult) (AbnormalModel, bool) {
|
|||||||
return abnormals, isabnormal
|
return abnormals, isabnormal
|
||||||
}
|
}
|
||||||
func (v *VQDHandle) SendData(buf []byte, _codec int) {
|
func (v *VQDHandle) SendData(buf []byte, _codec int) {
|
||||||
dataP := GetIFramePointer(buf)
|
|
||||||
if dataP == nil || !dataP.IsValid {
|
w, h, data, err := v.decoder.PushDataEx(buf, _codec)
|
||||||
slog.Error("I帧转指针失败: ", "TaskID", v.TaskID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w, h, data, err := v.decoder.PushDataEx(uintptr(dataP.Pointer), dataP.Length, _codec)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("I帧转YUV失败: ", "TaskID", v.TaskID, "err", err)
|
slog.Error("I帧转YUV失败: ", "TaskID", v.info.TaskID, "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(data) > 0 && v.data != nil {
|
if len(data) > 0 && v.data != nil {
|
||||||
@ -388,9 +427,6 @@ func (v *VQDHandle) SendData(buf []byte, _codec int) {
|
|||||||
h: h,
|
h: h,
|
||||||
now: now,
|
now: now,
|
||||||
}
|
}
|
||||||
//v.dataLock.Lock()
|
|
||||||
//v.data = append(v.data, d)
|
|
||||||
//v.dataLock.Unlock()
|
|
||||||
v.data <- d
|
v.data <- d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
pkg/vqdcms/worker.go
Normal file
56
pkg/vqdcms/worker.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package vqdcms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Worker struct {
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWorker() *Worker {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
return &Worker{
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) Stop() {
|
||||||
|
w.cancel() // 显式调用cancel停止worker
|
||||||
|
}
|
||||||
|
|
||||||
|
type Scheduler struct {
|
||||||
|
stopChan chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScheduler() *Scheduler {
|
||||||
|
return &Scheduler{
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scheduler) Start(interval time.Duration, task func()) {
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
task()
|
||||||
|
case <-s.stopChan:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scheduler) Stop() {
|
||||||
|
if s.stopChan != nil {
|
||||||
|
close(s.stopChan)
|
||||||
|
s.stopChan = nil // 防止重复关闭
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,6 +36,7 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
|
|||||||
channel_id: task.channel_id,
|
channel_id: task.channel_id,
|
||||||
channel_name: task.channel_name,
|
channel_name: task.channel_name,
|
||||||
task_template_id: task.task_template_id,
|
task_template_id: task.task_template_id,
|
||||||
|
time_template_id: task.time_template_id,
|
||||||
task_template_name: task.task_template_name,
|
task_template_name: task.task_template_name,
|
||||||
enable: task.enable,
|
enable: task.enable,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -114,7 +114,7 @@ const AddVqdTaskTemplate = forwardRef<AddVqdTaskTemplateRef, AddVqdTaskTemplateP
|
|||||||
const { mutate: createMutate, isPending: creating } = useMutation({
|
const { mutate: createMutate, isPending: creating } = useMutation({
|
||||||
mutationFn: CreateVqdTaskTemplate,
|
mutationFn: CreateVqdTaskTemplate,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
message.success("创建任务成功");
|
message.success("创建成功");
|
||||||
handleClose();
|
handleClose();
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
},
|
},
|
||||||
@ -124,7 +124,7 @@ const AddVqdTaskTemplate = forwardRef<AddVqdTaskTemplateRef, AddVqdTaskTemplateP
|
|||||||
const { mutate: updateMutate, isPending: updating } = useMutation({
|
const { mutate: updateMutate, isPending: updating } = useMutation({
|
||||||
mutationFn: UpdateVqdTaskTemplate,
|
mutationFn: UpdateVqdTaskTemplate,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
message.success("更新任务成功");
|
message.success("更新成功");
|
||||||
handleClose();
|
handleClose();
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -167,7 +167,7 @@ const AddVqdTimeTemplate = forwardRef<AddVqdTimeTemplateRef, AddVqdTimeTemplateP
|
|||||||
const { mutate: createMutate, isPending: creating } = useMutation({
|
const { mutate: createMutate, isPending: creating } = useMutation({
|
||||||
mutationFn: CreateVqdTimeTemplate,
|
mutationFn: CreateVqdTimeTemplate,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
message.success("创建任务成功");
|
message.success("创建成功");
|
||||||
handleClose();
|
handleClose();
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
},
|
},
|
||||||
@ -177,7 +177,7 @@ const AddVqdTimeTemplate = forwardRef<AddVqdTimeTemplateRef, AddVqdTimeTemplateP
|
|||||||
const { mutate: updateMutate, isPending: updating } = useMutation({
|
const { mutate: updateMutate, isPending: updating } = useMutation({
|
||||||
mutationFn: UpdateVqdTimeTemplate,
|
mutationFn: UpdateVqdTimeTemplate,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
message.success("更新任务成功");
|
message.success("更新成功");
|
||||||
handleClose();
|
handleClose();
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState, useMemo } from "react";
|
import { useRef, useState, useMemo } from "react";
|
||||||
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Select, Row, Col, Empty, Pagination, Tag } from "antd";
|
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Select, Row, Col, Empty, Pagination, Tag, Popover } from "antd";
|
||||||
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
|
import { EditOutlined, DeleteOutlined, InfoCircleOutlined } from "@ant-design/icons";
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import { GetVqdAlarm, DeleteVqdAlarm, DeleteVqdAlarmAll } from "../api/vqdalarm";
|
import { GetVqdAlarm, DeleteVqdAlarm, DeleteVqdAlarmAll } from "../api/vqdalarm";
|
||||||
import type { VqdAlarmItem } from "../types/vqdalarm";
|
import type { VqdAlarmItem } from "../types/vqdalarm";
|
||||||
@ -233,7 +233,7 @@ export default function VqdAlarmPage() {
|
|||||||
loading={moonLoading}
|
loading={moonLoading}
|
||||||
/> */}
|
/> */}
|
||||||
<div className="w-[150px] ml-[20px]">
|
<div className="w-[150px] ml-[20px]">
|
||||||
<Select
|
{/* <Select
|
||||||
defaultValue={0}
|
defaultValue={0}
|
||||||
className="w-[100%] mr-2"
|
className="w-[100%] mr-2"
|
||||||
placeholder="选择类型"
|
placeholder="选择类型"
|
||||||
@ -255,7 +255,7 @@ export default function VqdAlarmPage() {
|
|||||||
</span>
|
</span>
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
/>
|
/> */}
|
||||||
<Filter
|
<Filter
|
||||||
|
|
||||||
searchLoading={isLoading}
|
searchLoading={isLoading}
|
||||||
@ -274,24 +274,43 @@ export default function VqdAlarmPage() {
|
|||||||
<AlarmSnap filePath={item.file_path} />
|
<AlarmSnap filePath={item.file_path} />
|
||||||
<div className="pl-3 pr-2 pb-1">
|
<div className="pl-3 pr-2 pb-1">
|
||||||
|
|
||||||
<Flex justify="space-between" align="center">
|
<Flex align="center" wrap gap="small">
|
||||||
<Tag bordered={false} color="#87d068" className="m-0 mt-2">{item.alarm_name}</Tag>
|
{
|
||||||
<Space className="pr-2"> 通道:{item.channel_name||"2222"}</Space>
|
item.abnormals.map((item) => {
|
||||||
|
return (<>
|
||||||
|
<Tag bordered={false} color="#87d068" className="m-0 mt-2">{item.name}</Tag>
|
||||||
|
</>)
|
||||||
|
})
|
||||||
|
}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<div>
|
||||||
|
<Space className="pt-2"> 任务名称:{item.task_name}</Space>
|
||||||
|
</div>
|
||||||
|
{/* <Space className="pt-2"> 通道:{item.channel_name || item.channel_id}</Space> */}
|
||||||
<Flex justify="space-between" align="center">
|
<Flex justify="space-between" align="center">
|
||||||
<p className="m-0"> {item.created_at}</p>
|
<p className="m-0"> {item.created_at}</p>
|
||||||
<Tooltip title="删除">
|
<div>
|
||||||
<Popconfirm
|
<Popover content={(<>
|
||||||
title="删除告警"
|
<div>通道: {item.channel_name || item.channel_id}</div>
|
||||||
description="确定要删除此告警吗?"
|
<div>诊断计划: {item.plan_name}</div>
|
||||||
onConfirm={() => {
|
<div className="pb-2">诊断模板: {item.task_template_name} </div>
|
||||||
deleteMutation(item.id)
|
</>)} title="详情">
|
||||||
}}
|
<Button type="text" icon={<InfoCircleOutlined />}></Button>
|
||||||
>
|
</Popover>
|
||||||
{/* loading={isDelLoading} */}
|
<Tooltip title="删除">
|
||||||
<Button type="text" danger icon={<DeleteOutlined />}></Button>
|
<Popconfirm
|
||||||
</Popconfirm>
|
title="删除告警"
|
||||||
</Tooltip>
|
description="确定要删除此告警吗?"
|
||||||
|
onConfirm={() => {
|
||||||
|
deleteMutation(item.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* loading={isDelLoading} */}
|
||||||
|
<Button type="text" danger icon={<DeleteOutlined />}></Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useRef, useState, useMemo } from "react";
|
import { useRef, useState, useMemo } from "react";
|
||||||
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Switch } from "antd";
|
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Switch,Popover,Tag } from "antd";
|
||||||
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
|
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import { GetVqdTask, DeleteVqdTask, UpdateVqdTask } from "../api/vqdtask";
|
import { GetVqdTask, DeleteVqdTask, UpdateVqdTask } from "../api/vqdtask";
|
||||||
@ -160,6 +160,26 @@ export default function VqdTaskPage() {
|
|||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "拉流状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) => (
|
||||||
|
<Space>
|
||||||
|
{text == 0 && <Tag color="#ccc">未诊断</Tag>}
|
||||||
|
{text == 1 && <Tag color="#87d068">诊断中</Tag>}
|
||||||
|
{text == 2 &&
|
||||||
|
<Popover content={
|
||||||
|
<>
|
||||||
|
{record.error_msg}
|
||||||
|
</>
|
||||||
|
} title="异常详情">
|
||||||
|
<Tag color="#f50">诊断异常</Tag>
|
||||||
|
</Popover>
|
||||||
|
}
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "创建日期",
|
title: "创建日期",
|
||||||
dataIndex: "created_at",
|
dataIndex: "created_at",
|
||||||
|
|||||||
@ -356,7 +356,9 @@
|
|||||||
.overflow-y-auto {
|
.overflow-y-auto {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
.overflow-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.truncate {
|
.truncate {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@ -474,6 +476,10 @@
|
|||||||
padding-bottom: 0.75rem;
|
padding-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pt-2 {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pl-2 {
|
.pl-2 {
|
||||||
padding-left: 0.5rem;
|
padding-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,22 +16,34 @@ export type VqdAlarmRes = {
|
|||||||
*/
|
*/
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
export type Abnormals = {
|
||||||
|
value: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
export type DefaultValues = {
|
||||||
|
thr1: number;
|
||||||
|
name1: string;
|
||||||
|
thr2: number;
|
||||||
|
name2: string;
|
||||||
|
ratio: number;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 项
|
* 项
|
||||||
*/
|
*/
|
||||||
export type VqdAlarmItem = {
|
export type VqdAlarmItem = {
|
||||||
id: number;
|
id: number;
|
||||||
alarm_name: string;
|
is_deep: boolean;
|
||||||
alarm_value: string;
|
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
channel_name: string;
|
channel_name: string;
|
||||||
|
plan_id: number;
|
||||||
|
plan_name: string;
|
||||||
task_template_id: number;
|
task_template_id: number;
|
||||||
task_template_name: string;
|
task_template_name: string;
|
||||||
task_id: number;
|
task_id: number;
|
||||||
task_name: string;
|
task_name: string;
|
||||||
file_path: string;
|
file_path: string;
|
||||||
|
abnormals: Abnormals[];
|
||||||
|
default_values: DefaultValues[];
|
||||||
created_at?: string;
|
created_at?: string;
|
||||||
updated_at?: string;
|
updated_at?: string;
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,8 @@ export type VqdTaskItem = {
|
|||||||
name: string;
|
name: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
channel_name: string;
|
channel_name: string;
|
||||||
|
error_msg: string;
|
||||||
|
status: number;
|
||||||
task_template_id: number;
|
task_template_id: number;
|
||||||
time_template_id: number;
|
time_template_id: number;
|
||||||
task_template_name: string;
|
task_template_name: string;
|
||||||
@ -103,6 +105,8 @@ export type VqdTaskDetailRes = {
|
|||||||
name: string;
|
name: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
channel_name: string;
|
channel_name: string;
|
||||||
|
error_msg: string;
|
||||||
|
status: number;
|
||||||
task_template_id: number;
|
task_template_id: number;
|
||||||
time_template_id: number;
|
time_template_id: number;
|
||||||
task_template_name: string;
|
task_template_name: string;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
// 可选:重写路径
|
// 可选:重写路径
|
||||||
// rewrite: (path) => path.replace(/^\/api/, '')
|
// rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
},
|
},
|
||||||
'/uploads': {
|
'/snap': {
|
||||||
target: 'http://127.0.0.1:8089',
|
target: 'http://127.0.0.1:8089',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user