mirror of
https://github.com/gowvp/gb28181.git
synced 2025-09-27 03:45:57 +08:00
更新镜像
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
|
|
||||||
RUN apk --no-cache add ca-certificates \
|
RUN apk --no-cache add ca-certificates \
|
||||||
@@ -7,7 +9,7 @@ RUN apk --no-cache add ca-certificates \
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ADD ./build/linux_amd64/bin ./
|
ADD ./build/linux_${TARGETARCH}/bin ./
|
||||||
ADD ./configs/config.toml /app/configs/config.toml
|
ADD ./configs/config.toml /app/configs/config.toml
|
||||||
ADD ./www /app/www
|
ADD ./www /app/www
|
||||||
|
|
||||||
|
11
Makefile
11
Makefile
@@ -158,6 +158,12 @@ BUILD_LINUX_AMD64_DIR := ./build/linux_amd64
|
|||||||
build/linux:
|
build/linux:
|
||||||
$(eval GOARCH := amd64)
|
$(eval GOARCH := amd64)
|
||||||
$(eval GOOS := linux)
|
$(eval GOOS := linux)
|
||||||
|
$(eval dir := $(BUILD_DIR_ROOT)/$(GOOS)_$(GOARCH))
|
||||||
|
@make build/local GOOS=$(GOOS) GOARCH=$(GOARCH)
|
||||||
|
|
||||||
|
$(eval GOARCH := arm64)
|
||||||
|
$(eval GOOS := linux)
|
||||||
|
$(eval dir := $(BUILD_DIR_ROOT)/$(GOOS)_$(GOARCH))
|
||||||
@make build/local GOOS=$(GOOS) GOARCH=$(GOARCH)
|
@make build/local GOOS=$(GOOS) GOARCH=$(GOARCH)
|
||||||
|
|
||||||
## build/windows: 构建 windows 应用
|
## build/windows: 构建 windows 应用
|
||||||
@@ -178,7 +184,10 @@ docker/push:
|
|||||||
@docker push $(IMAGE_NAME)
|
@docker push $(IMAGE_NAME)
|
||||||
|
|
||||||
docker/build/full:
|
docker/build/full:
|
||||||
@docker build --force-rm=true --platform linux/amd64 -t $(IMAGE_NAME) -f Dockerfile_full .
|
@docker build --force-rm=true --push --platform linux/amd64,linux/arm64 -t $(IMAGE_NAME) -f Dockerfile_full .
|
||||||
|
|
||||||
|
docker/build/gowvp: build/clean build/linux
|
||||||
|
@docker build --force-rm=true --push --platform linux/amd64,linux/arm64 -t registry.cn-shanghai.aliyuncs.com/ixugo/gowvp:latest -f Dockerfile .
|
||||||
|
|
||||||
|
|
||||||
# ==================================================================================== #
|
# ==================================================================================== #
|
||||||
|
82
README.md
82
README.md
@@ -36,8 +36,6 @@ go wvp 是 Go 语言实现的开源 GB28181 解决方案,基于 GB28181-2022
|
|||||||
|
|
||||||
项目框架基于 @ixugo [goweb](https://github.com/ixugo/goweb)
|
项目框架基于 @ixugo [goweb](https://github.com/ixugo/goweb)
|
||||||
|
|
||||||
Java 语言 WVP @648540858 [wvp-GB28181-pro](https://github.com/648540858/wvp-GB28181-pro)
|
|
||||||
|
|
||||||
## QA
|
## QA
|
||||||
|
|
||||||
> 怎么没有前端资源? 如何加载网页呢?
|
> 怎么没有前端资源? 如何加载网页呢?
|
||||||
@@ -92,9 +90,54 @@ ZLM使用文档 [github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
### 视频指南
|
||||||
|
|
||||||
|
[如何构建或运行项目](https://www.bilibili.com/video/BV1QLQeYHEXb)
|
||||||
|
|
||||||
|
[如何用 docker compose 部署项目](https://www.bilibili.com/video/BV112QYY3EZX)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[docker hub](https://hub.docker.com/r/gospace/gowvp)
|
[docker hub](https://hub.docker.com/r/gospace/gowvp)
|
||||||
|
|
||||||
** gowvp & zlmediakit 融合镜像**
|
** gowvp & zlmediakit 分开镜像(推荐)**
|
||||||
|
|
||||||
|
```yml
|
||||||
|
services:
|
||||||
|
gowvp:
|
||||||
|
image: registry.cn-shanghai.aliyuncs.com/ixugo/gowvp:latest
|
||||||
|
ports:
|
||||||
|
- 15123:15123 # 管理平台 http 端口
|
||||||
|
- 15060:15060 # gb28181 sip tcp 端口
|
||||||
|
- 15060:15060/udp # gb28181 sip udp 端口
|
||||||
|
volumes:
|
||||||
|
# - ./logs:/app/logs # 如果需要持久化日志,请取消注释
|
||||||
|
- ./configs:/app/configs
|
||||||
|
depends_on:
|
||||||
|
- zlm
|
||||||
|
zlm:
|
||||||
|
image: zlmediakit/zlmediakit:master
|
||||||
|
restart: always
|
||||||
|
# 推荐 linux 主机使用 host 模式
|
||||||
|
# network_mode: host
|
||||||
|
ports:
|
||||||
|
- 1935:1935 # rtmp
|
||||||
|
- 554:554 # rtsp
|
||||||
|
- 8080:80 # api
|
||||||
|
- 8443:443
|
||||||
|
- 10000:10000
|
||||||
|
- 10000:10000/udp
|
||||||
|
- 8000:8000/udp
|
||||||
|
- 9000:9000/udp
|
||||||
|
- 20050-20100:20050-20100
|
||||||
|
- 20050-20100:20050-20100/udp
|
||||||
|
volumes:
|
||||||
|
- ./configs:/opt/media/conf
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
** gowvp & zlmediakit 融合镜像(不推荐)**
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
```yml
|
```yml
|
||||||
services:
|
services:
|
||||||
@@ -119,39 +162,6 @@ services:
|
|||||||
- ./zlm.conf:/opt/media/conf
|
- ./zlm.conf:/opt/media/conf
|
||||||
```
|
```
|
||||||
|
|
||||||
** gowvp & zlmediakit 分开镜像**
|
|
||||||
|
|
||||||
```yml
|
|
||||||
services:
|
|
||||||
gowvp:
|
|
||||||
image: registry.cn-shanghai.aliyuncs.com/ixugo/gowvp:latest
|
|
||||||
ports:
|
|
||||||
- 15123:15123 # 管理平台 http 端口
|
|
||||||
- 15060:15060 # gb28181 sip tcp 端口
|
|
||||||
- 15060:15060/udp # gb28181 sip udp 端口
|
|
||||||
volumes:
|
|
||||||
- ./logs:/app/logs
|
|
||||||
- ./configs:/app/configs
|
|
||||||
zlm:
|
|
||||||
image: zlmediakit/zlmediakit:master
|
|
||||||
restart: always
|
|
||||||
# 推荐 linux 主机使用 host 模式
|
|
||||||
# network_mode: host
|
|
||||||
ports:
|
|
||||||
- 1935:1935 # rtmp
|
|
||||||
- 554:554 # rtsp
|
|
||||||
- 8080:80 # api
|
|
||||||
- 8443:443
|
|
||||||
- 10000:10000
|
|
||||||
- 10000:10000/udp
|
|
||||||
- 8000:8000/udp
|
|
||||||
- 9000:9000/udp
|
|
||||||
- 20050-20100:20050-20100
|
|
||||||
- 20050-20100:20050-20100/udp
|
|
||||||
volumes:
|
|
||||||
- ./conf:/opt/media/conf
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -45,6 +46,7 @@ func main() {
|
|||||||
var bc conf.Bootstrap
|
var bc conf.Bootstrap
|
||||||
// 获取配置目录绝对路径
|
// 获取配置目录绝对路径
|
||||||
fileDir, _ := abs(*configDir)
|
fileDir, _ := abs(*configDir)
|
||||||
|
os.MkdirAll(fileDir, 0o755)
|
||||||
filePath := filepath.Join(fileDir, "config.toml")
|
filePath := filepath.Join(fileDir, "config.toml")
|
||||||
configIsNotExistWrite(filePath)
|
configIsNotExistWrite(filePath)
|
||||||
if err := conf.SetupConfig(&bc, filePath); err != nil {
|
if err := conf.SetupConfig(&bc, filePath); err != nil {
|
||||||
@@ -76,6 +78,14 @@ func main() {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secret, err := getSecret(*configDir)
|
||||||
|
if err == nil {
|
||||||
|
slog.Info("发现 zlm 配置,已赋值,未回写配置文件", "secret", secret)
|
||||||
|
bc.Media.Secret = secret
|
||||||
|
} else {
|
||||||
|
slog.Info("未发现 zlm 配置,请检查 config.ini 文件", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
handler, cleanUp, err := wireApp(&bc, log)
|
handler, cleanUp, err := wireApp(&bc, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("程序构建失败", "err", err)
|
slog.Error("程序构建失败", "err", err)
|
||||||
@@ -125,3 +135,17 @@ func configIsNotExistWrite(path string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 读取 config.ini 文件,通过正则表达式,获取 secret 的值
|
||||||
|
func getSecret(configDir string) (string, error) {
|
||||||
|
content, err := os.ReadFile(filepath.Join(system.Getwd(), configDir, "config.ini"))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
re := regexp.MustCompile(`secret=(\w+)`)
|
||||||
|
matches := re.FindStringSubmatch(string(content))
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return "", fmt.Errorf("secret not found")
|
||||||
|
}
|
||||||
|
return matches[1], nil
|
||||||
|
}
|
||||||
|
@@ -1,16 +1,25 @@
|
|||||||
version = 1
|
|
||||||
[Server]
|
[Server]
|
||||||
rtmpSecret = "123"
|
Debug = false
|
||||||
[Server.HTTP]
|
# rtmp 推流秘钥
|
||||||
Port = 15123
|
RTMPSecret = '123'
|
||||||
JwtSecret = ""
|
|
||||||
Timeout = "60s"
|
|
||||||
|
|
||||||
[Server.HTTP.Pprof]
|
# 对外提供的服务,建议由 nginx 代理
|
||||||
|
[Server.HTTP]
|
||||||
|
# http 端口
|
||||||
|
Port = 15123
|
||||||
|
# 请求超时时间
|
||||||
|
Timeout = '1m0s'
|
||||||
|
# jwt 秘钥,空串时,每次启动程序将随机赋值
|
||||||
|
JwtSecret = ''
|
||||||
|
|
||||||
|
[Server.HTTP.PProf]
|
||||||
|
# 是否启用 pprof, 建议设置为 true
|
||||||
Enabled = true
|
Enabled = true
|
||||||
|
# 访问白名单
|
||||||
AccessIps = ['::1', '127.0.0.1']
|
AccessIps = ['::1', '127.0.0.1']
|
||||||
|
|
||||||
[Data]
|
[Data]
|
||||||
|
# 数据库支持 sqlite 和 postgres 两种,使用 sqlite 时 dsn 应当填写文件存储路径
|
||||||
[Data.Database]
|
[Data.Database]
|
||||||
Dsn = './configs/data.db'
|
Dsn = './configs/data.db'
|
||||||
MaxIdleConns = 1
|
MaxIdleConns = 1
|
||||||
@@ -18,20 +27,6 @@ version = 1
|
|||||||
ConnMaxLifetime = '6h0m0s'
|
ConnMaxLifetime = '6h0m0s'
|
||||||
SlowThreshold = '200ms'
|
SlowThreshold = '200ms'
|
||||||
|
|
||||||
[Sip]
|
|
||||||
Port = 15060
|
|
||||||
ID = "3402000000200000001"
|
|
||||||
Domain = "3402000000"
|
|
||||||
Password = ""
|
|
||||||
|
|
||||||
[Media]
|
|
||||||
IP = "127.0.0.1"
|
|
||||||
HTTPPort = 8080
|
|
||||||
Secret = "s1kPE7bzqKeHUaVcp8dCA0jeB8yxyFq4"
|
|
||||||
WebHookIP = "192.168.1.10"
|
|
||||||
RTPPortRange = "20000-20500"
|
|
||||||
SDPIP = "192.168.1.10"
|
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
# 日志存储目录,不能使用特殊符号
|
# 日志存储目录,不能使用特殊符号
|
||||||
Dir = './logs'
|
Dir = './logs'
|
||||||
@@ -42,4 +37,28 @@ version = 1
|
|||||||
# 多久时间,分割一个新的日志文件
|
# 多久时间,分割一个新的日志文件
|
||||||
RotationTime = '12h0m0s'
|
RotationTime = '12h0m0s'
|
||||||
# 多大文件,分割一个新的日志文件(MB)
|
# 多大文件,分割一个新的日志文件(MB)
|
||||||
RotationSize = 50
|
RotationSize = 50
|
||||||
|
|
||||||
|
[Sip]
|
||||||
|
# 服务监听的 tcp/udp 端口号
|
||||||
|
Port = 15060
|
||||||
|
# gb/t28181 20 位国标 ID
|
||||||
|
ID = '3402000000200000001'
|
||||||
|
# 域
|
||||||
|
Domain = '3402000000'
|
||||||
|
# 注册密码
|
||||||
|
Password = ''
|
||||||
|
|
||||||
|
[Media]
|
||||||
|
# 媒体服务器 IP
|
||||||
|
IP = '127.0.0.1'
|
||||||
|
# 媒体服务器 HTTP 端口
|
||||||
|
HTTPPort = 8080
|
||||||
|
# 媒体服务器密钥
|
||||||
|
Secret = ''
|
||||||
|
# 用于流媒体 webhook 回调
|
||||||
|
WebHookIP = '192.168.1.10'
|
||||||
|
# 媒体服务器 RTP 端口范围
|
||||||
|
RTPPortRange = '20000-20500'
|
||||||
|
# 媒体服务器 SDP IP
|
||||||
|
SDPIP = '192.168.1.10'
|
@@ -5,4 +5,29 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: ./Dockerfile
|
dockerfile: ./Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- 18082:18081
|
- 15123:15123 # 管理平台 http 端口
|
||||||
|
- 15060:15060 # gb28181 sip tcp 端口
|
||||||
|
- 15060:15060/udp # gb28181 sip udp 端口
|
||||||
|
volumes:
|
||||||
|
- ./logs:/app/logs
|
||||||
|
- ./configs:/app/configs
|
||||||
|
depends_on:
|
||||||
|
- zlm
|
||||||
|
zlm:
|
||||||
|
image: zlmediakit/zlmediakit:master
|
||||||
|
restart: always
|
||||||
|
# 推荐 linux 主机使用 host 模式
|
||||||
|
# network_mode: host
|
||||||
|
ports:
|
||||||
|
- 1935:1935 # rtmp
|
||||||
|
- 554:554 # rtsp
|
||||||
|
- 8080:80 # api
|
||||||
|
- 8443:443
|
||||||
|
- 10000:10000
|
||||||
|
- 10000:10000/udp
|
||||||
|
- 8000:8000/udp
|
||||||
|
- 9000:9000/udp
|
||||||
|
- 20050-20100:20050-20100
|
||||||
|
- 20050-20100:20050-20100/udp
|
||||||
|
volumes:
|
||||||
|
- ./conf:/opt/media/conf
|
||||||
|
@@ -1,21 +1,24 @@
|
|||||||
services:
|
services:
|
||||||
gowvp:
|
gowvp:
|
||||||
image: gb28181
|
image: registry.cn-shanghai.aliyuncs.com/ixugo/gowvp:latest
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./Dockerfile
|
|
||||||
ports:
|
ports:
|
||||||
- 15123:15123 # 管理平台 http 端口
|
- 15123:15123 # 管理平台 http 端口
|
||||||
- 15060:15060 # gb28181 sip tcp 端口
|
- 15060:15060 # gb28181 sip tcp 端口
|
||||||
- 15060:15060/udp # gb28181 sip udp 端口
|
- 15060:15060/udp # gb28181 sip udp 端口
|
||||||
volumes:
|
volumes:
|
||||||
- ./logs:/app/logs
|
# - ./logs:/app/logs # 如果需要持久化日志,请取消注释
|
||||||
- ./configs:/app/configs
|
- ./configs:/app/configs
|
||||||
|
networks:
|
||||||
|
- gowvp-network
|
||||||
|
depends_on:
|
||||||
|
- zlm
|
||||||
zlm:
|
zlm:
|
||||||
image: zlmediakit/zlmediakit:master
|
image: zlmediakit/zlmediakit:master
|
||||||
restart: always
|
restart: always
|
||||||
# 推荐 linux 主机使用 host 模式
|
# 推荐 linux 主机使用 host 模式
|
||||||
# network_mode: host
|
# network_mode: host
|
||||||
|
networks:
|
||||||
|
- gowvp-network
|
||||||
ports:
|
ports:
|
||||||
- 1935:1935 # rtmp
|
- 1935:1935 # rtmp
|
||||||
- 554:554 # rtsp
|
- 554:554 # rtsp
|
||||||
@@ -28,4 +31,9 @@ services:
|
|||||||
- 20050-20100:20050-20100
|
- 20050-20100:20050-20100
|
||||||
- 20050-20100:20050-20100/udp
|
- 20050-20100:20050-20100/udp
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf:/opt/media/conf
|
- ./configs:/opt/media/conf
|
||||||
|
|
||||||
|
# 如果不使用 host 模式,可以使用下面的配置
|
||||||
|
networks:
|
||||||
|
gowvp-network:
|
||||||
|
driver: bridge
|
||||||
|
@@ -88,8 +88,9 @@ func (c *Cache) Change(deviceID string, changeFn func(*gb28181.Device), changeFn
|
|||||||
dev2.LastKeepaliveAt = dev.KeepaliveAt.Time
|
dev2.LastKeepaliveAt = dev.KeepaliveAt.Time
|
||||||
dev2.LastRegisterAt = dev.RegisteredAt.Time
|
dev2.LastRegisterAt = dev.RegisteredAt.Time
|
||||||
dev2.Expires = dev.Expires
|
dev2.Expires = dev.Expires
|
||||||
|
dev2.Password = dev.Password
|
||||||
|
dev2.Address = dev.Address
|
||||||
changeFn2(dev2)
|
changeFn2(dev2)
|
||||||
|
|
||||||
if !dev2.IsOnline {
|
if !dev2.IsOnline {
|
||||||
if err := c.Storer.Channel().BatchEdit(context.TODO(), "is_online", false, orm.Where("did=?", dev.ID)); err != nil {
|
if err := c.Storer.Channel().BatchEdit(context.TODO(), "is_online", false, orm.Where("did=?", dev.ID)); err != nil {
|
||||||
slog.Error("更新通道离线状态失败", "error", err)
|
slog.Error("更新通道离线状态失败", "error", err)
|
||||||
|
@@ -2,6 +2,7 @@ package gb28181cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/gowvp/gb28181/internal/core/gb28181"
|
"github.com/gowvp/gb28181/internal/core/gb28181"
|
||||||
"github.com/gowvp/gb28181/pkg/gbs"
|
"github.com/gowvp/gb28181/pkg/gbs"
|
||||||
@@ -12,7 +13,7 @@ import (
|
|||||||
|
|
||||||
var _ gb28181.DeviceStorer = &Device{}
|
var _ gb28181.DeviceStorer = &Device{}
|
||||||
|
|
||||||
type Device Cache
|
type Device = Cache
|
||||||
|
|
||||||
// Add implements gb28181.DeviceStorer.
|
// Add implements gb28181.DeviceStorer.
|
||||||
func (d *Device) Add(ctx context.Context, dev *gb28181.Device) error {
|
func (d *Device) Add(ctx context.Context, dev *gb28181.Device) error {
|
||||||
@@ -47,7 +48,23 @@ func (d *Device) Del(ctx context.Context, dev *gb28181.Device, opts ...orm.Query
|
|||||||
|
|
||||||
// Edit implements gb28181.DeviceStorer.
|
// Edit implements gb28181.DeviceStorer.
|
||||||
func (d *Device) Edit(ctx context.Context, dev *gb28181.Device, changeFn func(*gb28181.Device), opts ...orm.QueryOption) error {
|
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...)
|
if err := d.Storer.Device().Edit(ctx, dev, changeFn, opts...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dev2, ok := d.devices.Load(dev.DeviceID)
|
||||||
|
if !ok {
|
||||||
|
panic("edit device not found")
|
||||||
|
}
|
||||||
|
// 密码修改,设备需要重新注册
|
||||||
|
if dev2.Password != dev.Password && dev.Password != "" {
|
||||||
|
slog.Info("修改密码,设备离线")
|
||||||
|
d.Change(dev.DeviceID, func(d *gb28181.Device) {
|
||||||
|
d.Password = dev.Password
|
||||||
|
d.IsOnline = false
|
||||||
|
}, func(d *gbs.Device) {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find implements gb28181.DeviceStorer.
|
// Find implements gb28181.DeviceStorer.
|
||||||
|
@@ -54,7 +54,7 @@ func (c *Core) AddMediaServer(ctx context.Context, in *AddMediaServerInput) (*Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EditMediaServer Update object information
|
// EditMediaServer Update object information
|
||||||
func (c *Core) EditMediaServer(ctx context.Context, in *EditMediaServerInput, id string) (*MediaServer, error) {
|
func (c *Core) EditMediaServer(ctx context.Context, in *EditMediaServerInput, id string, serverPort int) (*MediaServer, error) {
|
||||||
var out MediaServer
|
var out MediaServer
|
||||||
if err := c.storer.MediaServer().Edit(ctx, &out, func(b *MediaServer) {
|
if err := c.storer.MediaServer().Edit(ctx, &out, func(b *MediaServer) {
|
||||||
if err := copier.Copy(b, in); err != nil {
|
if err := copier.Copy(b, in); err != nil {
|
||||||
@@ -63,6 +63,7 @@ func (c *Core) EditMediaServer(ctx context.Context, in *EditMediaServerInput, id
|
|||||||
}, orm.Where("id=?", id)); err != nil {
|
}, orm.Where("id=?", id)); err != nil {
|
||||||
return nil, web.ErrDB.Withf(`Edit err[%s]`, err.Error())
|
return nil, web.ErrDB.Withf(`Edit err[%s]`, err.Error())
|
||||||
}
|
}
|
||||||
|
c.connection(&out, serverPort)
|
||||||
return &out, nil
|
return &out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ type MediaServer struct {
|
|||||||
CreatedAt orm.Time `gorm:"column:created_at;notNull;default:CURRENT_TIMESTAMP" json:"created_at"`
|
CreatedAt orm.Time `gorm:"column:created_at;notNull;default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||||
UpdatedAt orm.Time `gorm:"column:updated_at;notNull;default:CURRENT_TIMESTAMP" json:"updated_at"`
|
UpdatedAt orm.Time `gorm:"column:updated_at;notNull;default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||||
HookIP string `gorm:"column:hook_ip;notNull;default:''" json:"hook_ip"`
|
HookIP string `gorm:"column:hook_ip;notNull;default:''" json:"hook_ip"`
|
||||||
SDPIP string `gorm:"column:sdpip;notNull;default:''" json:"sdpip"`
|
SDPIP string `gorm:"column:sdp_ip;notNull;default:''" json:"sdp_ip"`
|
||||||
StreamIP string `gorm:"column:stream_ip;notNull;default:''" json:"stream_ip"`
|
StreamIP string `gorm:"column:stream_ip;notNull;default:''" json:"stream_ip"`
|
||||||
Ports MediaServerPorts `gorm:"column:ports;notNull;default:'{}';type:jsonb" json:"ports"`
|
Ports MediaServerPorts `gorm:"column:ports;notNull;default:'{}';type:jsonb" json:"ports"`
|
||||||
AutoConfig bool `gorm:"column:auto_config;notNull;default:FALSE" json:"auto_config"`
|
AutoConfig bool `gorm:"column:auto_config;notNull;default:FALSE" json:"auto_config"`
|
||||||
|
@@ -30,25 +30,25 @@ type FindMediaServerInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EditMediaServerInput struct {
|
type EditMediaServerInput struct {
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
HookIP string `json:"hook_ip"`
|
HookIP string `json:"hook_ip"`
|
||||||
SDPIP string `json:"sdpip"`
|
SDPIP string `json:"sdpip"`
|
||||||
StreamIP string `json:"stream_ip"`
|
// StreamIP string `json:"stream_ip"`
|
||||||
Ports MediaServerPorts `json:"ports"`
|
// Ports MediaServerPorts `json:"ports"`
|
||||||
AutoConfig bool `json:"auto_config"`
|
// AutoConfig bool `json:"auto_config"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
HookAliveInterval int `json:"hook_alive_interval"`
|
// HookAliveInterval int `json:"hook_alive_interval"`
|
||||||
RTPEnable bool `json:"rtpenable"`
|
// RTPEnable bool `json:"rtpenable"`
|
||||||
Status bool `json:"status"`
|
// Status bool `json:"status"`
|
||||||
RTPPortRange string `json:"rtpport_range"`
|
// RTPPortRange string `json:"rtpport_range"`
|
||||||
SendRTPPortRange string `json:"send_rtpport_range"`
|
// SendRTPPortRange string `json:"send_rtpport_range"`
|
||||||
RecordAssistPort int `json:"record_assist_port"`
|
// RecordAssistPort int `json:"record_assist_port"`
|
||||||
LastKeepaliveAt orm.Time `json:"last_keepalive_at"`
|
// LastKeepaliveAt orm.Time `json:"last_keepalive_at"`
|
||||||
IsDefault bool `json:"is_default"`
|
// IsDefault bool `json:"is_default"`
|
||||||
RecordDay int `json:"record_day"`
|
// RecordDay int `json:"record_day"`
|
||||||
RecordPath string `json:"record_path"`
|
// RecordPath string `json:"record_path"`
|
||||||
Type string `json:"type"`
|
// Type string `json:"type"`
|
||||||
TranscodeSuffix string `json:"transcode_suffix"`
|
// TranscodeSuffix string `json:"transcode_suffix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddMediaServerInput struct {
|
type AddMediaServerInput struct {
|
||||||
|
@@ -126,10 +126,10 @@ func (n *NodeManager) connection(server *MediaServer, serverPort int) {
|
|||||||
|
|
||||||
log.Info("ZLM 服务节点连接中")
|
log.Info("ZLM 服务节点连接中")
|
||||||
|
|
||||||
for {
|
for i := range 10 {
|
||||||
resp, err := engine.GetServerConfig()
|
resp, err := engine.GetServerConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("ZLM 服务节点连接失败", "err", err)
|
log.Error("ZLM 服务节点连接失败", "err", err, "retry", i)
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ var startRuntime = time.Now()
|
|||||||
|
|
||||||
func setupRouter(r *gin.Engine, uc *Usecase) {
|
func setupRouter(r *gin.Engine, uc *Usecase) {
|
||||||
uc.GB28181API.uc = uc
|
uc.GB28181API.uc = uc
|
||||||
|
uc.SMSAPI.uc = uc
|
||||||
go stat.LoadTop(system.Getwd(), func(m map[string]any) {
|
go stat.LoadTop(system.Getwd(), func(m map[string]any) {
|
||||||
_ = m
|
_ = m
|
||||||
})
|
})
|
||||||
@@ -70,6 +71,7 @@ func setupRouter(r *gin.Engine, uc *Usecase) {
|
|||||||
registerGB28181(r, uc.GB28181API)
|
registerGB28181(r, uc.GB28181API)
|
||||||
registerProxy(r, uc.ProxyAPI)
|
registerProxy(r, uc.ProxyAPI)
|
||||||
registerConfig(r, uc.ConfigAPI)
|
registerConfig(r, uc.ConfigAPI)
|
||||||
|
registerSms(r, uc.SMSAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
type playOutput struct {
|
type playOutput struct {
|
||||||
|
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
type SmsAPI struct {
|
type SmsAPI struct {
|
||||||
smsCore sms.Core
|
smsCore sms.Core
|
||||||
|
uc *Usecase
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSMSCore(db *gorm.DB, cfg *conf.Bootstrap) sms.Core {
|
func NewSMSCore(db *gorm.DB, cfg *conf.Bootstrap) sms.Core {
|
||||||
@@ -31,10 +32,11 @@ func registerSms(g gin.IRouter, api SmsAPI, handler ...gin.HandlerFunc) {
|
|||||||
{
|
{
|
||||||
group := g.Group("/media_servers", handler...)
|
group := g.Group("/media_servers", handler...)
|
||||||
group.GET("", web.WarpH(api.findMediaServer))
|
group.GET("", web.WarpH(api.findMediaServer))
|
||||||
group.GET("/:id", web.WarpH(api.getMediaServer))
|
|
||||||
group.PUT("/:id", web.WarpH(api.editMediaServer))
|
group.PUT("/:id", web.WarpH(api.editMediaServer))
|
||||||
group.POST("", web.WarpH(api.addMediaServer))
|
|
||||||
group.DELETE("/:id", web.WarpH(api.delMediaServer))
|
// group.GET("/:id", web.WarpH(api.getMediaServer))
|
||||||
|
// group.POST("", web.WarpH(api.addMediaServer))
|
||||||
|
// group.DELETE("/:id", web.WarpH(api.delMediaServer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +54,20 @@ func (a SmsAPI) getMediaServer(c *gin.Context, _ *struct{}) (any, error) {
|
|||||||
|
|
||||||
func (a SmsAPI) editMediaServer(c *gin.Context, in *sms.EditMediaServerInput) (any, error) {
|
func (a SmsAPI) editMediaServer(c *gin.Context, in *sms.EditMediaServerInput) (any, error) {
|
||||||
mediaServerID := c.Param("id")
|
mediaServerID := c.Param("id")
|
||||||
return a.smsCore.EditMediaServer(c.Request.Context(), in, mediaServerID)
|
out, err := a.smsCore.EditMediaServer(c.Request.Context(), in, mediaServerID, a.uc.Conf.Server.HTTP.Port)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if mediaServerID == "local" {
|
||||||
|
a.uc.Conf.Media.IP = out.IP
|
||||||
|
a.uc.Conf.Media.SDPIP = out.SDPIP
|
||||||
|
a.uc.Conf.Media.Secret = out.Secret
|
||||||
|
a.uc.Conf.Media.WebHookIP = out.HookIP
|
||||||
|
if err := conf.WriteConfig(a.uc.Conf, a.uc.Conf.ConfigPath); err != nil {
|
||||||
|
return nil, web.ErrServer.Msg(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a SmsAPI) addMediaServer(c *gin.Context, in *sms.AddMediaServerInput) (any, error) {
|
func (a SmsAPI) addMediaServer(c *gin.Context, in *sms.AddMediaServerInput) (any, error) {
|
||||||
|
@@ -29,6 +29,7 @@ type Device struct {
|
|||||||
|
|
||||||
IsOnline bool
|
IsOnline bool
|
||||||
Address string
|
Address string
|
||||||
|
Password string
|
||||||
|
|
||||||
conn sip.Connection
|
conn sip.Connection
|
||||||
source net.Addr
|
source net.Addr
|
||||||
@@ -63,6 +64,7 @@ func NewDevice(conn sip.Connection, d *gb28181.Device) *Device {
|
|||||||
LastKeepaliveAt: d.KeepaliveAt.Time,
|
LastKeepaliveAt: d.KeepaliveAt.Time,
|
||||||
LastRegisterAt: d.RegisteredAt.Time,
|
LastRegisterAt: d.RegisteredAt.Time,
|
||||||
IsOnline: d.IsOnline,
|
IsOnline: d.IsOnline,
|
||||||
|
Password: d.Password,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &c
|
return &c
|
||||||
|
@@ -48,8 +48,9 @@ func (e Engine) SetConfig(cfg Config) Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) post(path string, data map[string]any, out any) error {
|
func (e *Engine) post(path string, data map[string]any, out any) error {
|
||||||
bodyMap := map[string]any{
|
bodyMap := make(map[string]any)
|
||||||
"secret": e.cfg.Secret,
|
if e.cfg.Secret != "" {
|
||||||
|
bodyMap["secret"] = e.cfg.Secret
|
||||||
}
|
}
|
||||||
maps.Copy(bodyMap, data)
|
maps.Copy(bodyMap, data)
|
||||||
body, _ := json.Marshal(bodyMap)
|
body, _ := json.Marshal(bodyMap)
|
||||||
|
Reference in New Issue
Block a user