feat: 支持ip转地址

This commit is contained in:
ydajiang
2025-10-31 17:17:52 +08:00
parent 4f4fc016f4
commit f351a10819
9 changed files with 134 additions and 26 deletions

View File

@@ -39,10 +39,12 @@ func (api *ApiServer) OnDeviceList(q *QueryDeviceChannel, _ http.ResponseWriter,
}
response := struct {
DeviceCount int
DeviceList_ []LiveGBSDevice `json:"DeviceList"`
DeviceCount int
DeviceList_ []LiveGBSDevice `json:"DeviceList"`
DeviceRegion bool
}{
DeviceCount: total,
DeviceCount: total,
DeviceRegion: common.Config.IP2RegionEnable,
}
// livgbs设备离线后的最后心跳时间, 涉及到是否显示非法设备的批量删除按钮
@@ -89,8 +91,8 @@ func (api *ApiServer) OnDeviceList(q *QueryDeviceChannel, _ http.ResponseWriter,
KeepOriginalTree: false,
LastKeepaliveAt: lastKeealiveTime,
LastRegisterAt: device.RegisterTime.Format("2006-01-02 15:04:05"),
Latitude: 0,
Longitude: 0,
Latitude: device.Latitude,
Longitude: device.Longitude,
//Manufacturer: device.Manufacturer,
Manufacturer: device.UserAgent,
MediaTransport: device.GetSetup().Transport(),
@@ -105,7 +107,7 @@ func (api *ApiServer) OnDeviceList(q *QueryDeviceChannel, _ http.ResponseWriter,
RecvStreamIP: "",
RemoteIP: device.RemoteIP,
RemotePort: device.RemotePort,
RemoteRegion: "",
RemoteRegion: device.RemoteRegion,
SMSGroupID: "",
SMSID: "",
StreamMode: "",

View File

@@ -221,6 +221,10 @@ func (api *ApiServer) OnSetBaseConfig(baseConfig *BaseConfig, _ http.ResponseWri
return nil, err
}
// ip库只在启动时加载
newConfig.IP2RegionEnable = common.Config.IP2RegionEnable
newConfig.IP2RegionDBPath = common.Config.IP2RegionDBPath
// 重启sip服务
if sipChanged {
log.Sugar.Infof("重启sip服务器 port: %d", baseConfig.Port)

View File

@@ -45,6 +45,9 @@ type Config_ struct {
Position string `json:"position"`
OnInvite string `json:"on_invite"`
}
IP2RegionDBPath string
IP2RegionEnable bool
}
type LogConfig struct {
@@ -84,6 +87,8 @@ func ParseConfig(path string) (*Config_, error) {
SubPTZGlobalInterval: load.Section("sip").Key("sub_ptz_global_interval").MustInt(),
DeviceDefaultMediaTransport: load.Section("sip").Key("device_default_media_transport").String(),
GlobalDropChannelType: load.Section("sip").Key("global_drop_channel_type").String(),
IP2RegionDBPath: load.Section("ip2region").Key("db_path").String(),
IP2RegionEnable: load.Section("ip2region").Key("enable").MustBool(),
}
config_.Hooks.Online = load.Section("hooks").Key("online").String()

65
common/ip2region.go Normal file
View File

@@ -0,0 +1,65 @@
package common
import (
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
"strings"
)
var (
searcher *xdb.Searcher
)
func LoadIP2RegionDB(path string) error {
// 1、从 dbPath 加载整个 xdb 到内存
cBuff, err := xdb.LoadContentFromFile(path)
if err != nil {
return err
}
// 2、用全局的 cBuff 创建完全基于内存的查询对象。
searcher, err = xdb.NewWithBuffer(xdb.IPv4, cBuff)
if err != nil {
return err
}
return nil
}
func IP2Region(ip string) (string, error) {
// 3、查询
region, err := searcher.SearchByStr(ip)
if err != nil {
return "", err
}
// 合并成一个地址
var addressList []string
for _, address := range strings.Split(region, "|") {
if address == "" || address == "中国" || address == "0" {
continue
}
var same bool
for _, s := range addressList {
if s == address {
same = true
break
}
}
if same {
continue
}
addressList = append(addressList, address)
}
if length := len(addressList); length == 0 {
return "", nil
} else if length > 1 {
// 最后一个地址空格分开
addressList[length-2] += " "
}
return strings.Join(addressList, ""), nil
}

View File

@@ -18,7 +18,7 @@ alarm_reserve_days = 3
# invite超时时间, 单位秒
invite_timeout = 10
# udp/passive/active, 优先级小于设备的setup字段
device_default_media_transport = active
device_default_media_transport = passive
# 媒体服务器地址
media_server = http://0.0.0.0:8080
# 前端拉流优先使用的流格式, FLV/WS_FLV/WEBRTC/RTMP/HLS
@@ -32,22 +32,21 @@ sub_position_global_interval = 3600
# 全局订阅PTZ
sub_ptz_global_interval = 3600
# 全局过滤通道类型, 逗号分隔
global_drop_channel_type =
global_drop_channel_type =
[http]
port = 9000
[hooks]
online =
offline =
position =
online =
offline =
position =
# 被邀请, 用于通知1078信令服务器, 向设备下发推流指令
on_invite = http://localhost:8081/api/v1/jt1078/on_invite
# 被查询录像,用于通知1078信令服务器
on_query_record =
on_query_record =
[subscribe]
alarm = 3600
catalog = 3600
ptz = 3600
position = 3600
[ip2region]
# ip2region数据库路径, 更新地址: https://github.com/lionsoul2014/ip2region/tree/master/data
db_path = ip2region_v4.xdb
enable = 1

View File

@@ -2,6 +2,7 @@ package dao
import (
"gb-cms/common"
"gb-cms/log"
"gorm.io/gorm"
"net"
"strconv"
@@ -19,6 +20,7 @@ type DeviceModel struct {
Name string `json:"name" gorm:"index"`
RemoteIP string `json:"remote_ip"`
RemotePort int `json:"remote_port"`
RemoteRegion string `json:"remote_region"`
Transport string `json:"transport"` // 信令传输模式 UDP/TCP
Status common.OnlineStatus `json:"status"` // 在线状态 ON-在线/OFF-离线
Manufacturer string `json:"manufacturer"`
@@ -86,17 +88,26 @@ func (d *daoDevice) LoadDevices() (map[string]*DeviceModel, error) {
}
func (d *daoDevice) SaveDevice(device *DeviceModel) error {
return DBTransaction(func(tx *gorm.DB) error {
old := DeviceModel{}
if db.Select("id").Where("device_id =?", device.DeviceID).Take(&old).Error == nil {
device.ID = old.ID
old := DeviceModel{}
if db.Select("id", "remote_ip", "remote_region").Where("device_id =?", device.DeviceID).Take(&old).Error == nil {
device.ID = old.ID
}
if common.Config.IP2RegionEnable && (old.RemoteRegion == "" || (old.RemoteIP != "" && old.RemoteIP != device.RemoteIP)) {
region, err := common.IP2Region(device.RemoteIP)
if err != nil {
log.Sugar.Errorf("IP2Region failed. err: %s", err.Error())
}
device.RemoteRegion = region
}
return DBTransaction(func(tx *gorm.DB) error {
if device.ID == 0 {
//return tx.Create(&old).Error
return tx.Save(device).Error
} else {
return tx.Model(device).Select("Transport", "RemoteIP", "RemotePort", "Status", "RegisterTime", "LastHeartbeat").Updates(*device).Error
return tx.Model(device).Select("transport", "remote_ip", "remote_port", "status", "register_time", "last_heartbeat", "remote_region").Updates(*device).Error
}
})
}
@@ -127,17 +138,29 @@ func (d *daoDevice) UpdateDeviceStatus(deviceId string, status common.OnlineStat
}
func (d *daoDevice) RefreshHeartbeat(deviceId string, now time.Time, addr string) error {
if tx := db.Select("id").Take(&DeviceModel{}, "device_id =?", deviceId); tx.Error != nil {
old := DeviceModel{}
if tx := db.Select("id", "remote_ip", "remote_region").Take(&old, "device_id =?", deviceId); tx.Error != nil {
return tx.Error
}
host, p, _ := net.SplitHostPort(addr)
var region = old.RemoteRegion
if common.Config.IP2RegionEnable && (old.RemoteRegion == "" || (old.RemoteIP != "" && old.RemoteIP != host)) {
var err error
region, err = common.IP2Region(host)
if err != nil {
log.Sugar.Errorf("IP2Region failed. err: %s", err.Error())
}
}
return DBTransaction(func(tx *gorm.DB) error {
host, p, _ := net.SplitHostPort(addr)
port, _ := strconv.Atoi(p)
return tx.Model(&DeviceModel{}).Select("LastHeartbeat", "Status", "RemoteIP", "RemotePort").Where("device_id =?", deviceId).Updates(&DeviceModel{
return tx.Model(&DeviceModel{}).Select("last_heartbeat", "status", "remote_ip", "remote_port", "remote_region").Where("device_id =?", deviceId).Updates(&DeviceModel{
LastHeartbeat: now,
Status: common.ON,
RemoteIP: host,
RemotePort: port,
RemoteRegion: region,
}).Error
})
}

3
go.mod
View File

@@ -45,7 +45,6 @@ require (
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
@@ -58,9 +57,11 @@ require (
github.com/go-co-op/gocron/v2 v2.16.6
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20251031035847-91e542de380a
github.com/lkmio/avformat v0.0.1
github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
github.com/shirou/gopsutil/v3 v3.24.5
gopkg.in/ini.v1 v1.67.0
gorm.io/gorm v1.26.1
)

BIN
ip2region_v4.xdb Normal file

Binary file not shown.

View File

@@ -254,4 +254,13 @@ func Start() {
)
s.Start()
// 加载ip2region数据库
if common.Config.IP2RegionEnable {
err := common.LoadIP2RegionDB(common.Config.IP2RegionDBPath)
if err != nil {
common.Config.IP2RegionEnable = false
log.Sugar.Errorf("加载ip2region数据库失败. err: %s", err.Error())
}
}
}