mirror of
https://github.com/gowvp/gb28181.git
synced 2025-10-04 15:12:50 +08:00
删除设备的同时清理通道
This commit is contained in:
@@ -19,18 +19,18 @@ version = 1
|
|||||||
SlowThreshold = '200ms'
|
SlowThreshold = '200ms'
|
||||||
|
|
||||||
[Sip]
|
[Sip]
|
||||||
Port = 15062
|
Port = 15060
|
||||||
ID = "3402000000200000001"
|
ID = "3402000000200000001"
|
||||||
Domain = "3402000000"
|
Domain = "3402000000"
|
||||||
Password = "12345678"
|
Password = ""
|
||||||
|
|
||||||
[Media]
|
[Media]
|
||||||
IP = "127.0.0.1"
|
IP = "127.0.0.1"
|
||||||
HTTPPort = 8080
|
HTTPPort = 8080
|
||||||
Secret = "s1kPE7bzqKeHUaVcp8dCA0jeB8yxyFq4"
|
Secret = "s1kPE7bzqKeHUaVcp8dCA0jeB8yxyFq4"
|
||||||
WebHookIP = "host.docker.internal"
|
WebHookIP = "192.168.1.10"
|
||||||
RTPPortRange = "20000-20500"
|
RTPPortRange = "20000-20500"
|
||||||
SDPIP = "192.168.10.14"
|
SDPIP = "192.168.1.10"
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
# 日志存储目录,不能使用特殊符号
|
# 日志存储目录,不能使用特殊符号
|
||||||
@@ -40,6 +40,6 @@ version = 1
|
|||||||
# 保留日志多久,超过时间自动删除
|
# 保留日志多久,超过时间自动删除
|
||||||
MaxAge = '744h0m0s'
|
MaxAge = '744h0m0s'
|
||||||
# 多久时间,分割一个新的日志文件
|
# 多久时间,分割一个新的日志文件
|
||||||
RotationTime = '8h0m0s'
|
RotationTime = '12h0m0s'
|
||||||
# 多大文件,分割一个新的日志文件(MB)
|
# 多大文件,分割一个新的日志文件(MB)
|
||||||
RotationSize = 50
|
RotationSize = 50
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/ixugo/goweb/pkg/orm"
|
"github.com/ixugo/goweb/pkg/orm"
|
||||||
"github.com/ixugo/goweb/pkg/web"
|
"github.com/ixugo/goweb/pkg/web"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeviceStorer Instantiation interface
|
// DeviceStorer Instantiation interface
|
||||||
@@ -18,6 +19,8 @@ type DeviceStorer interface {
|
|||||||
Add(context.Context, *Device) error
|
Add(context.Context, *Device) error
|
||||||
Edit(context.Context, *Device, func(*Device), ...orm.QueryOption) error
|
Edit(context.Context, *Device, func(*Device), ...orm.QueryOption) error
|
||||||
Del(context.Context, *Device, ...orm.QueryOption) error
|
Del(context.Context, *Device, ...orm.QueryOption) error
|
||||||
|
|
||||||
|
Session(ctx context.Context, changeFns ...func(*gorm.DB) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindDevice Paginated search
|
// FindDevice Paginated search
|
||||||
@@ -96,9 +99,9 @@ func (c Core) EditDevice(ctx context.Context, in *EditDeviceInput, id string) (*
|
|||||||
|
|
||||||
// DelDevice Delete object
|
// DelDevice Delete object
|
||||||
func (c Core) DelDevice(ctx context.Context, id string) (*Device, error) {
|
func (c Core) DelDevice(ctx context.Context, id string) (*Device, error) {
|
||||||
var out Device
|
var dev Device
|
||||||
if err := c.store.Device().Del(ctx, &out, orm.Where("id=?", id)); err != nil {
|
if err := c.store.Device().Del(ctx, &dev, orm.Where("id=?", id)); err != nil {
|
||||||
return nil, web.ErrDB.Withf(`Del err[%s]`, err.Error())
|
return nil, web.ErrDB.Withf(`Del err[%s]`, err.Error())
|
||||||
}
|
}
|
||||||
return &out, nil
|
return &dev, nil
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
_ gbs.MemoryStorer = &Cache{}
|
_ gbs.MemoryStorer = &Cache{}
|
||||||
_ gb28181.Storer = &Cache{}
|
_ gb28181.Storer = &Cache{}
|
||||||
_ gb28181.DeviceStorer = &Cache{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
@@ -26,33 +25,12 @@ type Cache struct {
|
|||||||
devices *conc.Map[string, *gbs.Device]
|
devices *conc.Map[string, *gbs.Device]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add implements gb28181.DeviceStorer.
|
|
||||||
func (c *Cache) Add(ctx context.Context, d *gb28181.Device) error {
|
|
||||||
return c.Storer.Device().Add(ctx, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Del implements gb28181.DeviceStorer.
|
|
||||||
func (c *Cache) Del(ctx context.Context, d *gb28181.Device, opts ...orm.QueryOption) error {
|
|
||||||
return c.Storer.Device().Del(ctx, d, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edit implements gb28181.DeviceStorer.
|
|
||||||
func (c *Cache) Edit(ctx context.Context, d *gb28181.Device, changeFn func(*gb28181.Device), opts ...orm.QueryOption) error {
|
|
||||||
return c.Storer.Device().Edit(ctx, d, changeFn, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find implements gb28181.DeviceStorer.
|
|
||||||
func (c *Cache) Find(ctx context.Context, d *[]*gb28181.Device, pager orm.Pager, opts ...orm.QueryOption) (int64, error) {
|
|
||||||
return c.Storer.Device().Find(ctx, d, pager, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get implements gb28181.DeviceStorer.
|
|
||||||
func (c *Cache) Get(ctx context.Context, d *gb28181.Device, opts ...orm.QueryOption) error {
|
|
||||||
return c.Storer.Device().Get(ctx, d, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) Device() gb28181.DeviceStorer {
|
func (c *Cache) Device() gb28181.DeviceStorer {
|
||||||
return c
|
return (*Device)(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Channel() gb28181.ChannelStorer {
|
||||||
|
return (*Channel)(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCache(store gb28181.Storer) *Cache {
|
func NewCache(store gb28181.Storer) *Cache {
|
||||||
@@ -76,15 +54,15 @@ func (c *Cache) LoadDeviceToMemory(conn sip.Connection) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev := gbs.NewDevice(conn, d)
|
||||||
|
if dev != nil {
|
||||||
|
slog.Debug("load device to memory", "device_id", d.DeviceID, "to", dev.To())
|
||||||
channels := make([]*gb28181.Channel, 0, 8)
|
channels := make([]*gb28181.Channel, 0, 8)
|
||||||
_, err := c.Storer.Channel().Find(context.TODO(), &channels, web.NewPagerFilterMaxSize(), orm.Where("device_id=?", d.DeviceID))
|
_, err := c.Storer.Channel().Find(context.TODO(), &channels, web.NewPagerFilterMaxSize(), orm.Where("device_id=?", d.DeviceID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
dev.LoadChannels(channels...)
|
||||||
dev := gbs.NewDevice(conn, d, channels)
|
|
||||||
if dev != nil {
|
|
||||||
slog.Debug("load device to memory", "device_id", d.DeviceID, "to", dev.To())
|
|
||||||
c.devices.Store(d.DeviceID, dev)
|
c.devices.Store(d.DeviceID, dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
internal/core/gb28181/store/gb28181cache/channel.go
Normal file
49
internal/core/gb28181/store/gb28181cache/channel.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package gb28181cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gowvp/gb28181/internal/core/gb28181"
|
||||||
|
"github.com/ixugo/goweb/pkg/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ gb28181.ChannelStorer = &Channel{}
|
||||||
|
|
||||||
|
type Channel Cache
|
||||||
|
|
||||||
|
// Add implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) Add(ctx context.Context, ch *gb28181.Channel) error {
|
||||||
|
if err := c.Storer.Channel().Add(ctx, ch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dev, ok := c.devices.Load(ch.DeviceID)
|
||||||
|
if ok {
|
||||||
|
dev.LoadChannels(ch)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchEdit implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) BatchEdit(ctx context.Context, field string, value any, opts ...orm.QueryOption) error {
|
||||||
|
return c.Storer.Channel().BatchEdit(ctx, field, value, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Del implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) Del(ctx context.Context, ch *gb28181.Channel, opts ...orm.QueryOption) error {
|
||||||
|
return c.Storer.Channel().Del(ctx, ch, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) Edit(ctx context.Context, ch *gb28181.Channel, changeFn func(*gb28181.Channel), opts ...orm.QueryOption) error {
|
||||||
|
return c.Storer.Channel().Edit(ctx, ch, changeFn, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) Find(ctx context.Context, chs *[]*gb28181.Channel, pager orm.Pager, opts ...orm.QueryOption) (int64, error) {
|
||||||
|
return c.Storer.Channel().Find(ctx, chs, pager, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements gb28181.ChannelStorer.
|
||||||
|
func (c *Channel) Get(ctx context.Context, ch *gb28181.Channel, opts ...orm.QueryOption) error {
|
||||||
|
return c.Storer.Channel().Get(ctx, ch, opts...)
|
||||||
|
}
|
66
internal/core/gb28181/store/gb28181cache/device.go
Normal file
66
internal/core/gb28181/store/gb28181cache/device.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package gb28181cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gowvp/gb28181/internal/core/gb28181"
|
||||||
|
"github.com/gowvp/gb28181/pkg/gbs"
|
||||||
|
"github.com/ixugo/goweb/pkg/orm"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ gb28181.DeviceStorer = &Device{}
|
||||||
|
|
||||||
|
type Device Cache
|
||||||
|
|
||||||
|
// Add implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Add(ctx context.Context, dev *gb28181.Device) error {
|
||||||
|
if err := d.Storer.Device().Add(ctx, dev); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.devices.LoadOrStore(dev.DeviceID, gbs.NewDevice(nil, dev))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Del implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Del(ctx context.Context, dev *gb28181.Device, opts ...orm.QueryOption) error {
|
||||||
|
if err := d.Storer.Device().Session(
|
||||||
|
ctx,
|
||||||
|
func(tx *gorm.DB) error {
|
||||||
|
db := tx.Clauses(clause.Returning{})
|
||||||
|
for _, fn := range opts {
|
||||||
|
db = fn(db)
|
||||||
|
}
|
||||||
|
return db.Delete(dev).Error
|
||||||
|
},
|
||||||
|
func(tx *gorm.DB) error {
|
||||||
|
return tx.Model(&gb28181.Channel{}).Where("did=?", dev.ID).Delete(nil).Error
|
||||||
|
},
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.devices.Delete(dev.DeviceID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Edit(ctx context.Context, dev *gb28181.Device, changeFn func(*gb28181.Device), opts ...orm.QueryOption) error {
|
||||||
|
return d.Storer.Device().Edit(ctx, dev, changeFn, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Find(ctx context.Context, devs *[]*gb28181.Device, pager orm.Pager, opts ...orm.QueryOption) (int64, error) {
|
||||||
|
return d.Storer.Device().Find(ctx, devs, pager, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Get(ctx context.Context, dev *gb28181.Device, opts ...orm.QueryOption) error {
|
||||||
|
return d.Storer.Device().Get(ctx, dev, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Session implements gb28181.DeviceStorer.
|
||||||
|
func (d *Device) Session(ctx context.Context, changeFns ...func(*gorm.DB) error) error {
|
||||||
|
return d.Storer.Device().Session(ctx, changeFns...)
|
||||||
|
}
|
@@ -2,7 +2,6 @@ package gbs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
@@ -70,9 +69,10 @@ func (g GB28181API) sipMessageCatalog(ctx *sip.Context) {
|
|||||||
// QueryCatalog 设备目录查询或订阅请求
|
// QueryCatalog 设备目录查询或订阅请求
|
||||||
// GB/T28181 81 页 A.2.4.3
|
// GB/T28181 81 页 A.2.4.3
|
||||||
func (g *GB28181API) QueryCatalog(deviceID string) error {
|
func (g *GB28181API) QueryCatalog(deviceID string) error {
|
||||||
|
slog.Debug("QueryCatalog", "deviceID", deviceID)
|
||||||
ipc, ok := g.svr.memoryStorer.Load(deviceID)
|
ipc, ok := g.svr.memoryStorer.Load(deviceID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("device not found")
|
return ErrDeviceOffline
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := g.svr.wrapRequest(ipc, sip.MethodMessage, &sip.ContentTypeXML, sip.GetCatalogXML(deviceID))
|
_, err := g.svr.wrapRequest(ipc, sip.MethodMessage, &sip.ContentTypeXML, sip.GetCatalogXML(deviceID))
|
||||||
|
@@ -21,13 +21,14 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
channels conc.Map[string, *Channel]
|
Channels conc.Map[string, *Channel]
|
||||||
|
|
||||||
registerWithKeepaliveMutex sync.Mutex
|
registerWithKeepaliveMutex sync.Mutex
|
||||||
// 播放互斥锁也可以移动到 channel 属性
|
// 播放互斥锁也可以移动到 channel 属性
|
||||||
playMutex sync.Mutex
|
playMutex sync.Mutex
|
||||||
|
|
||||||
IsOnline bool
|
IsOnline bool
|
||||||
|
Address string
|
||||||
|
|
||||||
conn sip.Connection
|
conn sip.Connection
|
||||||
source net.Addr
|
source net.Addr
|
||||||
@@ -38,7 +39,7 @@ type Device struct {
|
|||||||
Expires int
|
Expires int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDevice(conn sip.Connection, d *gb28181.Device, channels []*gb28181.Channel) *Device {
|
func NewDevice(conn sip.Connection, d *gb28181.Device) *Device {
|
||||||
uri, err := sip.ParseURI(fmt.Sprintf("sip:%s@%s", d.DeviceID, d.Address))
|
uri, err := sip.ParseURI(fmt.Sprintf("sip:%s@%s", d.DeviceID, d.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("parse uri", "err", err, "did", d.ID)
|
slog.Error("parse uri", "err", err, "did", d.ID)
|
||||||
@@ -58,20 +59,24 @@ func NewDevice(conn sip.Connection, d *gb28181.Device, channels []*gb28181.Chann
|
|||||||
URI: uri,
|
URI: uri,
|
||||||
Params: sip.NewParams(),
|
Params: sip.NewParams(),
|
||||||
},
|
},
|
||||||
|
Address: d.Address,
|
||||||
LastKeepaliveAt: d.KeepaliveAt.Time,
|
LastKeepaliveAt: d.KeepaliveAt.Time,
|
||||||
LastRegisterAt: d.RegisteredAt.Time,
|
LastRegisterAt: d.RegisteredAt.Time,
|
||||||
IsOnline: d.IsOnline,
|
IsOnline: d.IsOnline,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) LoadChannels(channels ...*gb28181.Channel) {
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
ch := Channel{
|
ch := Channel{
|
||||||
ChannelID: channel.ChannelID,
|
ChannelID: channel.ChannelID,
|
||||||
device: &c,
|
device: d,
|
||||||
}
|
}
|
||||||
ch.init(d.Address)
|
ch.init(d.Address)
|
||||||
c.channels.Store(channel.ChannelID, &ch)
|
d.Channels.Store(channel.ChannelID, &ch)
|
||||||
}
|
}
|
||||||
return &c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conn implements Targeter.
|
// Conn implements Targeter.
|
||||||
@@ -164,7 +169,7 @@ func newDevice(network, address string, conn sip.Connection) *Device {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
func (c *Device) GetChannel(channelID string) (*Channel, bool) {
|
func (c *Device) GetChannel(channelID string) (*Channel, bool) {
|
||||||
return c.channels.Load(channelID)
|
return c.Channels.Load(channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (c *Client) Delete(deviceID string) {
|
// func (c *Client) Delete(deviceID string) {
|
||||||
|
Reference in New Issue
Block a user