zlm api 测试

补充部分注释
This commit is contained in:
shikong 2025-01-25 15:53:25 +08:00
parent 7909229664
commit 529e9fc375
Signed by: Shikong
GPG Key ID: BD85FF18B373C341
9 changed files with 142 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
) )
func GenerateConfig() error { func GenerateConfig() error {
// 生成配置文件
p, _ := filepath.Abs("./config.toml") p, _ := filepath.Abs("./config.toml")
flag := os.O_RDWR flag := os.O_RDWR
@ -35,6 +36,7 @@ func GenerateConfig() error {
} }
func ReadClientConfig() (*ClientConfig, error) { func ReadClientConfig() (*ClientConfig, error) {
// 读取客户端配置文件,如果不存在则生成示例配置
viper.SetConfigName(constants.ConfigFileName) viper.SetConfigName(constants.ConfigFileName)
viper.SetConfigType(constants.ConfigType) viper.SetConfigType(constants.ConfigType)
for _, path := range constants.ConfigPaths { for _, path := range constants.ConfigPaths {

View File

@ -9,17 +9,28 @@ import (
"github.com/emiago/sipgo/sip" "github.com/emiago/sipgo/sip"
) )
// messageHandler 是一个处理SIP消息的函数类型
type messageHandler = func(client *sipgo.Client, clientConfig *config.ClientConfig, req *sip.Request, tx sip.ServerTransaction) type messageHandler = func(client *sipgo.Client, clientConfig *config.ClientConfig, req *sip.Request, tx sip.ServerTransaction)
// handlers 是一个存储消息处理器的映射,键为命令类型,值为消息处理器函数
var handlers = make(map[string]messageHandler) var handlers = make(map[string]messageHandler)
// SetupMessageHandler 设置SIP服务器的消息处理器根据消息的命令类型调用相应的处理器
func SetupMessageHandler(srv *sipgo.Server, client *sipgo.Client, clientConfig *config.ClientConfig) { func SetupMessageHandler(srv *sipgo.Server, client *sipgo.Client, clientConfig *config.ClientConfig) {
srv.OnMessage(func(req *sip.Request, tx sip.ServerTransaction) { srv.OnMessage(func(req *sip.Request, tx sip.ServerTransaction) {
body := req.Body() body := req.Body()
if len(body) == 0 {
log.Log().Warn().Msgf("消息体为空")
_ = tx.Respond(sip.NewResponseFromRequest(req, sip.StatusOK, "OK", nil))
return
}
message := new(manscdp.MessageReq) message := new(manscdp.MessageReq)
err := utils.XMLUnmarshal(body, message) err := utils.XMLUnmarshal(body, message)
if err != nil { if err != nil {
log.Log().Error().Msgf("XML Unmarshal error: %v", err) log.Log().Error().Msgf("XML Unmarshal error: %v", err)
_ = tx.Respond(sip.NewResponseFromRequest(req, sip.StatusBadRequest, "Bad Request", nil))
return
} }
handlers, ok := handlers[message.CmdType] handlers, ok := handlers[message.CmdType]

View File

@ -2,6 +2,7 @@ package manscdp
import "encoding/xml" import "encoding/xml"
// CatalogReq 定义了查询目录的请求结构
type CatalogReq struct { type CatalogReq struct {
XMLName xml.Name `xml:"Query"` XMLName xml.Name `xml:"Query"`
CmdType string `xml:"CmdType"` CmdType string `xml:"CmdType"`
@ -9,6 +10,7 @@ type CatalogReq struct {
DeviceID string `xml:"DeviceID"` DeviceID string `xml:"DeviceID"`
} }
// CatalogResp 定义了查询目录的响应结构
type CatalogResp struct { type CatalogResp struct {
XMLName xml.Name `xml:"Response"` XMLName xml.Name `xml:"Response"`
CmdType string `xml:"CmdType"` CmdType string `xml:"CmdType"`
@ -18,12 +20,14 @@ type CatalogResp struct {
DeviceID string `xml:"DeviceID"` DeviceID string `xml:"DeviceID"`
} }
// CateLogDeviceList 定义了设备列表的结构
type CateLogDeviceList struct { type CateLogDeviceList struct {
XMLName xml.Name `xml:"DeviceList"` XMLName xml.Name `xml:"DeviceList"`
Num string `xml:"Num,attr"` Num string `xml:"Num,attr"`
Item []CateLogDevice `xml:"Item"` Item []CateLogDevice `xml:"Item"`
} }
// CateLogDevice 定义了单个设备的详细信息结构
type CateLogDevice struct { type CateLogDevice struct {
XMLName xml.Name `xml:"Item"` XMLName xml.Name `xml:"Item"`
Name string `xml:"Name"` Name string `xml:"Name"`

View File

@ -2,6 +2,7 @@ package manscdp
import "encoding/xml" import "encoding/xml"
// MessageReq 定义了查询消息的请求结构体使用XML格式进行序列化和反序列化
type MessageReq struct { type MessageReq struct {
XMLName xml.Name `xml:"Query"` XMLName xml.Name `xml:"Query"`
CmdType string `xml:"CmdType"` CmdType string `xml:"CmdType"`

View File

@ -1,6 +1,8 @@
package zlmediakit package zlmediakit
import ( import (
"encoding/json"
"git.skcks.cn/Shikong/go-gb28181/pkg/services/zlmediakit/types"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"time" "time"
) )
@ -22,3 +24,51 @@ func SetupZLMediaKitService(config *Config) {
client: client, client: client,
} }
} }
func GetZLMediaKitService() *ZLMediaKit {
return zLMediaKitService
}
func (z *ZLMediaKit) GetApiList() (data *types.Data[[]string], err error) {
resp, err := z.client.R().Get("/index/api/getApiList")
if err != nil {
return nil, err
}
data = new(types.Data[[]string])
err = json.Unmarshal(resp.Body(), data)
if err != nil {
return nil, err
}
return data, nil
}
func (z *ZLMediaKit) GetServerConfig() (data *types.ServerConfigResp, err error) {
resp, err := z.client.R().Get("/index/api/getServerConfig")
if err != nil {
return nil, err
}
data = new(types.ServerConfigResp)
err = json.Unmarshal(resp.Body(), data)
if err != nil {
return nil, err
}
return data, nil
}
func (z *ZLMediaKit) SetServerConfig(config *types.ServerConfig) (data *types.SetServerConfigResp, err error) {
resp, err := z.client.R().
SetBody(config).
Post("/index/api/setServerConfig")
if err != nil {
return nil, err
}
data = new(types.SetServerConfigResp)
err = json.Unmarshal(resp.Body(), data)
if err != nil {
return nil, err
}
return data, nil
}

View File

@ -5,18 +5,22 @@ import (
"fmt" "fmt"
"git.skcks.cn/Shikong/go-gb28181/pkg/services/zlmediakit/types" "git.skcks.cn/Shikong/go-gb28181/pkg/services/zlmediakit/types"
"github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/formatter"
"github.com/duke-git/lancet/v2/netutil" "github.com/duke-git/lancet/v2/netutil"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"strings"
"testing" "testing"
) )
func TestZLMediaKit(t *testing.T) { func TestZLMediaKit(t *testing.T) {
// 设置ZLMediaKit服务传入配置信息
SetupZLMediaKitService(&Config{ SetupZLMediaKitService(&Config{
Id: "amrWMKmbKqoBjRQ9", Id: "amrWMKmbKqoBjRQ9",
Url: "http://10.10.10.200:5081", Url: "http://10.10.10.200:5081",
Secret: "4155cca6-2f9f-11ee-85e6-8de4ce2e7333", Secret: "4155cca6-2f9f-11ee-85e6-8de4ce2e7333",
}) })
// 获取媒体列表并检查响应
resp, err := zLMediaKitService.client.R().Get("/index/api/getMediaList") resp, err := zLMediaKitService.client.R().Get("/index/api/getMediaList")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -27,6 +31,67 @@ func TestZLMediaKit(t *testing.T) {
for _, datum := range data.Data { for _, datum := range data.Data {
t.Logf("%+v\n", datum) t.Logf("%+v\n", datum)
} }
// 获取ZLMediaKit服务实例
service := GetZLMediaKitService()
// 获取API列表并打印数据
apiList, err := service.GetApiList()
printData(apiList, err, t)
// 打印分隔线
t.Log(strings.Repeat("=", 50))
// 获取服务器配置并打印数据
getConfigResp, err := service.GetServerConfig()
printData(getConfigResp, err, t)
// 深度克隆配置并修改SRT超时时间然后设置服务器配置
config := convertor.DeepClone(getConfigResp.Data[0])
config.SrtTimeoutSec = "5"
serverConfigResp, err := service.SetServerConfig(&config)
printResp(serverConfigResp, err, t)
// 再次获取服务器配置并打印数据,以验证修改是否成功
getConfigResp, err = service.GetServerConfig()
printData(getConfigResp, err, t)
// 打印分隔线
t.Log(strings.Repeat("=", 50))
}
func printResp[T any](data *T, err error, t *testing.T) {
if err != nil {
t.Error(err)
} else {
pretty, _ := formatter.Pretty(data)
t.Log(pretty)
}
}
func printData[T any](data *types.Data[T], err error, t *testing.T) {
if err != nil {
t.Error(err)
} else {
switch x := interface{}(data.Data).(type) {
case string, int, int64, float32, float64, bool, nil, []byte:
t.Log(x)
case []any:
for _, s := range x {
t.Logf("\t%+v\n", s)
}
case []string:
for _, s := range x {
t.Logf("\t%+v\n", s)
}
default:
result, _ := formatter.Pretty(x)
t.Logf("%s\n", result)
}
}
} }
func TestZLMediaKit_API(t *testing.T) { func TestZLMediaKit_API(t *testing.T) {

View File

@ -1,5 +1,6 @@
package types package types
// Data 是一个泛型结构体,用于封装 API 响应的数据
type Data[T any] struct { type Data[T any] struct {
Code int `json:"code"` Code int `json:"code"`
Data T `json:"data"` Data T `json:"data"`

View File

@ -4,6 +4,11 @@ type ServerConfigResp = Data[ServerConfigRespRaw]
type ServerConfigRespRaw = []ServerConfig type ServerConfigRespRaw = []ServerConfig
type SetServerConfigResp struct {
Code int `json:"code"`
Changed int `json:"changed"`
}
type ServerConfig struct { type ServerConfig struct {
ApiApiDebug string `json:"api.apiDebug"` ApiApiDebug string `json:"api.apiDebug"`
ApiDefaultSnap string `json:"api.defaultSnap"` ApiDefaultSnap string `json:"api.defaultSnap"`

View File

@ -12,6 +12,7 @@ import (
"strings" "strings"
) )
// XMLMarshalString 将给定的对象v序列化为XML字符串并指定字符集charset
func XMLMarshalString(v interface{}, charset string) (string, error) { func XMLMarshalString(v interface{}, charset string) (string, error) {
marshal, err := XMLMarshal(v, charset) marshal, err := XMLMarshal(v, charset)
if err != nil { if err != nil {
@ -20,6 +21,7 @@ func XMLMarshalString(v interface{}, charset string) (string, error) {
return string(marshal), nil return string(marshal), nil
} }
// XMLMarshal 将给定的对象obj序列化为XML格式的字节数组并指定字符集charset
func XMLMarshal(obj interface{}, charset string) ([]byte, error) { func XMLMarshal(obj interface{}, charset string) ([]byte, error) {
marshal := &bytes.Buffer{} marshal := &bytes.Buffer{}
encoder := xml.NewEncoder(marshal) encoder := xml.NewEncoder(marshal)
@ -69,6 +71,7 @@ func XMLMarshal(obj interface{}, charset string) ([]byte, error) {
return xmlBytes.Bytes(), nil return xmlBytes.Bytes(), nil
} }
// XMLUnmarshal 将XML格式的字节数组data反序列化为对象obj
func XMLUnmarshal(data []byte, obj interface{}) error { func XMLUnmarshal(data []byte, obj interface{}) error {
decoder := xml.NewDecoder(bytes.NewReader(data)) decoder := xml.NewDecoder(bytes.NewReader(data))
decoder.CharsetReader = func(c string, input io.Reader) (io.Reader, error) { decoder.CharsetReader = func(c string, input io.Reader) (io.Reader, error) {