Files
monibuca/plugin/mp4/exception.go

171 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package plugin_mp4
import (
"os"
"path/filepath"
"strings"
"time"
"github.com/shirou/gopsutil/v4/disk"
"gorm.io/gorm"
"m7s.live/v5"
"m7s.live/v5/pkg/task"
)
// mysql数据库里Exception 定义异常结构体
type Exception struct {
CreateTime string `json:"createTime" gorm:"type:varchar(50)"`
AlarmType string `json:"alarmType" gorm:"type:varchar(50)"`
AlarmDesc string `json:"alarmDesc" gorm:"type:varchar(50)"`
ServerIP string `json:"serverIP" gorm:"type:varchar(50)"`
StreamPath string `json:"streamPath" gorm:"type:varchar(50)"`
}
// // 向第三方发送异常报警
// func (p *MP4Plugin) SendToThirdPartyAPI(exception *Exception) {
// exception.CreateTime = time.Now().Format("2006-01-02 15:04:05")
// exception.ServerIP = p.GetCommonConf().PublicIP
// data, err := json.Marshal(exception)
// if err != nil {
// p.Error("SendToThirdPartyAPI", " marshalling exception error", err.Error())
// return
// }
// err = p.DB.Create(&exception).Error
// if err != nil {
// p.Error("SendToThirdPartyAPI", "insert into db error", err.Error())
// return
// }
// resp, err := http.Post(p.ExceptionPostUrl, "application/json", bytes.NewBuffer(data))
// if err != nil {
// p.Error("SendToThirdPartyAPI", "Error sending exception to third party API error", err.Error())
// return
// }
// defer resp.Body.Close()
// if resp.StatusCode != http.StatusOK {
// p.Error("SendToThirdPartyAPI", "Failed to send exception, status code:", resp.StatusCode)
// } else {
// p.Info("SendToThirdPartyAPI", "Exception sent successfully!")
// }
// }
// // 磁盘超上限报警
// func (p *DeleteRecordTask) getDisckException(streamPath string) bool {
// if p.getDiskOutOfSpace(p.DiskMaxPercent) {
// exceptionChannel <- &Exception{AlarmType: "disk alarm", AlarmDesc: "disk is full", StreamPath: streamPath}
// return true
// }
// return false
// }
// 判断磁盘使用量是否中超限
func (p *DeleteRecordTask) getDiskOutOfSpace(filePath string) bool {
exePath := filepath.Dir(filePath)
d, err := disk.Usage(exePath)
if err != nil || d == nil {
p.Error("getDiskOutOfSpace", "error", err)
return false
}
p.plugin.Debug("getDiskOutOfSpace", "current path", exePath, "disk UsedPercent", d.UsedPercent, "total disk space", d.Total,
"disk free", d.Free, "disk usage", d.Used, "AutoOverWriteDiskPercent", p.AutoOverWriteDiskPercent, "DiskMaxPercent", p.DiskMaxPercent)
return d.UsedPercent >= p.AutoOverWriteDiskPercent
}
func (p *DeleteRecordTask) deleteOldestFile() {
//当当前磁盘使用量大于AutoOverWriteDiskPercent自动覆盖磁盘使用量配置时自动删除最旧的文件
//连续录像删除最旧的文件
// 创建一个数组来存储所有的conf.FilePath
var filePaths []string
if len(p.plugin.GetCommonConf().OnPub.Record) > 0 {
for _, conf := range p.plugin.GetCommonConf().OnPub.Record {
// 处理路径,去掉最后的/$0部分只保留目录部分
dirPath := filepath.Dir(conf.FilePath)
p.Info("deleteOldestFile", "original filepath", conf.FilePath, "processed filepath", dirPath)
filePaths = append(filePaths, dirPath)
}
}
if p.plugin.EventRecordFilePath != "" {
// 同样处理EventRecordFilePath
dirPath := filepath.Dir(p.plugin.EventRecordFilePath)
filePaths = append(filePaths, dirPath)
}
for _, filePath := range filePaths {
for p.getDiskOutOfSpace(filePath) {
queryRecord := m7s.RecordStream{
EventLevel: m7s.EventLevelLow, // 查询条件event_level = 1,非重要事件
}
var eventRecords []m7s.RecordStream
// 使用不同的方法进行路径匹配避免ESCAPE语法问题
// 解决方案用MySQL能理解的简单方式匹配路径前缀
basePath := filePath
// 直接替换所有反斜杠,不需要判断是否包含
basePath = strings.Replace(basePath, "\\", "\\\\", -1)
searchPattern := basePath + "%"
p.Info("deleteOldestFile", "searching with path pattern", searchPattern)
err := p.DB.Where(&queryRecord).Where("end_time != '1970-01-01 00:00:00'").
Where("file_path LIKE ?", searchPattern).
Order("end_time ASC").Limit(1).Find(&eventRecords).Error
if err == nil {
if len(eventRecords) > 0 {
for _, record := range eventRecords {
p.Info("deleteOldestFile", "ready to delete oldestfile,ID", record.ID, "create time", record.EndTime, "filepath", record.FilePath)
err = os.Remove(record.FilePath)
if err != nil {
p.Error("deleteOldestFile", "delete file from disk error", err)
}
err = p.DB.Delete(&record).Error
if err != nil {
p.Error("deleteOldestFile", "delete record from disk error", err)
}
}
}
} else {
p.Error("deleteOldestFile", "search record from db error", err)
}
time.Sleep(time.Second * 3)
}
}
}
type DeleteRecordTask struct {
task.TickTask
DiskMaxPercent float64
AutoOverWriteDiskPercent float64
RecordFileExpireDays int
DB *gorm.DB
plugin *MP4Plugin
}
func (t *DeleteRecordTask) GetTickInterval() time.Duration {
return 1 * time.Minute
}
func (t *DeleteRecordTask) Tick(any) {
t.deleteOldestFile()
if t.RecordFileExpireDays <= 0 {
return
}
//搜索event_records表中event_level值为1的非重要数据并将其create_time与当前时间比对大于RecordFileExpireDays则进行删除数据库标记is_delete为1磁盘上删除录像文件
var eventRecords []m7s.RecordStream
expireTime := time.Now().AddDate(0, 0, -t.RecordFileExpireDays)
t.Debug("RecordFileExpireDays is set to auto delete oldestfile", "expireTime", expireTime.Format("2006-01-02 15:04:05"))
queryRecord := m7s.RecordStream{
EventLevel: m7s.EventLevelLow, // 查询条件event_level = low,非重要事件
}
err := t.DB.Where(&queryRecord).Find(&eventRecords, "end_time < ? AND end_time != '1970-01-01 00:00:00'", expireTime).Error
if err == nil {
for _, record := range eventRecords {
t.Info("RecordFileExpireDays is set to auto delete oldestfile", "ID", record.ID, "create time", record.EndTime, "filepath", record.FilePath)
err = os.Remove(record.FilePath)
if err != nil {
t.Error("RecordFileExpireDays set to auto delete oldestfile", "delete file from disk error", err)
}
err = t.DB.Delete(&record).Error
if err != nil {
t.Error("RecordFileExpireDays set to auto delete oldestfile", "delete record from db error", err)
}
}
}
}