Compare commits

...

35 Commits
v4.3.6 ... v4

Author SHA1 Message Date
muxiang
f00a5b11e9 兼容海康设备推流,处理流为tcp 协议时将sdp中y放到最后 2024-12-13 15:40:24 +08:00
langhuihui
5690be3b64 feat: update gosip lib 2024-08-19 16:37:01 +08:00
dexter
92c9876d82 Merge pull request #117 from bigbeer1/v4
:解决端口没有回收的问题,明确错误提示
2024-08-05 15:49:37 +08:00
dabenxiong
e9353651aa Merge remote-tracking branch 'origin/v4' into v4 2024-08-05 15:44:29 +08:00
dabenxiong
26f452fad0 fix:解决端口没有回收的问题,明确错误提示 2024-08-05 15:43:55 +08:00
dexter
ec32f5db39 Merge pull request #116 from BleethNie/v4
feat:预置位操作接口和列表查询
2024-08-02 17:39:14 +08:00
bleeth
87f3849fe7 feat:预置位操作接口和列表查询 2024-08-02 17:15:18 +08:00
dexter
78e16b4746 Merge pull request #114 from bigbeer1/v4
feat:增加配置文件支持多端口多路复用
2024-07-30 10:07:29 +08:00
dabenxiong
6ab73cd8dd feat:增加配置文件支持多端口多路复用 2024-07-30 10:00:03 +08:00
langhuihui
edffd7d470 fix: invite 失败时回收端口 2024-07-23 15:15:07 +08:00
langhuihui
70c06ebf84 fix: add ErrNoAvailablePorts 2024-07-09 19:47:12 +08:00
dexter
d35b18f1a9 Merge pull request #107 from duiniuluantanqin/fix-bug
Fix incorrect comparison
2024-04-03 10:15:12 +08:00
Haibo Chen
210f67b047 Fix incorrect comparison 2024-04-03 10:11:21 +08:00
langhuihui
bee261a670 支持通道号为空的情况 2023-12-12 19:18:48 +08:00
langhuihui
ce49463689 默认限制 invite 的通道类型 2023-12-08 19:04:43 +08:00
langhuihui
cbcaab61d4 开放更多属性 2023-12-08 09:07:13 +08:00
langhuihui
f80916dcf9 开放一些设备属性 2023-12-06 09:57:12 +08:00
langhuihui
35e916dd1c 配置中增加额外信息 2023-12-05 19:17:17 +08:00
langhuihui
26311753c2 doc: update readme 2023-10-18 14:19:49 +08:00
langhuihui
8f6ac6a40c 录像流无人观看则自动关闭 2023-09-29 09:39:15 +08:00
langhuihui
90901dc1ad 进一步加强对 from 的判断 2023-09-25 14:22:59 +08:00
langhuihui
f065353bd9 加点日志 2023-09-22 10:02:33 +08:00
langhuihui
879a7fc14c 升级 aurora 2023-09-20 19:12:31 +08:00
langhuihui
a2e47c727d 增加一些From 判空 2023-09-18 17:15:09 +08:00
langhuihui
f967679763 序列化 channel 时增加一些字段 2023-09-06 14:17:49 +08:00
langhuihui
db8ce0d94f 适配引擎升级 2023-08-13 14:49:38 +08:00
langhuihui
538e96a5c2 规避注册包里面from.Address为空导致的panic 2023-08-06 14:26:41 +08:00
langhuihui
c2003d53e8 更新readme 2023-07-14 15:55:48 +08:00
langhuihui
64ac75905f 默认打开范围端口 2023-07-11 19:38:30 +08:00
langhuihui
d2cc62ff9e 修改一个变量名拼写错误 2023-07-07 14:50:09 +08:00
dexter
2e8aa47bc5 Merge pull request #99 from kingecg/v4
修复:按需拉流支持回放流
2023-07-04 18:42:09 +08:00
程广
585d5949d3 fix query record 2023-07-04 18:17:11 +08:00
kingecg
0285236cce 修复:按需拉流支持回放流 2023-06-30 22:31:51 +08:00
dexter
12895fa2cc Merge pull request #98 from kingecg/patch-1
Update channel.go to support device not use tcp
2023-06-30 21:24:07 +08:00
kingecg
c66303e7e8 Update channel.go to support device not use tcp
when media set to tcp and device not support, fallback to udp
2023-06-30 19:13:47 +08:00
13 changed files with 702 additions and 387 deletions

View File

@@ -23,25 +23,23 @@ gb28181:
autosubposition: false #是否自动订阅定位
expires: 3600s #订阅周期(单位:秒)默认3600
interval: 6s #订阅间隔单位默认6
udpcachesize: 0 #表示UDP缓存大小默认为0不开启。仅当TCP关闭切缓存大于0时才开启
sipip: "" #sip服务器地址 默认 自动适配设备网段
serial: "34020000002000000001"
realm: "3402000000"
username: ""
password: ""
registervalidity: 60s #注册有效期
mediaip: "" #媒体服务器地址 默认 自动适配设备网段
port:
sip: udp:5060 #sip服务器端口
media: tcp:58200 #媒体服务器端口,用于接收设备的流,范围端口表示法udp:50000-60000
media: tcp:58200-59200 #媒体服务器端口,用于接收设备的流
fdm: false #端口复用,单端口默认多路复用,多端口多路复用根据这个
removebaninterval: 10m #定时移除注册失败的设备黑名单单位秒默认10分钟600秒
loglevel: info
```
**如果配置了端口范围,将采用范围端口机制,每一个流对应一个端口
**如果配置了端口范围(默认为范围端口),将采用范围端口机制,每一个流对应一个端口
**注意某些摄像机没有设置用户名的地方摄像机会以自身的国标id作为用户名这个时候m7s会忽略使用摄像机的用户名忽略配置的用户名**
如果设备配置了错误的用户名和密码连续三次上报错误后m7s会记录设备id并在10分钟内禁止设备注册
@@ -62,10 +60,6 @@ gb28181:
- 当invite设备的**实时**视频流时会在m7s中创建对应的流StreamPath由设备编号和通道编号组成即[设备编号]/[通道编号],如果有多个层级,通道编号是最后一个层级的编号
- 当invite设备的**录像**视频流时StreamPath由设备编号和通道编号以及录像的起止时间拼接而成即[设备编号]/[通道编号]/[开始时间]-[结束时间]
### 如何设置UDP缓存大小
通过wireshark抓包分析rtp然后看一下大概多少个包可以有序
## 接口API
### 罗列所有的gb28181协议的设备
@@ -133,8 +127,8 @@ http 200 表示成功404流不存在
| --------- | ---- | -------------------------------------------- |
| id | 是 | 设备ID |
| channel | 是 | 通道编号 |
| startTime | 否 | 开始时间(字符串格式2021-7-23T12:00:00 |
| endTime | 否 | 结束时间(字符串格式同上 |
| startTime | 否 | 开始时间(Unix时间戳 |
| endTime | 否 | 结束时间(Unix时间戳 |
### 移动位置订阅
@@ -145,3 +139,24 @@ http 200 表示成功404流不存在
| id | 是 | 设备ID |
| expires | 是 | 订阅周期(秒) |
| interval | 是 | 订阅间隔(秒) |
### 预置位列表查询
`/gb28181/api/preset/list`
| 参数名 | 必传 | 含义 |
| -------- | ---- | -------------- |
| id | 是 | 设备ID |
| channel | 是 | 通道编号 |
### 预置位操作
`/gb28181/api/preset/control`
| 参数名 | 必传 | 含义 |
| -------- | ---- |---------------------|
| id | 是 | 设备ID |
| channel | 是 | 通道编号 |
| cmd | 是 | 操作指令 0=新增,1=删除,2=调用 |
| point | 是 | 预置点位1-255 |

View File

@@ -10,6 +10,7 @@ import (
"sync/atomic"
"github.com/ghettovoice/gosip/sip"
"github.com/goccy/go-json"
"go.uber.org/zap"
. "m7s.live/engine/v4"
"m7s.live/engine/v4/log"
@@ -30,6 +31,7 @@ func (p *PullStream) CreateRequest(method sip.RequestMethod) (req sip.Request) {
req = p.channel.CreateRequst(method)
from, _ := res.From()
to, _ := res.To()
callId, _ := res.CallID()
req.ReplaceHeaders(from.Name(), []sip.Header{from})
req.ReplaceHeaders(to.Name(), []sip.Header{to})
@@ -39,9 +41,9 @@ func (p *PullStream) CreateRequest(method sip.RequestMethod) (req sip.Request) {
func (p *PullStream) Bye() int {
req := p.CreateRequest(sip.BYE)
resp, err := p.channel.device.SipRequestForResponse(req)
resp, err := p.channel.Device.SipRequestForResponse(req)
if p.opt.IsLive() {
p.channel.status.Store(0)
p.channel.State.Store(0)
}
if p.opt.recyclePort != nil {
p.opt.recyclePort(p.opt.MediaPort)
@@ -53,7 +55,7 @@ func (p *PullStream) Bye() int {
}
func (p *PullStream) info(body string) int {
d := p.channel.device
d := p.channel.Device
req := p.CreateRequest(sip.INFO)
contentType := sip.ContentType("Application/MANSRTSP")
req.AppendHeader(&contentType)
@@ -72,53 +74,83 @@ func (p *PullStream) Pause() int {
body := fmt.Sprintf(`PAUSE RTSP/1.0
CSeq: %d
PauseTime: now
`, p.channel.device.sn)
`, p.channel.Device.SN)
return p.info(body)
}
// 恢复播放
func (p *PullStream) Resume() int {
d := p.channel.device
d := p.channel.Device
body := fmt.Sprintf(`PLAY RTSP/1.0
CSeq: %d
Range: npt=now-
`, d.sn)
`, d.SN)
return p.info(body)
}
// 跳转到播放时间
// second: 相对于起始点调整到第 sec 秒播放
func (p *PullStream) PlayAt(second uint) int {
d := p.channel.device
d := p.channel.Device
body := fmt.Sprintf(`PLAY RTSP/1.0
CSeq: %d
Range: npt=%d-
`, d.sn, second)
`, d.SN, second)
return p.info(body)
}
// 快进/快退播放
// speed 取值: 0.25 0.5 1 2 4 或者其对应的负数表示倒放
func (p *PullStream) PlayForward(speed float32) int {
d := p.channel.device
d := p.channel.Device
body := fmt.Sprintf(`PLAY RTSP/1.0
CSeq: %d
Scale: %0.6f
`, d.sn, speed)
`, d.SN, speed)
return p.info(body)
}
type Channel struct {
device *Device // 所属设备
status atomic.Int32 // 通道状态,0:空闲,1:正在invite,2:正在播放
Device *Device `json:"-" yaml:"-"` // 所属设备
State atomic.Int32 `json:"-" yaml:"-"` // 通道状态,0:空闲,1:正在invite,2:正在播放/对讲
LiveSubSP string // 实时子码流通过rtsp
GpsTime time.Time //gps时间
Longitude string //经度
Latitude string //纬度
GpsTime time.Time // gps时间
Longitude string // 经度
Latitude string // 纬度
*log.Logger `json:"-" yaml:"-"`
ChannelInfo
}
type PresetInfo struct {
PresetID int `json:"-" yaml:"-"` //
PresetName string `json:"-" yaml:"-"` //
}
func (c *Channel) MarshalJSON() ([]byte, error) {
m := map[string]any{
"DeviceID": c.DeviceID,
"ParentID": c.ParentID,
"Name": c.Name,
"Manufacturer": c.Manufacturer,
"Model": c.Model,
"Owner": c.Owner,
"CivilCode": c.CivilCode,
"Address": c.Address,
"Port": c.Port,
"Parental": c.Parental,
"SafetyWay": c.SafetyWay,
"RegisterWay": c.RegisterWay,
"Secrecy": c.Secrecy,
"Status": c.Status,
"Longitude": c.Longitude,
"Latitude": c.Latitude,
"GpsTime": c.GpsTime,
"LiveSubSP": c.LiveSubSP,
"LiveStatus": c.State.Load(),
}
return json.Marshal(m)
}
// Channel 通道
type ChannelInfo struct {
DeviceID string // 通道ID
@@ -145,14 +177,14 @@ const (
)
func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request) {
d := channel.device
d.sn++
d := channel.Device
d.SN++
callId := sip.CallID(utils.RandNumString(10))
userAgent := sip.UserAgentHeader("Monibuca")
maxForwards := sip.MaxForwards(70) //增加max-forwards为默认值 70
cseq := sip.CSeq{
SeqNo: uint32(d.sn),
SeqNo: uint32(d.SN),
MethodName: Method,
}
port := sip.Port(conf.SipPort)
@@ -160,14 +192,14 @@ func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request)
//DisplayName: sip.String{Str: d.serverConfig.Serial},
Uri: &sip.SipUri{
FUser: sip.String{Str: conf.Serial},
FHost: d.sipIP,
FHost: d.SipIP,
FPort: &port,
},
Params: sip.NewParams().Add("tag", sip.String{Str: utils.RandNumString(9)}),
}
//非同一域的目标地址需要使用@host
host := conf.Realm
if channel.DeviceID[0:9] != host {
if channel.DeviceID[0:10] != host {
if channel.Port != 0 {
deviceIp := d.NetAddr
deviceIp = deviceIp[0:strings.LastIndex(deviceIp, ":")]
@@ -205,23 +237,26 @@ func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request)
}
func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error) {
d := channel.device
d := channel.Device
request := d.CreateRequest(sip.MESSAGE)
contentType := sip.ContentType("Application/MANSCDP+xml")
request.AppendHeader(&contentType)
body := fmt.Sprintf(`<?xml version="1.0"?>
<Query>
<CmdType>RecordInfo</CmdType>
<SN>%d</SN>
<DeviceID>%s</DeviceID>
<StartTime>%s</StartTime>
<EndTime>%s</EndTime>
<Secrecy>0</Secrecy>
<Type>all</Type>
</Query>`, d.sn, channel.DeviceID, startTime, endTime)
// body := fmt.Sprintf(`<?xml version="1.0"?>
// <Query>
// <CmdType>RecordInfo</CmdType>
// <SN>%d</SN>
// <DeviceID>%s</DeviceID>
// <StartTime>%s</StartTime>
// <EndTime>%s</EndTime>
// <Secrecy>0</Secrecy>
// <Type>all</Type>
// </Query>`, d.sn, channel.DeviceID, startTime, endTime)
start, _ := strconv.ParseInt(startTime, 10, 0)
end, _ := strconv.ParseInt(endTime, 10, 0)
body := BuildRecordInfoXML(d.SN, channel.DeviceID, start, end)
request.SetBody(body, true)
resultCh := RecordQueryLink.WaitResult(d.ID, channel.DeviceID, d.sn, QUERY_RECORD_TIMEOUT)
resultCh := RecordQueryLink.WaitResult(d.ID, channel.DeviceID, d.SN, QUERY_RECORD_TIMEOUT)
resp, err := d.SipRequestForResponse(request)
if err != nil {
return nil, fmt.Errorf("query error: %s", err)
@@ -235,8 +270,43 @@ func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error
return r.list, r.err
}
func (channel *Channel) QueryPresetList() (sip.Response, error) {
d := channel.Device
request := d.CreateRequest(sip.MESSAGE)
contentType := sip.ContentType("Application/MANSCDP+xml")
request.AppendHeader(&contentType)
body := BuildPresetListXML(100, channel.DeviceID)
request.SetBody(body, true)
resp, err := d.SipRequestForResponse(request)
if err != nil {
return nil, fmt.Errorf("query error: %s", err)
}
if resp.StatusCode() != http.StatusOK {
return nil, fmt.Errorf("query error, status=%d", resp.StatusCode())
}
return resp, nil
}
func (channel *Channel) PresetControl(ptzCode int, point byte) int {
cmd := byte(PresetSet)
switch ptzCode {
case PresetAddPoint:
cmd = PresetSet
case PresetDelPoint:
cmd = PresetDel
case PresetCallPoint:
cmd = PresetCall
default:
}
PTZCmd := Pack(cmd, point)
return channel.Control(PTZCmd)
}
func (channel *Channel) Control(PTZCmd string) int {
d := channel.device
d := channel.Device
request := d.CreateRequest(sip.MESSAGE)
contentType := sip.ContentType("Application/MANSCDP+xml")
request.AppendHeader(&contentType)
@@ -246,7 +316,7 @@ func (channel *Channel) Control(PTZCmd string) int {
<SN>%d</SN>
<DeviceID>%s</DeviceID>
<PTZCmd>%s</PTZCmd>
</Control>`, d.sn, channel.DeviceID, PTZCmd)
</Control>`, d.SN, channel.DeviceID, PTZCmd)
request.SetBody(body, true)
resp, err := d.SipRequestForResponse(request)
if err != nil {
@@ -304,13 +374,13 @@ f字段中视、音频参数段之间不需空格分割。
func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
if opt.IsLive() {
if !channel.status.CompareAndSwap(0, 1) {
if !channel.State.CompareAndSwap(0, 1) {
return 304, nil
}
defer func() {
if err != nil {
GB28181Plugin.Error("Invite", zap.Error(err))
channel.status.Store(0)
GB28181Plugin.Error("InviteRetryInit", zap.Error(err))
channel.State.Store(0)
if conf.InviteMode == 1 {
// 5秒后重试
time.AfterFunc(time.Second*5, func() {
@@ -318,11 +388,12 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
})
}
} else {
channel.status.Store(2)
channel.State.Store(2)
}
}()
}
d := channel.device
d := channel.Device
streamPath := fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
s := "Play"
opt.CreateSSRC()
@@ -332,6 +403,8 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
}
if opt.StreamPath != "" {
streamPath = opt.StreamPath
} else if channel.DeviceID == "" {
streamPath = "gb28181/" + d.ID
} else {
opt.StreamPath = streamPath
}
@@ -340,20 +413,21 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
}
protocol := ""
networkType := "udp"
resuePort := true
// 根据配置文件判断是否多路复用
reusePort := conf.Port.Fdm
if conf.IsMediaNetworkTCP() {
networkType = "tcp"
protocol = "TCP/"
if conf.tcpPorts.Valid {
opt.MediaPort, err = conf.tcpPorts.GetPort()
opt.recyclePort = conf.tcpPorts.Recycle
resuePort = false
}
} else {
if conf.udpPorts.Valid {
opt.MediaPort, err = conf.udpPorts.GetPort()
opt.recyclePort = conf.udpPorts.Recycle
resuePort = false
}
}
if err != nil {
@@ -361,23 +435,25 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
}
if opt.MediaPort == 0 {
opt.MediaPort = conf.MediaPort
// 单端口默认多路复用
reusePort = true
}
sdpInfo := []string{
"v=0",
fmt.Sprintf("o=%s 0 0 IN IP4 %s", channel.DeviceID, d.mediaIP),
fmt.Sprintf("o=%s 0 0 IN IP4 %s", channel.DeviceID, d.MediaIP),
"s=" + s,
"u=" + channel.DeviceID + ":0",
"c=IN IP4 " + d.mediaIP,
"c=IN IP4 " + d.MediaIP,
opt.String(),
fmt.Sprintf("m=video %d %sRTP/AVP 96", opt.MediaPort, protocol),
"a=recvonly",
"a=rtpmap:96 PS/90000",
"y=" + opt.ssrc,
}
if conf.IsMediaNetworkTCP() {
sdpInfo = append(sdpInfo, "a=setup:passive", "a=connection:new")
}
sdpInfo = append(sdpInfo, "y="+opt.ssrc)
invite := channel.CreateRequst(sip.INVITE)
contentType := sip.ContentType("application/sdp")
invite.AppendHeader(&contentType)
@@ -390,7 +466,10 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
invite.AppendHeader(&subject)
inviteRes, err := d.SipRequestForResponse(invite)
if err != nil {
channel.Error("invite", zap.Error(err), zap.String("msg", invite.String()))
if opt.recyclePort != nil {
opt.recyclePort(opt.MediaPort)
}
channel.Error("inviteRequestError", zap.Error(err), zap.String("msg", invite.String()))
return http.StatusInternalServerError, err
}
code = int(inviteRes.StatusCode())
@@ -406,25 +485,54 @@ func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
} else {
channel.Error("read invite response y ", zap.Error(err))
}
break
// break
}
if ls[0] == "m" && len(ls[1]) > 0 {
netinfo := strings.Split(ls[1], " ")
if strings.ToUpper(netinfo[2]) == "TCP/RTP/AVP" {
channel.Debug("Device support tcp")
} else {
channel.Debug("Device not support tcp")
networkType = "udp"
}
}
}
}
err = ps.Receive(streamPath, opt.dump, fmt.Sprintf("%s:%d", networkType, opt.MediaPort), opt.SSRC, resuePort)
if err == nil {
PullStreams.Store(streamPath, &PullStream{
opt: opt,
channel: channel,
inviteRes: inviteRes,
})
err = srv.Send(sip.NewAckRequest("", invite, inviteRes, "", nil))
var psPuber ps.PSPublisher
err = psPuber.Receive(streamPath, opt.dump, fmt.Sprintf("%s:%d", networkType, opt.MediaPort), opt.SSRC, reusePort)
if err != nil {
if opt.recyclePort != nil {
opt.recyclePort(opt.MediaPort)
}
channel.Error("inviteTcpCreateError", zap.Error(err))
return http.StatusInternalServerError, err
}
if !opt.IsLive() {
// 10秒无数据关闭
if psPuber.Stream.DelayCloseTimeout == 0 {
psPuber.Stream.DelayCloseTimeout = time.Second * 10
}
if psPuber.Stream.IdleTimeout == 0 {
psPuber.Stream.IdleTimeout = time.Second * 10
}
}
PullStreams.Store(streamPath, &PullStream{
opt: opt,
channel: channel,
inviteRes: inviteRes,
})
err = srv.Send(sip.NewAckRequest("", invite, inviteRes, "", nil))
} else {
if opt.recyclePort != nil {
opt.recyclePort(opt.MediaPort)
}
}
return
}
func (channel *Channel) Bye(streamPath string) int {
d := channel.device
d := channel.Device
if streamPath == "" {
streamPath = fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
}
@@ -482,13 +590,15 @@ func (channel *Channel) PlayForward(streamPath string, speed float32) int {
}
func (channel *Channel) TryAutoInvite(opt *InviteOptions) {
if channel.CanInvite() {
condition := !opt.IsLive() || channel.CanInvite()
channel.Debug("TryAutoInvite", zap.Any("opt", opt), zap.Bool("condition", condition))
if condition {
go channel.Invite(opt)
}
}
func (channel *Channel) CanInvite() bool {
if channel.status.Load() != 0 || len(channel.DeviceID) != 20 || channel.Status == ChannelOffStatus {
if channel.State.Load() != 0 || len(channel.DeviceID) != 20 || channel.Status == ChannelOffStatus {
return false
}

View File

@@ -15,7 +15,6 @@ import (
"m7s.live/engine/v4/log"
"m7s.live/plugin/gb28181/v4/utils"
// . "github.com/logrusorgru/aurora"
"github.com/ghettovoice/gosip/sip"
myip "github.com/husanpao/ip"
)
@@ -55,7 +54,6 @@ const (
)
type Device struct {
//*transaction.Core `json:"-" yaml:"-"`
ID string
Name string
Manufacturer string
@@ -65,10 +63,10 @@ type Device struct {
UpdateTime time.Time
LastKeepaliveAt time.Time
Status DeviceStatus
sn int
addr sip.Address
sipIP string //设备对应网卡的服务器ip
mediaIP string //设备对应网卡的服务器ip
SN int
Addr sip.Address `json:"-" yaml:"-"`
SipIP string //设备对应网卡的服务器ip
MediaIP string //设备对应网卡的服务器ip
NetAddr string
channelMap sync.Map
subscriber struct {
@@ -85,21 +83,20 @@ type Device struct {
func (d *Device) MarshalJSON() ([]byte, error) {
type Alias Device
data := &struct {
Channels []*ChannelInfo
Channels []*Channel
*Alias
}{
Alias: (*Alias)(d),
}
d.channelMap.Range(func(key, value interface{}) bool {
c := value.(*Channel)
data.Channels = append(data.Channels, &c.ChannelInfo)
data.Channels = append(data.Channels, value.(*Channel))
return true
})
return json.Marshal(data)
}
func (c *GB28181Config) RecoverDevice(d *Device, req sip.Request) {
from, _ := req.From()
d.addr = sip.Address{
d.Addr = sip.Address{
DisplayName: from.DisplayName,
Uri: from.Address,
}
@@ -125,8 +122,8 @@ func (c *GB28181Config) RecoverDevice(d *Device, req sip.Request) {
}
d.Info("RecoverDevice", zap.String("deviceIp", deviceIp), zap.String("servIp", servIp), zap.String("sipIP", sipIP), zap.String("mediaIp", mediaIp))
d.Status = DeviceRegisterStatus
d.sipIP = sipIP
d.mediaIP = mediaIp
d.SipIP = sipIP
d.MediaIP = mediaIp
d.NetAddr = deviceIp
d.UpdateTime = time.Now()
}
@@ -142,7 +139,7 @@ func (c *GB28181Config) StoreDevice(id string, req sip.Request) (d *Device) {
d = _d.(*Device)
d.UpdateTime = time.Now()
d.NetAddr = deviceIp
d.addr = deviceAddr
d.Addr = deviceAddr
d.Debug("UpdateDevice", zap.String("netaddr", d.NetAddr))
} else {
servIp := req.Recipient().Host()
@@ -169,9 +166,9 @@ func (c *GB28181Config) StoreDevice(id string, req sip.Request) (d *Device) {
RegisterTime: time.Now(),
UpdateTime: time.Now(),
Status: DeviceRegisterStatus,
addr: deviceAddr,
sipIP: sipIP,
mediaIP: mediaIp,
Addr: deviceAddr,
SipIP: sipIP,
MediaIP: mediaIp,
NetAddr: deviceIp,
Logger: GB28181Plugin.With(zap.String("id", id)),
}
@@ -216,11 +213,11 @@ func (d *Device) addOrUpdateChannel(info ChannelInfo) (c *Channel) {
c.ChannelInfo = info
} else {
c = &Channel{
device: d,
Device: d,
ChannelInfo: info,
Logger: d.Logger.With(zap.String("channel", info.DeviceID)),
}
if s := engine.Streams.Get(fmt.Sprintf("%s/%s/rtsp", c.device.ID, c.DeviceID)); s != nil {
if s := engine.Streams.Get(fmt.Sprintf("%s/%s/rtsp", c.Device.ID, c.DeviceID)); s != nil {
c.LiveSubSP = s.Path
} else {
c.LiveSubSP = ""
@@ -236,7 +233,7 @@ func (d *Device) deleteChannel(DeviceID string) {
func (d *Device) UpdateChannels(list ...ChannelInfo) {
for _, c := range list {
if _, ok := conf.Ignores[c.DeviceID]; ok {
if _, ok := conf.ignores[c.DeviceID]; ok {
continue
}
//当父设备非空且存在时、父设备节点增加通道
@@ -271,13 +268,13 @@ func (d *Device) UpdateChannels(list ...ChannelInfo) {
}
func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
d.sn++
d.SN++
callId := sip.CallID(utils.RandNumString(10))
userAgent := sip.UserAgentHeader("Monibuca")
maxForwards := sip.MaxForwards(70) //增加max-forwards为默认值 70
cseq := sip.CSeq{
SeqNo: uint32(d.sn),
SeqNo: uint32(d.SN),
MethodName: Method,
}
port := sip.Port(conf.SipPort)
@@ -285,7 +282,7 @@ func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
//DisplayName: sip.String{Str: d.config.Serial},
Uri: &sip.SipUri{
FUser: sip.String{Str: conf.Serial},
FHost: d.sipIP,
FHost: d.SipIP,
FPort: &port,
},
Params: sip.NewParams().Add("tag", sip.String{Str: utils.RandNumString(9)}),
@@ -293,11 +290,11 @@ func (d *Device) CreateRequest(Method sip.RequestMethod) (req sip.Request) {
req = sip.NewRequest(
"",
Method,
d.addr.Uri,
d.Addr.Uri,
"SIP/2.0",
[]sip.Header{
serverAddr.AsFromHeader(),
d.addr.AsToHeader(),
d.Addr.AsToHeader(),
&callId,
&userAgent,
&cseq,
@@ -348,7 +345,7 @@ func (d *Device) Subscribe() int {
request.AppendHeader(&contentType)
request.AppendHeader(&expires)
request.SetBody(BuildCatalogXML(d.sn, d.ID), true)
request.SetBody(BuildCatalogXML(d.SN, d.ID), true)
response, err := d.SipRequestForResponse(request)
if err == nil && response != nil {
@@ -372,7 +369,7 @@ func (d *Device) Catalog() int {
request.AppendHeader(&contentType)
request.AppendHeader(&expires)
request.SetBody(BuildCatalogXML(d.sn, d.ID), true)
request.SetBody(BuildCatalogXML(d.SN, d.ID), true)
// 输出Sip请求设备通道信息信令
GB28181Plugin.Sugar().Debugf("SIP->Catalog:%s", request)
resp, err := d.SipRequestForResponse(request)
@@ -392,7 +389,7 @@ func (d *Device) QueryDeviceInfo() {
request := d.CreateRequest(sip.MESSAGE)
contentType := sip.ContentType("Application/MANSCDP+xml")
request.AppendHeader(&contentType)
request.SetBody(BuildDeviceInfoXML(d.sn, d.ID), true)
request.SetBody(BuildDeviceInfoXML(d.SN, d.ID), true)
response, _ := d.SipRequestForResponse(request)
if response != nil {
@@ -427,7 +424,7 @@ func (d *Device) MobilePositionSubscribe(id string, expires time.Duration, inter
mobilePosition.AppendHeader(&contentType)
mobilePosition.AppendHeader(&expiresHeader)
mobilePosition.SetBody(BuildDevicePositionXML(d.sn, id, int(interval/time.Second)), true)
mobilePosition.SetBody(BuildDevicePositionXML(d.SN, id, int(interval/time.Second)), true)
response, err := d.SipRequestForResponse(mobilePosition)
if err == nil && response != nil {

82
go.mod
View File

@@ -3,62 +3,64 @@ module m7s.live/plugin/gb28181/v4
go 1.19
require (
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7
github.com/goccy/go-json v0.10.2
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/pion/rtp v1.7.13
go.uber.org/zap v1.23.0
golang.org/x/net v0.8.0
golang.org/x/text v0.8.0
m7s.live/engine/v4 v4.12.8
m7s.live/plugin/ps/v4 v4.0.1
github.com/logrusorgru/aurora/v4 v4.0.0
github.com/pion/rtp v1.8.3
go.uber.org/zap v1.26.0
golang.org/x/net v0.19.0
golang.org/x/text v0.14.0
m7s.live/engine/v4 v4.15.2
m7s.live/plugin/ps/v4 v4.1.3
)
require (
github.com/aler9/gortsplib/v2 v2.2.2 // indirect
github.com/cnotch/ipchub v1.1.0 // indirect
github.com/bluenviron/gortsplib/v4 v4.6.2 // indirect
github.com/bluenviron/mediacommon v1.5.1 // indirect
github.com/deepch/vdk v0.0.27 // indirect
github.com/denisbrodbeck/machineid v1.0.1 // indirect
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/gobwas/ws v1.3.1 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mcuadros/go-defaults v1.2.0 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.12.1 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/webrtc/v3 v3.1.49 // indirect
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
github.com/q191201771/naza v0.30.8 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/quic-go/quic-go v0.32.0 // indirect
github.com/pion/webrtc/v3 v3.2.20 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/q191201771/naza v0.30.48 // indirect
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
github.com/quic-go/quic-go v0.38.1 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/shirou/gopsutil/v3 v3.22.10 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/shirou/gopsutil/v3 v3.23.8 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tevino/abool v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/tools v0.6.0 // indirect
github.com/yapingcat/gomedia v0.0.0-20230905155010-55b9713fcec1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

275
go.sum
View File

@@ -1,43 +1,38 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aler9/gortsplib/v2 v2.2.2 h1:tTw8pdKSOEjlZjjE1S4ftXPHJkYOqjNNv3hjQ0Nto9M=
github.com/aler9/gortsplib/v2 v2.2.2/go.mod h1:k6uBVHGwsIc/0L5SLLqWwi6bSJUb4VR0HfvncyHlKQI=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3/go.mod h1:5deJPLON/x/s2dLOQfuKS0lenhOIT4xX0pvtN/OEIuY=
github.com/cnotch/ipchub v1.1.0 h1:hH0lh2mU3AZXPiqMwA0pdtqrwo7PFIMRGush9OobMUs=
github.com/cnotch/ipchub v1.1.0/go.mod h1:2PbeBs2q2VxxTVCn1eYCDwpAWuVXbq1+N0FU7GimOH4=
github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439/go.mod h1:oWpDagHB6p+Kqqq7RoRZKyC4XAXft50hR8pbTxdbYYs=
github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo=
github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E=
github.com/bluenviron/gortsplib/v4 v4.6.2 h1:CGIsxpnUFvSlIxnSFS0oFSSfwsHMmBCmYcrGAtIcwXc=
github.com/bluenviron/gortsplib/v4 v4.6.2/go.mod h1:dN1YjyPNMfy/NwC17Ga6MiIMiUoQfg5GL7LGsVHa0Jo=
github.com/bluenviron/mediacommon v1.5.1 h1:yYVF+ebqZOJh8yH+EeuPcAtTmWR66BqbJGmStxkScoI=
github.com/bluenviron/mediacommon v1.5.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deepch/vdk v0.0.27 h1:j/SHaTiZhA47wRpaue8NRp7P9xwOOO/lunxrDJBwcao=
github.com/deepch/vdk v0.0.27/go.mod h1:JlgGyR2ld6+xOIHa7XAxJh+stSDBAkdNvIPkUIdIywk=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca h1:cTTdXpkQ1aVbOOmHwdwtYuwUZcQtcMrleD1UXLWhAq8=
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca/go.mod h1:W+3LQaEkN8qAwwcw0KC546sUEnX86GIT8CcMLZC4mG0=
github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d h1:f1JRfm0MwkluwtUsbYxuVReDMajlc9Wn6zc2orX4sRE=
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d/go.mod h1:yTr3BEYSFe9As6XM7ldyrVgqsPwlnw8Ahc4N28VFM2g=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7 h1:2ENInMa9XHho+1mUM8RZMZomAnfz+qR5v6AS0+TrM8w=
github.com/ghettovoice/gosip v0.0.0-20231227123312-6b80e2d3e6f7/go.mod h1:rlD1yLOErWYohWTryG/2bTTpmzB79p52ntLA/uIFXeI=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0-rc.1/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -48,8 +43,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -57,35 +52,32 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ=
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8 h1:4Jk58quTZmzJcTrLlbB5L1Q6qXu49EIjCReWxcBFWKo=
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8/go.mod h1:medl9/CfYoQlqAXtAARmMW5dAX2UOdwwkhaszYPk0AM=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/kelindar/process v0.0.0-20170730150328-69a29e249ec3/go.mod h1:+lTCLnZFXOkqwD8sLPl6u4erAc0cP8wFegQHfipz7KE=
github.com/kelindar/rate v1.0.0/go.mod h1:AjT4G+hTItNwt30lucEGZIz8y7Uk5zPho6vurIZ+1Es=
github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA=
github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk56oZtc=
github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@@ -98,153 +90,147 @@ github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
github.com/pion/ice/v2 v2.2.12/go.mod h1:z2KXVFyRkmjetRlaVRgjO9U3ShKwzhlUylvxKfHfd5A=
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
github.com/pion/interceptor v0.1.18/go.mod h1:tpvvF4cPM6NGxFA1DUMbhabzQBxdWMATDGEUYOR9x6I=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSyaI=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.3/go.mod h1:OHbDjdk7kg+L+7TJim9q/qGVefdEJohuA2SZyihccgI=
github.com/pion/rtp v1.8.1/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8=
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp/v2 v2.0.10/go.mod h1:XEeSWaK9PfuMs7zxXyiN252AHPbH12NX5q/CFDWtUuA=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.49 h1:rbsNGxK9jMYts+xE6zYAJMUQHnGwmk/JYze8yttW+to=
github.com/pion/webrtc/v3 v3.1.49/go.mod h1:kHf/o47QW4No1rgpsFux/h7lUhtUnwFnSFDZOXeLapw=
github.com/pixelbender/go-sdp v1.1.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs=
github.com/pion/srtp/v2 v2.0.17/go.mod h1:y5WSHcJY4YfNB/5r7ca5YjHeIr1H3LM1rKArGGs8jMc=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/webrtc/v3 v3.2.20 h1:BQJiXQsJq9LgLp3op7rLy1y8d2WD+LtiS9cpY0uQ22A=
github.com/pion/webrtc/v3 v3.2.20/go.mod h1:vVURQTBOG5BpWKOJz3nlr23NfTDeyKVmubRNqzQp+Tg=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/q191201771/naza v0.30.8 h1:Lhh29o65C4PmTDj2l+eKfsw9dddpgWZk4bFICtcnSaA=
github.com/q191201771/naza v0.30.8/go.mod h1:n+dpJjQSh90PxBwxBNuifOwQttywvSIN5TkWSSYCeBk=
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/q191201771/naza v0.30.48 h1:lbYUaa7A15kJKYwOiU4AbFS1Zo8oQwppl2tLEbJTqnw=
github.com/q191201771/naza v0.30.48/go.mod h1:n+dpJjQSh90PxBwxBNuifOwQttywvSIN5TkWSSYCeBk=
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg=
github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk=
github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274 h1:cj4I+bvWX9I+Hg6tnZ7DAiOVxzhyLhdvYVKp+WpM/2c=
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
github.com/yapingcat/gomedia v0.0.0-20230905155010-55b9713fcec1 h1:ilNIuDBR+UKA3qefiyWRoFufIFn3E4tgEXbBM4ILH28=
github.com/yapingcat/gomedia v0.0.0-20230905155010-55b9713fcec1/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -253,55 +239,66 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -314,25 +311,23 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
m7s.live/engine/v4 v4.12.8 h1:cNGyajzEkbUzIcPtcedGbxvMlIuScWxDb/raYFgAHKE=
m7s.live/engine/v4 v4.12.8/go.mod h1:LoALBfV5rmsz5TJQr6cmLxM33mfUE5BKBq/sMtXOVlc=
m7s.live/plugin/ps/v4 v4.0.1 h1:iKgo9D4g6vo3I97Je1hG8v/6+IDRei7sHnTCYBEyasY=
m7s.live/plugin/ps/v4 v4.0.1/go.mod h1:lAPr3gGIFoU4ctMRnPeyjbcREueyT6TfiKhWBgDrOGM=
m7s.live/engine/v4 v4.15.2 h1:Uws658Ict2B8JojBG7fNmd2G2i63MlomsQ4npgNzF3g=
m7s.live/engine/v4 v4.15.2/go.mod h1:uKxjmsjU1WARUNowEkP83BSrJMUjGwkJrX5nPi6DGmE=
m7s.live/plugin/ps/v4 v4.1.3 h1:Lbvu3ZlX/s3w9lcOwF0SCOCvxtxongPexCIn6x4yukw=
m7s.live/plugin/ps/v4 v4.1.3/go.mod h1:RAb507iNmPG43I5kUA6ewF1fTRHDRsKbIVkIdLdKeeI=

View File

@@ -7,10 +7,10 @@ import (
"fmt"
"strconv"
"go.uber.org/zap"
"m7s.live/plugin/gb28181/v4/utils"
"github.com/ghettovoice/gosip/sip"
"go.uber.org/zap"
. "m7s.live/engine/v4"
"m7s.live/plugin/gb28181/v4/utils"
"net/http"
"time"
@@ -54,8 +54,8 @@ func (a *Authorization) getDigest(raw string) string {
func (c *GB28181Config) OnRegister(req sip.Request, tx sip.ServerTransaction) {
from, ok := req.From()
if !ok {
GB28181Plugin.Error("OnRegister", zap.String("error", "no from"))
if !ok || from.Address == nil || from.Address.User() == nil {
GB28181Plugin.Error("OnRegister", zap.String("error", "no id"))
return
}
id := from.Address.User().String()
@@ -195,8 +195,17 @@ func (d *Device) syncChannels() {
}
}
type MessageEvent struct {
Type string
Device *Device
}
func (c *GB28181Config) OnMessage(req sip.Request, tx sip.ServerTransaction) {
from, _ := req.From()
from, ok := req.From()
if !ok || from.Address == nil || from.Address.User() == nil {
GB28181Plugin.Error("OnMessage", zap.String("error", "no id"))
return
}
id := from.Address.User().String()
GB28181Plugin.Debug("SIP<-OnMessage", zap.String("id", id), zap.String("source", req.Source()), zap.String("req", req.String()))
if v, ok := Devices.Load(id); ok {
@@ -263,13 +272,20 @@ func (c *GB28181Config) OnMessage(req sip.Request, tx sip.ServerTransaction) {
case "Alarm":
d.Status = DeviceAlarmedStatus
body = BuildAlarmResponseXML(d.ID)
case "Broadcast":
GB28181Plugin.Info("broadcast message", zap.String("body", req.Body()))
case "PresetQuery":
GB28181Plugin.Info("PresetQuery message", zap.String("body", req.Body()))
default:
d.Warn("Not supported CmdType", zap.String("CmdType", temp.CmdType), zap.String("body", req.Body()))
response := sip.NewResponseFromRequest("", req, http.StatusBadRequest, "", "")
tx.Respond(response)
return
}
EmitEvent(MessageEvent{
Type: temp.CmdType,
Device: d,
})
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", body))
} else {
GB28181Plugin.Debug("Unauthorized message, device not found", zap.String("id", id))
@@ -279,9 +295,15 @@ func (c *GB28181Config) OnBye(req sip.Request, tx sip.ServerTransaction) {
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", ""))
}
type NotifyEvent MessageEvent
// OnNotify 订阅通知处理
func (c *GB28181Config) OnNotify(req sip.Request, tx sip.ServerTransaction) {
from, _ := req.From()
from, ok := req.From()
if !ok || from.Address == nil || from.Address.User() == nil {
GB28181Plugin.Error("OnMessage", zap.String("error", "no id"))
return
}
id := from.Address.User().String()
if v, ok := Devices.Load(id); ok {
d := v.(*Device)
@@ -315,15 +337,17 @@ func (c *GB28181Config) OnNotify(req sip.Request, tx sip.ServerTransaction) {
case "MobilePosition":
//更新channel的坐标
d.UpdateChannelPosition(temp.DeviceID, temp.Time, temp.Longitude, temp.Latitude)
// case "Alarm":
// //报警事件通知 TODO
case "Alarm":
d.Status = DeviceAlarmedStatus
default:
d.Warn("Not supported CmdType", zap.String("CmdType", temp.CmdType), zap.String("body", req.Body()))
response := sip.NewResponseFromRequest("", req, http.StatusBadRequest, "", "")
tx.Respond(response)
return
}
EmitEvent(NotifyEvent{
Type: temp.CmdType,
Device: d})
tx.Respond(sip.NewResponseFromRequest("", req, http.StatusOK, "OK", body))
}
}

104
main.go
View File

@@ -6,6 +6,7 @@ import (
"sync"
"time"
"github.com/ghettovoice/gosip/sip"
myip "github.com/husanpao/ip"
"go.uber.org/zap"
. "m7s.live/engine/v4"
@@ -13,55 +14,52 @@ import (
)
type GB28181PositionConfig struct {
AutosubPosition bool //是否自动订阅定位
Expires time.Duration `default:"3600s"` //订阅周期(单位:秒)
Interval time.Duration `default:"6s"` //订阅间隔(单位:秒)
AutosubPosition bool `desc:"是否自动订阅定位"` //是否自动订阅定位
Expires time.Duration `default:"3600s" desc:"订阅周期"` //订阅周期
Interval time.Duration `default:"6s" desc:"订阅间隔"` //订阅间隔
}
type GB28181Config struct {
InviteMode int `default:"1"` //邀请模式0:手动拉流1:预拉流2:按需拉流
InviteIDs string //按照国标gb28181协议允许邀请的设备类型:132 摄像机 NVR
ListenAddr string `default:"0.0.0.0"`
InviteMode int `default:"1" desc:"拉流模式" enum:"0:手动拉流,1:预拉流,2:按需拉流"` //邀请模式0:手动拉流1:预拉流2:按需拉流
InviteIDs string `default:"131,132" desc:"允许邀请的设备类型( 1113位是设备类型编码,逗号分割"` //按照国标gb28181协议允许邀请的设备类型:132 摄像机 NVR
ListenAddr string `default:"0.0.0.0" desc:"监听IP地址"` //监听地址
//sip服务器的配置
SipNetwork string `default:"udp"` //传输协议默认UDP可选TCP
SipIP string //sip 服务器公网IP
SipPort uint16 `default:"5060"` //sip 服务器端口,默认 5060
Serial string `default:"34020000002000000001"` //sip 服务器 id, 默认 34020000002000000001
Realm string `default:"3402000000"` //sip 服务器域,默认 3402000000
Username string //sip 服务器账号
Password string //sip 服务器密码
SipNetwork string `default:"udp" desc:"废弃,请使用 Port"` //传输协议默认UDP可选TCP
SipIP string `desc:"sip 服务IP地址"` //sip 服务器公网IP
SipPort sip.Port `default:"5060" desc:"废弃,请使用 Port"` //sip 服务器端口,默认 5060
Serial string `default:"34020000002000000001" desc:"sip 服务 id"` //sip 服务器 id, 默认 34020000002000000001
Realm string `default:"3402000000" desc:"sip 服务域"` //sip 服务器域,默认 3402000000
Username string `desc:"sip 服务账号"` //sip 服务器账号
Password string `desc:"sip 服务密码"` //sip 服务器密码
Port struct { // 新配置方式
Sip string `default:"udp:5060"`
Media string `default:"tcp:58200"`
Sip string `default:"udp:5060" desc:"sip服务端口号"`
Media string `default:"tcp:58200-59200" desc:"媒体服务端口号"`
Fdm bool `default:"false" desc:"多路复用"`
}
// AckTimeout uint16 //sip 服务应答超时,单位秒
RegisterValidity time.Duration `default:"3600s"` //注册有效期,单位秒,默认 3600
// RegisterInterval int //注册间隔,单位秒,默认 60
HeartbeatInterval time.Duration `default:"60s"` //心跳间隔,单位秒,默认 60
// HeartbeatRetry int //心跳超时次数,默认 3
RegisterValidity time.Duration `default:"3600s" desc:"注册有效期"` //注册有效期,单位秒,默认 3600
HeartbeatInterval time.Duration `default:"60s" desc:"心跳间隔"` //心跳间隔,单位秒,默认 60
//媒体服务器配置
MediaIP string //媒体服务器地址
MediaPort uint16 `default:"58200"` //媒体服务器端口
MediaNetwork string `default:"tcp"` //媒体传输协议默认UDP可选TCP
MediaPortMin uint16
MediaPortMax uint16
// MediaIdleTimeout uint16 //推流超时时间,超过则断开链接,让设备重连
MediaIP string `desc:"媒体服务IP地址"` //媒体服务器地址
MediaPort uint16 `default:"58200" desc:"废弃,请使用 Port"` //媒体服务器端口
MediaNetwork string `default:"tcp" desc:"废弃,请使用 Port"` //媒体传输协议默认UDP可选TCP
MediaPortMin uint16 `default:"58200" desc:"废弃,请使用 Port"`
MediaPortMax uint16 `default:"59200" desc:"废弃,请使用 Port"`
// WaitKeyFrame bool //是否等待关键帧,如果等待,则在收到第一个关键帧之前,忽略所有媒体流
RemoveBanInterval time.Duration `default:"600s"` //移除禁止设备间隔
// UdpCacheSize int //udp缓存大小
LogLevel string `default:"info"` //trace, debug, info, warn, error, fatal, panic
routes map[string]string
DumpPath string //dump PS流本地文件路径
Ignores map[string]struct{}
tcpPorts PortManager
udpPorts PortManager
RemoveBanInterval time.Duration `default:"600s" desc:"移除禁止设备间隔"` //移除禁止设备间隔
routes map[string]string
DumpPath string `desc:"dump PS流本地文件路径"` //dump PS流本地文件路径
Ignores []string `desc:"忽略的设备ID"` //忽略的设备ID
ignores map[string]struct{}
tcpPorts PortManager
udpPorts PortManager
Position GB28181PositionConfig //关于定位的配置参数
}
var SipUri *sip.SipUri
func (c *GB28181Config) initRoutes() {
c.routes = make(map[string]string)
tempIps := myip.LocalAndInternalIPs()
@@ -80,26 +78,52 @@ func (c *GB28181Config) OnEvent(event any) {
if c.Port.Sip != "udp:5060" {
protocol, ports := util.Conf2Listener(c.Port.Sip)
c.SipNetwork = protocol
c.SipPort = ports[0]
c.SipPort = sip.Port(ports[0])
}
if c.Port.Media != "tcp:58200" {
if c.Port.Media != "tcp:58200-59200" {
protocol, ports := util.Conf2Listener(c.Port.Media)
c.MediaNetwork = protocol
if len(ports) > 1 {
c.MediaPortMin = ports[0]
c.MediaPortMax = ports[1]
} else {
c.MediaPortMin = 0
c.MediaPortMax = 0
c.MediaPort = ports[0]
}
}
if len(c.Ignores) > 0 {
c.ignores = make(map[string]struct{})
for _, v := range c.Ignores {
c.ignores[v] = util.Null
}
}
os.MkdirAll(c.DumpPath, 0766)
c.ReadDevices()
SipUri = &sip.SipUri{
FUser: sip.String{Str: c.Serial},
FHost: c.SipIP,
FPort: &conf.SipPort,
}
go c.initRoutes()
c.startServer()
case *Stream:
case InvitePublish:
if c.InviteMode == INVIDE_MODE_ONSUBSCRIBE {
if channel := FindChannel(e.AppName, e.StreamName); channel != nil {
channel.TryAutoInvite(&InviteOptions{})
//流可能是回放流stream path是device/channel/start-end形式
streamNames := strings.Split(e.Target, "/")
if channel := FindChannel(streamNames[0], streamNames[1]); channel != nil {
opt := InviteOptions{}
if len(streamNames) > 2 {
last := len(streamNames) - 1
timestr := streamNames[last]
trange := strings.Split(timestr, "-")
if len(trange) == 2 {
startTime := trange[0]
endTime := trange[1]
opt.Validate(startTime, endTime)
}
}
channel.TryAutoInvite(&opt)
}
}
case SEpublish:

View File

@@ -1,11 +1,23 @@
package gb28181
import (
"encoding/xml"
"fmt"
"strconv"
"time"
)
var (
// 获取预置位列表
PresentListXML = `
<?xml version="1.0"?>
<Query>
<CmdType>PresetQuery</CmdType>
<SN>%d</SN>
<DeviceID>%s</DeviceID>
</Query>
`
// CatalogXML 获取设备列表xml样式
CatalogXML = `<?xml version="1.0"?><Query>
<CmdType>Catalog</CmdType>
@@ -43,6 +55,17 @@ var (
</Query>`
)
func intTotime(t int64) time.Time {
tstr := strconv.FormatInt(t, 10)
if len(tstr) == 10 {
return time.Unix(t, 0)
}
if len(tstr) == 13 {
return time.UnixMilli(t)
}
return time.Now()
}
// BuildDeviceInfoXML 获取设备详情指令
func BuildDeviceInfoXML(sn int, id string) string {
return fmt.Sprintf(DeviceInfoXML, sn, id)
@@ -53,9 +76,13 @@ func BuildCatalogXML(sn int, id string) string {
return fmt.Sprintf(CatalogXML, sn, id)
}
func BuildPresetListXML(sn int, id string) string {
return fmt.Sprintf(PresentListXML, sn, id)
}
// BuildRecordInfoXML 获取录像文件列表指令
func BuildRecordInfoXML(sn int, id string, start, end int64) string {
return fmt.Sprintf(RecordInfoXML, sn, id, time.Unix(start, 0).Format("2006-01-02T15:04:05"), time.Unix(end, 0).Format("2006-01-02T15:04:05"))
return fmt.Sprintf(RecordInfoXML, sn, id, intTotime(start).Format("2006-01-02T15:04:05"), intTotime(end).Format("2006-01-02T15:04:05"))
}
// BuildDevicePositionXML 订阅设备位置
@@ -78,3 +105,13 @@ var (
func BuildAlarmResponseXML(id string) string {
return fmt.Sprintf(AlarmResponseXML, id)
}
func XmlEncode(v interface{}) (string, error) {
xmlData, err := xml.MarshalIndent(v, "", " ")
if err != nil {
return "", err
}
xml := string(xmlData)
xml = `<?xml version="1.0" ?>` + "\n" + xml + "\n"
return xml, err
}

View File

@@ -1,15 +1,21 @@
package gb28181
import "io"
import (
"errors"
)
var ErrNoAvailablePorts = errors.New("no available ports")
type PortManager struct {
recycle chan uint16
start uint16
max uint16
pos uint16
Valid bool
}
func (pm *PortManager) Init(start, end uint16) {
pm.start = start
pm.pos = start - 1
pm.max = end
if pm.pos > 0 && pm.max > pm.pos {
@@ -27,7 +33,7 @@ func (pm *PortManager) Recycle(p uint16) (err error) {
case pm.recycle <- p:
return nil
default:
return io.EOF //TODO: 换一个Error
return ErrNoAvailablePorts
}
}
@@ -41,7 +47,12 @@ func (pm *PortManager) GetPort() (p uint16, err error) {
p = pm.pos
return
} else {
return 0, io.EOF //TODO: 换一个Error
if conf.Port.Fdm == false {
return 0, ErrNoAvailablePorts
}
pm.pos = pm.start - 1
p = pm.pos
return
}
}
}

62
ptz.go
View File

@@ -1,6 +1,10 @@
package gb28181
import "fmt"
import (
"encoding/hex"
"encoding/xml"
"fmt"
)
var (
name2code = map[string]uint8{
@@ -18,6 +22,35 @@ var (
}
)
type PresetCmd byte
const (
PresetAddPoint = 0
PresetDelPoint = 1
PresetCallPoint = 2
)
const DeviceControl = "DeviceControl"
const PTZFirstByte = 0xA5
const (
PresetSet = 0x81
PresetCall = 0x82
PresetDel = 0x83
)
type MessagePtz struct {
XMLName xml.Name `xml:"Control"`
CmdType string `xml:"CmdType"`
SN int `xml:"SN"`
DeviceID string `xml:"DeviceID"`
PTZCmd string `xml:"PTZCmd"`
}
type Preset struct {
CMD byte
Point byte
}
func toPtzStrByCmdName(cmdName string, horizontalSpeed, verticalSpeed, zoomSpeed uint8) (string, error) {
c, err := toPtzCode(cmdName)
if err != nil {
@@ -45,3 +78,30 @@ func toPtzCode(cmd string) (uint8, error) {
return 0, fmt.Errorf("invalid ptz cmd %q", cmd)
}
}
func getVerificationCode(ptz []byte) {
sum := uint8(0)
for i := 0; i < len(ptz)-1; i++ {
sum += ptz[i]
}
ptz[len(ptz)-1] = sum
}
func getAssembleCode() uint8 {
return (PTZFirstByte>>4 + PTZFirstByte&0xF + 0) % 16
}
func Pack(cmd, point byte) string {
buf := make([]byte, 8)
buf[0] = PTZFirstByte
buf[1] = getAssembleCode()
buf[2] = 0
buf[3] = cmd
buf[4] = 0
buf[5] = point
buf[6] = 0
getVerificationCode(buf)
return hex.EncodeToString(buf)
}

View File

@@ -1,7 +1,6 @@
package gb28181
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
@@ -16,14 +15,18 @@ var (
)
func (c *GB28181Config) API_list(w http.ResponseWriter, r *http.Request) {
util.ReturnJson(func() (list []*Device) {
query := r.URL.Query()
if query.Get("interval") == "" {
query.Set("interval", "5s")
}
util.ReturnFetchValue(func() (list []*Device) {
list = make([]*Device, 0)
Devices.Range(func(key, value interface{}) bool {
list = append(list, value.(*Device))
return true
})
return
}, time.Second*5, w, r)
}, w, r)
}
func (c *GB28181Config) API_records(w http.ResponseWriter, r *http.Request) {
@@ -40,12 +43,12 @@ func (c *GB28181Config) API_records(w http.ResponseWriter, r *http.Request) {
if c := FindChannel(id, channel); c != nil {
res, err := c.QueryRecord(startTime, endTime)
if err == nil {
WriteJSONOk(w, res)
util.ReturnValue(res, w, r)
} else {
WriteJSON(w, err.Error(), http.StatusInternalServerError)
util.ReturnError(util.APIErrorInternal, err.Error(), w, r)
}
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -54,9 +57,9 @@ func (c *GB28181Config) API_control(w http.ResponseWriter, r *http.Request) {
channel := r.URL.Query().Get("channel")
ptzcmd := r.URL.Query().Get("ptzcmd")
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.Control(ptzcmd))
util.ReturnError(0, fmt.Sprintf("control code:%d", c.Control(ptzcmd)), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -71,30 +74,30 @@ func (c *GB28181Config) API_ptz(w http.ResponseWriter, r *http.Request) {
hsN, err := strconv.ParseUint(hs, 10, 8)
if err != nil {
WriteJSON(w, "hSpeed parameter is invalid", 400)
util.ReturnError(util.APIErrorQueryParse, "hSpeed parameter is invalid", w, r)
return
}
vsN, err := strconv.ParseUint(vs, 10, 8)
if err != nil {
WriteJSON(w, "vSpeed parameter is invalid", 400)
util.ReturnError(util.APIErrorQueryParse, "vSpeed parameter is invalid", w, r)
return
}
zsN, err := strconv.ParseUint(zs, 10, 8)
if err != nil {
WriteJSON(w, "zSpeed parameter is invalid", 400)
util.ReturnError(util.APIErrorQueryParse, "zSpeed parameter is invalid", w, r)
return
}
ptzcmd, err := toPtzStrByCmdName(cmd, uint8(hsN), uint8(vsN), uint8(zsN))
if err != nil {
WriteJSON(w, err.Error(), 400)
util.ReturnError(util.APIErrorQueryParse, err.Error(), w, r)
return
}
if c := FindChannel(id, channel); c != nil {
code := c.Control(ptzcmd)
WriteJSON(w, "device received", code)
util.ReturnError(code, "device received", w, r)
} else {
WriteJSON(w, fmt.Sprintf("device %q channel %q not found", id, channel), 404)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -118,13 +121,17 @@ func (c *GB28181Config) API_invite(w http.ResponseWriter, r *http.Request) {
}
opt.Validate(startTime, endTime)
if c := FindChannel(id, channel); c == nil {
http.NotFound(w, r)
} else if opt.IsLive() && c.status.Load() > 0 {
http.Error(w, "live stream already exists", http.StatusNotModified)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
} else if opt.IsLive() && c.State.Load() > 0 {
util.ReturnError(util.APIErrorQueryParse, "live stream already exists", w, r)
} else if code, err := c.Invite(&opt); err == nil {
w.WriteHeader(code)
if code == 200 {
util.ReturnOK(w, r)
} else {
util.ReturnError(util.APIErrorInternal, fmt.Sprintf("invite return code %d", code), w, r)
}
} else {
http.Error(w, err.Error(), code)
util.ReturnError(util.APIErrorInternal, err.Error(), w, r)
}
}
@@ -133,9 +140,9 @@ func (c *GB28181Config) API_bye(w http.ResponseWriter, r *http.Request) {
channel := r.URL.Query().Get("channel")
streamPath := r.URL.Query().Get("streamPath")
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.Bye(streamPath))
util.ReturnError(0, fmt.Sprintf("bye code:%d", c.Bye(streamPath)), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -144,9 +151,9 @@ func (c *GB28181Config) API_play_pause(w http.ResponseWriter, r *http.Request) {
channel := r.URL.Query().Get("channel")
streamPath := r.URL.Query().Get("streamPath")
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.Pause(streamPath))
util.ReturnError(0, fmt.Sprintf("pause code:%d", c.Pause(streamPath)), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -155,9 +162,9 @@ func (c *GB28181Config) API_play_resume(w http.ResponseWriter, r *http.Request)
channel := r.URL.Query().Get("channel")
streamPath := r.URL.Query().Get("streamPath")
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.Resume(streamPath))
util.ReturnError(0, fmt.Sprintf("resume code:%d", c.Resume(streamPath)), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -168,13 +175,13 @@ func (c *GB28181Config) API_play_seek(w http.ResponseWriter, r *http.Request) {
secStr := r.URL.Query().Get("second")
sec, err := strconv.ParseUint(secStr, 10, 32)
if err != nil {
WriteJSON(w, "second parameter is invalid: "+err.Error(), 400)
util.ReturnError(util.APIErrorQueryParse, "second parameter is invalid: "+err.Error(), w, r)
return
}
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.PlayAt(streamPath, uint(sec)))
util.ReturnError(0, fmt.Sprintf("play code:%d", c.PlayAt(streamPath, uint(sec))), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -186,13 +193,13 @@ func (c *GB28181Config) API_play_forward(w http.ResponseWriter, r *http.Request)
speed, err := strconv.ParseFloat(speedStr, 32)
secondErrMsg := "speed parameter is invalid, should be one of 0.25,0.5,1,2,4"
if err != nil || !playScaleValues[float32(speed)] {
WriteJSON(w, secondErrMsg, 400)
util.ReturnError(util.APIErrorQueryParse, secondErrMsg, w, r)
return
}
if c := FindChannel(id, channel); c != nil {
w.WriteHeader(c.PlayForward(streamPath, float32(speed)))
util.ReturnError(0, fmt.Sprintf("playforward code:%d", c.PlayForward(streamPath, float32(speed))), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -217,9 +224,50 @@ func (c *GB28181Config) API_position(w http.ResponseWriter, r *http.Request) {
if v, ok := Devices.Load(id); ok {
d := v.(*Device)
w.WriteHeader(d.MobilePositionSubscribe(id, expiresInt, intervalInt))
util.ReturnError(0, fmt.Sprintf("mobileposition code:%d", d.MobilePositionSubscribe(id, expiresInt, intervalInt)), w, r)
} else {
http.NotFound(w, r)
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q not found", id), w, r)
}
}
func (c *GB28181Config) API_preset_list(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
//设备id
id := query.Get("id")
//获取通道
channel := query.Get("channel")
if c := FindChannel(id, channel); c != nil {
res, err := c.QueryPresetList()
if err == nil {
util.ReturnValue(res, w, r)
} else {
util.ReturnError(util.APIErrorInternal, err.Error(), w, r)
}
} else {
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
func (c *GB28181Config) API_preset_control(w http.ResponseWriter, r *http.Request) {
//CORS(w, r)
query := r.URL.Query()
//设备id
id := query.Get("id")
//获取通道
channel := query.Get("channel")
//获取cmd
ptzCmd := query.Get("cmd")
//获取点
point := query.Get("point")
if c := FindChannel(id, channel); c != nil {
_ptzCmd, _ := strconv.ParseInt(ptzCmd, 10, 16)
_point, _ := strconv.ParseInt(point, 10, 8)
code := c.PresetControl(int(_ptzCmd), byte(_point))
util.ReturnError(code, "device received", w, r)
} else {
util.ReturnError(util.APIErrorNotFound, fmt.Sprintf("device %q channel %q not found", id, channel), w, r)
}
}
@@ -234,8 +282,10 @@ func (c *GB28181Config) API_get_position(w http.ResponseWriter, r *http.Request)
query := r.URL.Query()
//设备id
id := query.Get("id")
util.ReturnJson(func() (list []*DevicePosition) {
if query.Get("interval") == "" {
query.Set("interval", fmt.Sprintf("%ds", c.Position.Interval.Seconds()))
}
util.ReturnFetchValue(func() (list []*DevicePosition) {
if id == "" {
Devices.Range(func(key, value interface{}) bool {
d := value.(*Device)
@@ -249,15 +299,5 @@ func (c *GB28181Config) API_get_position(w http.ResponseWriter, r *http.Request)
list = append(list, &DevicePosition{ID: d.ID, GpsTime: d.GpsTime, Longitude: d.Longitude, Latitude: d.Latitude})
}
return
}, c.Position.Interval, w, r)
}
func WriteJSONOk(w http.ResponseWriter, data interface{}) {
WriteJSON(w, data, 200)
}
func WriteJSON(w http.ResponseWriter, data interface{}, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}, w, r)
}

View File

@@ -7,13 +7,13 @@ import (
"strings"
"time"
"github.com/logrusorgru/aurora"
"go.uber.org/zap"
"m7s.live/plugin/gb28181/v4/utils"
"github.com/ghettovoice/gosip"
"github.com/ghettovoice/gosip/log"
"github.com/ghettovoice/gosip/sip"
"github.com/logrusorgru/aurora/v4"
"go.uber.org/zap"
. "m7s.live/engine/v4"
"m7s.live/plugin/gb28181/v4/utils"
)
var srv gosip.Server
@@ -119,7 +119,7 @@ func (c *GB28181Config) startServer() {
addr := c.ListenAddr + ":" + strconv.Itoa(int(c.SipPort))
logger := utils.NewZapLogger(GB28181Plugin.Logger, "GB SIP Server", nil)
logger.SetLevel(levelMap[c.LogLevel])
logger.SetLevel(uint32(levelMap[EngineConfig.LogLevel]))
// logger := log.NewDefaultLogrusLogger().WithPrefix("GB SIP Server")
srvConf := gosip.ServerConfig{}
if c.SipIP != "" {

View File

@@ -131,7 +131,7 @@ func (l *ZapLogger) Prefix() string {
return l.prefix
}
func (l *ZapLogger) WithFields(fields log.Fields) log.Logger {
func (l *ZapLogger) WithFields(fields map[string]interface{}) log.Logger {
return NewZapLogger(l.log, l.Prefix(), l.Fields().WithFields(fields))
}
@@ -154,6 +154,6 @@ func (l *ZapLogger) prepareEntry() *zap.SugaredLogger {
return newlog.Sugar()
}
func (l *ZapLogger) SetLevel(level log.Level) {
l.level = level
func (l *ZapLogger) SetLevel(level uint32) {
l.level = log.Level(level)
}