diff --git a/README.md b/README.md index 6344e62..d71a67e 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,8 @@ services: - 10000:10000/udp - 8000:8000/udp - 9000:9000/udp - - 20050-20100:20050-20100 - - 20050-20100:20050-20100/udp + - 20000-20300:20000-20300 + - 20000-20300:20000-20300/udp volumes: - ./configs:/opt/media/conf @@ -214,6 +214,7 @@ services: - [x] 按需拉流,节省流量 - [x] 视频支持播放 H264 和 H265 - [x] 音频支持 g711a/g711u/aac + - [x] 与设备侧超时同步,例如设备侧填写超时 3 秒,次数 3 次,则 9+x 秒左右收不到心跳认为离线,x 是检测间隔周期 - [ ] 设备云台控制 - [ ] 录像回放 - [ ] 报警事件订阅 diff --git a/go.mod b/go.mod index e8362ea..c0b0c3b 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.24 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 - github.com/gin-contrib/gzip v1.2.0 + github.com/gin-contrib/gzip v1.2.2 github.com/gin-gonic/gin v1.10.0 github.com/glebarez/sqlite v1.11.0 github.com/google/wire v0.6.0 - github.com/ixugo/goweb v1.0.19 + github.com/ixugo/goweb v1.0.21 github.com/jinzhu/copier v0.4.0 github.com/pelletier/go-toml/v2 v2.2.3 github.com/shirou/gopsutil v3.21.11+incompatible @@ -17,9 +17,9 @@ require ( ) require ( - github.com/bytedance/sonic v1.12.7 // indirect - github.com/bytedance/sonic/loader v0.2.2 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect @@ -27,8 +27,8 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.24.0 // indirect - github.com/goccy/go-json v0.10.4 // indirect + github.com/go-playground/validator/v10 v10.25.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/gofrs/uuid v4.4.0+incompatible github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/google/uuid v1.6.0 // indirect @@ -39,7 +39,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/lestrrat-go/strftime v1.1.0 // indirect @@ -58,15 +58,15 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/arch v0.13.0 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.36.0 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 + golang.org/x/net v0.38.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 golang.org/x/time v0.8.0 // indirect - google.golang.org/protobuf v1.36.2 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.61.5 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/go.sum b/go.sum index f1a3384..1ba954a 100644 --- a/go.sum +++ b/go.sum @@ -2,11 +2,17 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q= github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o= github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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= @@ -17,6 +23,8 @@ github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3G github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gin-contrib/gzip v1.2.0 h1:JzN6DT3/xYL5zAdviN1ORNzKeklrwafXCIDKIR+qmUA= github.com/gin-contrib/gzip v1.2.0/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s= +github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI= +github.com/gin-contrib/gzip v1.2.2/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s= github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= @@ -35,8 +43,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= +github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= @@ -54,6 +66,8 @@ github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= github.com/ixugo/goweb v1.0.19 h1:q5pIAANBNxZdCSZfRamekqJByt1U3BCHXA0mcCFiioE= github.com/ixugo/goweb v1.0.19/go.mod h1:iBwaaazAtvEuuODjnoCR/5bssvTi49Eft6x8ULg/jsg= +github.com/ixugo/goweb v1.0.21 h1:Bi437yjO+6hJupm+rRXI0u344LIwDDXUCoSNX+oG8Mg= +github.com/ixugo/goweb v1.0.21/go.mod h1:6bUJpmDB6SGMdLyYF5EouHCmHKVYA8Od675JX6twaA4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= @@ -76,6 +90,8 @@ github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCy github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -145,12 +161,16 @@ go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -168,6 +188,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -175,6 +197,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -188,6 +212,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -203,6 +229,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -216,6 +244,8 @@ golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/core/gb28181/store/gb28181cache/cache.go b/internal/core/gb28181/store/gb28181cache/cache.go index 1c03754..c35bd65 100644 --- a/internal/core/gb28181/store/gb28181cache/cache.go +++ b/internal/core/gb28181/store/gb28181cache/cache.go @@ -56,6 +56,11 @@ func (c *Cache) LoadDeviceToMemory(conn sip.Connection) { dev := gbs.NewDevice(conn, d) if dev != nil { + if err := dev.CheckConnection(); err != nil { + slog.Warn("检查设备连接失败", "err", err, "device_id", d.DeviceID, "to", dev.To()) + continue + } + slog.Debug("load device to memory", "device_id", d.DeviceID, "to", dev.To()) channels := make([]*gb28181.Channel, 0, 8) _, err := c.Storer.Channel().Find(context.TODO(), &channels, web.NewPagerFilterMaxSize(), orm.Where("device_id=?", d.DeviceID)) diff --git a/internal/core/sms/node_manager.go b/internal/core/sms/node_manager.go index dc910e6..62cb513 100644 --- a/internal/core/sms/node_manager.go +++ b/internal/core/sms/node_manager.go @@ -126,7 +126,7 @@ func (n *NodeManager) connection(server *MediaServer, serverPort int) { log.Info("ZLM 服务节点连接中") - for i := range 10 { + for i := range 5 { resp, err := engine.GetServerConfig() if err != nil { log.Error("ZLM 服务节点连接失败", "err", err, "retry", i) diff --git a/pkg/gbs/config.go b/pkg/gbs/config.go new file mode 100644 index 0000000..f5586aa --- /dev/null +++ b/pkg/gbs/config.go @@ -0,0 +1,138 @@ +package gbs + +import ( + "encoding/hex" + "encoding/xml" + "log/slog" + "math" + + "github.com/gowvp/gb28181/pkg/gbs/sip" +) + +// 配置参数类型常量定义 +const ( + // basicParam 基本参数配置 + basicParam = "BasicParam" + // videoParamOpt 视频参数范围配置 + // videoParamOpt = "VideoParamOpt" + // // SVACEncodeConfig SVAC编码配置 + // SVACEncodeConfig = "SVACEncodeConfig" + // // SVACDecodeConfig SVAC解码配置 + // SVACDecodeConfig = "SVACDecodeConfig" + // // videoParamAttribute 视频参数属性配置 + // videoParamAttribute = "VideoParamAttribute" + // // videoRecordPlan 录像计划 + // videoRecordPlan = "VideoRecordPlan" + // // videoAlarmRecord 报警录像 + // videoAlarmRecord = "VideoAlarmRecord" + // // pictureMask 视频画面遮挡 + // pictureMask = "PictureMask" + // // frameMirror 画面翻转 + // frameMirror = "FrameMirror" + // // AlarmReport 报警上报开关 + // AlarmReport = "AlarmReport" + // // OSDConfig 前端OSD设置 + // OSDConfig = "OSDConfig" + // // SnapShotConfig 图像抓拍配置 + // SnapShotConfig = "SnapShotConfig" +) + +type ConfigDownloadRequest struct { + XMLName xml.Name `xml:"Query"` + CmdType string `xml:"CmdType"` // 命令类型:设备配置查询(必选) + SN int32 `xml:"SN"` // 命令序列号(必选) + DeviceID string `xml:"DeviceID"` // 目标设备编码(必选) + ConfigType string `xml:"ConfigType"` // 查询配置参数类型(必选) +} + +type ConfigDownloadResponse struct { + XMLName xml.Name `xml:"Response"` + CmdType string `xml:"CmdType"` + SN int `xml:"SN"` + DeviceID string `xml:"DeviceID"` + Result string `xml:"Result"` + BasicParam *BasicParam `xml:"BasicParam"` + // VideoParamOpt *VideoParamOpt `xml:"VideoParamOpt"` + // SVACEncodeConfig *SVACEncodeConfig `xml:"SVACEncodeConfig"` + // SVACDecodeConfig *SVACDecodeConfig `xml:"SVACDecodeConfig"` + // VideoParamAttribute *VideoParamAttribute `xml:"VideoParamAttribute"` + // VideoRecordPlan *VideoRecordPlan `xml:"VideoRecordPlan"` + // VideoAlarmRecord *VideoAlarmRecord `xml:"VideoAlarmRecord"` + // PictureMask *PictureMask `xml:"PictureMask"` + // FrameMirror *FrameMirror `xml:"FrameMirror"` + // AlarmReport *AlarmReport `xml:"AlarmReport"` + // OSDConfig *OSDConfig `xml:"OSDConfig"` + // SnapShot *SnapShot `xml:"SnapShot"` +} + +// BasicParam 设备基本参数配置 +type BasicParam struct { + Name string `xml:"Name"` // 设备名称 + Expiration int `xml:"Expiration"` // 注册过期时间 + HeartBeatInterval int `xml:"HeartBeatInterval"` // 心跳间隔时间 + HeartBeatCount int `xml:"HeartBeatCount"` // 心跳超时次数 +} + +func NewConfigDownloadRequest(sn int32, deviceID string, configType string) []byte { + c := ConfigDownloadRequest{ + CmdType: "ConfigDownload", + SN: sn, + DeviceID: deviceID, + ConfigType: configType, + } + xmlData, _ := sip.XMLEncode(c) + return xmlData +} + +func (g *GB28181API) QueryConfigDownloadBasic(deviceID, configType string) error { + slog.Debug("QueryConfigDownloadBasic", "deviceID", deviceID) + ipc, ok := g.svr.memoryStorer.Load(deviceID) + if !ok { + return ErrDeviceOffline + } + + tx, err := g.svr.wrapRequest(ipc, sip.MethodMessage, &sip.ContentTypeXML, NewConfigDownloadRequest(1, deviceID, configType)) + if err != nil { + return err + } + _, err = sipResponse(tx) + return err +} + +func (g *GB28181API) sipMessageConfigDownload(ctx *sip.Context) { + slog.Debug("sipMessageConfigDownload", "deviceID", ctx.DeviceID) + + var msg ConfigDownloadResponse + if err := sip.XMLDecode(ctx.Request.Body(), &msg); err != nil { + ctx.Log.Error("sipMessageConfigDownload", "err", err, "body", hex.EncodeToString(ctx.Request.Body())) + ctx.String(400, ErrXMLDecode.Error()) + return + } + + if msg.BasicParam != nil { + ipc, ok := g.svr.memoryStorer.Load(ctx.DeviceID) + if !ok { + ctx.Log.Debug("sipMessageConfigDownload", "deviceID", ctx.DeviceID, "err", "device offline") + return + } + + // 确保 HeartBeatCount 在合法范围内 + if msg.BasicParam.HeartBeatCount > math.MaxUint16 { + msg.BasicParam.HeartBeatCount = math.MaxUint16 + } + if msg.BasicParam.HeartBeatInterval > math.MaxUint16 { + msg.BasicParam.HeartBeatInterval = math.MaxUint16 + } + if msg.BasicParam.HeartBeatCount <= 0 { + msg.BasicParam.HeartBeatCount = 1 + } + // 计算设备离线超时时间 + if msg.BasicParam.HeartBeatInterval*msg.BasicParam.HeartBeatCount > 0 { + ipc.keepaliveInterval = uint16(msg.BasicParam.HeartBeatInterval) // nolint + ipc.keepaliveTimeout = uint16(msg.BasicParam.HeartBeatCount) // nolint + ctx.Log.Debug("sipMessageConfigDownload update", "deviceID", ctx.DeviceID, "keepaliveInterval", ipc.keepaliveInterval, "keepaliveTimeout", ipc.keepaliveTimeout) + } + } + + ctx.String(200, "OK") +} diff --git a/pkg/gbs/devices.go b/pkg/gbs/devices.go index 7227151..e2f872f 100644 --- a/pkg/gbs/devices.go +++ b/pkg/gbs/devices.go @@ -38,6 +38,9 @@ type Device struct { LastKeepaliveAt time.Time LastRegisterAt time.Time Expires int + + keepaliveInterval uint16 + keepaliveTimeout uint16 } func NewDevice(conn sip.Connection, d *gb28181.Device) *Device { @@ -70,6 +73,22 @@ func NewDevice(conn sip.Connection, d *gb28181.Device) *Device { return &c } +// CheckConnection 检查 udp 设备能否通信 +func (d *Device) CheckConnection() error { + const timeout = 2 * time.Second + + if d.source.Network() == "tcp" { + return nil + } + // 创建临时UDP连接进行检查 + tempConn, err := net.DialTimeout("udp", d.source.String(), timeout) + if err != nil { + return fmt.Errorf("UDP连接失败: %w", err) + } + defer tempConn.Close() + return nil +} + func (d *Device) LoadChannels(channels ...*gb28181.Channel) { for _, channel := range channels { ch := Channel{ diff --git a/pkg/gbs/info.go b/pkg/gbs/info.go index 15ea8b5..5b19769 100644 --- a/pkg/gbs/info.go +++ b/pkg/gbs/info.go @@ -1,6 +1,8 @@ package gbs import ( + "encoding/hex" + "github.com/gowvp/gb28181/internal/core/gb28181" "github.com/gowvp/gb28181/pkg/gbs/sip" ) @@ -36,7 +38,7 @@ type MessageDeviceInfoResponse struct { func (g GB28181API) sipMessageDeviceInfo(ctx *sip.Context) { var msg MessageDeviceInfoResponse if err := sip.XMLDecode(ctx.Request.Body(), &msg); err != nil { - ctx.Log.Error("sipMessageDeviceInfo", "err", err) + ctx.Log.Error("sipMessageDeviceInfo", "err", err, "body", hex.EncodeToString(ctx.Request.Body())) ctx.String(400, ErrXMLDecode.Error()) return } diff --git a/pkg/gbs/play.go b/pkg/gbs/play.go index 845086f..ed4c4c5 100644 --- a/pkg/gbs/play.go +++ b/pkg/gbs/play.go @@ -1,11 +1,9 @@ package gbs import ( - "errors" "fmt" "net" "sync" - "time" "github.com/gowvp/gb28181/internal/core/gb28181" "github.com/gowvp/gb28181/internal/core/sms" @@ -202,167 +200,167 @@ func (g *GB28181API) sipPlayPush2(ch *Channel, in *PlayInput, port int, stream * } // sip 请求播放 -func SipPlay(data *Streams) (*Streams, error) { - channel := Channels{ChannelID: data.ChannelID} - // if err := db.Get(db.DBClient, &channel); err != nil { - // if db.RecordNotFound(err) { - // return nil, errors.New("通道不存在") - // } - // return nil, err - // } +// func SipPlay(data *Streams) (*Streams, error) { +// channel := Channels{ChannelID: data.ChannelID} +// // if err := db.Get(db.DBClient, &channel); err != nil { +// // if db.RecordNotFound(err) { +// // return nil, errors.New("通道不存在") +// // } +// // return nil, err +// // } - data.DeviceID = channel.DeviceID - data.StreamType = channel.StreamType - // 使用通道的播放模式进行处理 - switch channel.StreamType { - case m.StreamTypePull: - // 拉流 +// data.DeviceID = channel.DeviceID +// data.StreamType = channel.StreamType +// // 使用通道的播放模式进行处理 +// switch channel.StreamType { +// case m.StreamTypePull: +// // 拉流 - default: - // 推流模式要求设备在线且活跃 - if time.Now().Unix()-channel.Active > 30*60 || channel.Status != m.DeviceStatusON { - return nil, errors.New("通道已离线") - } - user, ok := _activeDevices.Get(channel.DeviceID) - if !ok { - return nil, errors.New("设备已离线") - } - // GB28181推流 - if data.StreamID == "" { - ssrcLock.Lock() - // data.ssrc =g. getSSRC(data.T) - data.StreamID = ssrc2stream(data.ssrc) +// default: +// // 推流模式要求设备在线且活跃 +// if time.Now().Unix()-channel.Active > 30*60 || channel.Status != m.DeviceStatusON { +// return nil, errors.New("通道已离线") +// } +// user, ok := _activeDevices.Get(channel.DeviceID) +// if !ok { +// return nil, errors.New("设备已离线") +// } +// // GB28181推流 +// if data.StreamID == "" { +// ssrcLock.Lock() +// // data.ssrc =g. getSSRC(data.T) +// data.StreamID = ssrc2stream(data.ssrc) - // 成功后保存 - // db.Create(db.DBClient, data) - ssrcLock.Unlock() - } +// // 成功后保存 +// // db.Create(db.DBClient, data) +// ssrcLock.Unlock() +// } - var err error - data, err = sipPlayPush(data, channel, user) - if err != nil { - return nil, fmt.Errorf("获取视频失败:%v", err) - } - } +// var err error +// data, err = sipPlayPush(data, channel, user) +// if err != nil { +// return nil, fmt.Errorf("获取视频失败:%v", err) +// } +// } - data.HTTP = fmt.Sprintf("%s/rtp/%s/hls.m3u8", config.Media.HTTP, data.StreamID) - data.RTMP = fmt.Sprintf("%s/rtp/%s", config.Media.RTMP, data.StreamID) - data.RTSP = fmt.Sprintf("%s/rtp/%s", config.Media.RTSP, data.StreamID) - data.WSFLV = fmt.Sprintf("%s/rtp/%s.live.flv", config.Media.WS, data.StreamID) +// data.HTTP = fmt.Sprintf("%s/rtp/%s/hls.m3u8", config.Media.HTTP, data.StreamID) +// data.RTMP = fmt.Sprintf("%s/rtp/%s", config.Media.RTMP, data.StreamID) +// data.RTSP = fmt.Sprintf("%s/rtp/%s", config.Media.RTSP, data.StreamID) +// data.WSFLV = fmt.Sprintf("%s/rtp/%s.live.flv", config.Media.WS, data.StreamID) - data.Ext = time.Now().Unix() + 2*60 // 2分钟等待时间 - StreamList.Response.Store(data.StreamID, data) - if data.T == 0 { - StreamList.Succ.Store(data.ChannelID, data) - } - // db.Save(db.DBClient, data) - return data, nil -} +// data.Ext = time.Now().Unix() + 2*60 // 2分钟等待时间 +// StreamList.Response.Store(data.StreamID, data) +// if data.T == 0 { +// StreamList.Succ.Store(data.ChannelID, data) +// } +// // db.Save(db.DBClient, data) +// return data, nil +// } var ssrcLock *sync.Mutex -func sipPlayPush(data *Streams, channel Channels, device Devices) (*Streams, error) { - var ( - s sdp.Session - b []byte - ) - name := "Play" - protocal := "TCP/RTP/AVP" - if data.T == 1 { - name = "Playback" - protocal = "RTP/RTCP" - } +// func sipPlayPush(data *Streams, channel Channels, device Devices) (*Streams, error) { +// var ( +// s sdp.Session +// b []byte +// ) +// name := "Play" +// protocal := "TCP/RTP/AVP" +// if data.T == 1 { +// name = "Playback" +// protocal = "RTP/RTCP" +// } - video := sdp.Media{ - Description: sdp.MediaDescription{ - Type: "video", - Port: _sysinfo.MediaServerRtpPort, - Formats: []string{"96", "98", "97"}, - Protocol: protocal, - }, - } - video.AddAttribute("recvonly") - if data.T == 0 { - video.AddAttribute("setup", "passive") - video.AddAttribute("connection", "new") - } - video.AddAttribute("rtpmap", "96", "PS/90000") - video.AddAttribute("rtpmap", "98", "H264/90000") - video.AddAttribute("rtpmap", "97", "MPEG4/90000") +// video := sdp.Media{ +// Description: sdp.MediaDescription{ +// Type: "video", +// Port: _sysinfo.MediaServerRtpPort, +// Formats: []string{"96", "98", "97"}, +// Protocol: protocal, +// }, +// } +// video.AddAttribute("recvonly") +// if data.T == 0 { +// video.AddAttribute("setup", "passive") +// video.AddAttribute("connection", "new") +// } +// video.AddAttribute("rtpmap", "96", "PS/90000") +// video.AddAttribute("rtpmap", "98", "H264/90000") +// video.AddAttribute("rtpmap", "97", "MPEG4/90000") - // defining message - msg := &sdp.Message{ - Origin: sdp.Origin{ - Username: _serverDevices.DeviceID, // 媒体服务器id - Address: _sysinfo.MediaServerRtpIP.String(), - }, - Name: name, - Connection: sdp.ConnectionData{ - IP: _sysinfo.MediaServerRtpIP, - TTL: 0, - }, - Timing: []sdp.Timing{ - { - Start: data.S, - End: data.E, - }, - }, - Medias: []sdp.Media{video}, - SSRC: data.ssrc, - } - if data.T == 1 { - msg.URI = fmt.Sprintf("%s:0", channel.ChannelID) - } +// // defining message +// msg := &sdp.Message{ +// Origin: sdp.Origin{ +// Username: _serverDevices.DeviceID, // 媒体服务器id +// Address: _sysinfo.MediaServerRtpIP.String(), +// }, +// Name: name, +// Connection: sdp.ConnectionData{ +// IP: _sysinfo.MediaServerRtpIP, +// TTL: 0, +// }, +// Timing: []sdp.Timing{ +// { +// Start: data.S, +// End: data.E, +// }, +// }, +// Medias: []sdp.Media{video}, +// SSRC: data.ssrc, +// } +// if data.T == 1 { +// msg.URI = fmt.Sprintf("%s:0", channel.ChannelID) +// } - // appending message to session - s = msg.Append(s) - // appending session to byte buffer - b = s.AppendTo(b) - uri, _ := sip.ParseURI(channel.URIStr) - channel.addr = &sip.Address{URI: uri} - _serverDevices.addr.Params.Add("tag", sip.String{Str: sip.RandString(20)}) - hb := sip.NewHeaderBuilder().SetTo(channel.addr).SetFrom(_serverDevices.addr).AddVia(&sip.ViaHop{ - Params: sip.NewParams().Add("branch", sip.String{Str: sip.GenerateBranch()}), - }).SetContentType(&sip.ContentTypeSDP).SetMethod(sip.MethodInvite).SetContact(_serverDevices.addr) - req := sip.NewRequest("", sip.MethodInvite, channel.addr.URI, sip.DefaultSipVersion, hb.Build(), b) - req.SetDestination(device.source) - req.AppendHeader(&sip.GenericHeader{HeaderName: "Subject", Contents: fmt.Sprintf("%s:%s,%s:%s", channel.ChannelID, data.StreamID, _serverDevices.DeviceID, data.StreamID)}) - req.SetRecipient(channel.addr.URI) - tx, err := svr.Request(req) - if err != nil { - // logrus.Warningln("sipPlayPush fail.id:", device.DeviceID, channel.ChannelID, "err:", err) - return data, err - } - // response - response, err := sipResponse(tx) - if err != nil { - // logrus.Warningln("sipPlayPush response fail.id:", device.DeviceID, channel.ChannelID, "err:", err) - return data, err - } - data.Resp = response - // ACK - tx.Request(sip.NewRequestFromResponse(sip.MethodACK, response)) +// // appending message to session +// s = msg.Append(s) +// // appending session to byte buffer +// b = s.AppendTo(b) +// uri, _ := sip.ParseURI(channel.URIStr) +// channel.addr = &sip.Address{URI: uri} +// _serverDevices.addr.Params.Add("tag", sip.String{Str: sip.RandString(20)}) +// hb := sip.NewHeaderBuilder().SetTo(channel.addr).SetFrom(_serverDevices.addr).AddVia(&sip.ViaHop{ +// Params: sip.NewParams().Add("branch", sip.String{Str: sip.GenerateBranch()}), +// }).SetContentType(&sip.ContentTypeSDP).SetMethod(sip.MethodInvite).SetContact(_serverDevices.addr) +// req := sip.NewRequest("", sip.MethodInvite, channel.addr.URI, sip.DefaultSipVersion, hb.Build(), b) +// req.SetDestination(device.source) +// req.AppendHeader(&sip.GenericHeader{HeaderName: "Subject", Contents: fmt.Sprintf("%s:%s,%s:%s", channel.ChannelID, data.StreamID, _serverDevices.DeviceID, data.StreamID)}) +// req.SetRecipient(channel.addr.URI) +// tx, err := svr.Request(req) +// if err != nil { +// // logrus.Warningln("sipPlayPush fail.id:", device.DeviceID, channel.ChannelID, "err:", err) +// return data, err +// } +// // response +// response, err := sipResponse(tx) +// if err != nil { +// // logrus.Warningln("sipPlayPush response fail.id:", device.DeviceID, channel.ChannelID, "err:", err) +// return data, err +// } +// data.Resp = response +// // ACK +// tx.Request(sip.NewRequestFromResponse(sip.MethodACK, response)) - callid, _ := response.CallID() - data.CallID = string(*callid) +// callid, _ := response.CallID() +// data.CallID = string(*callid) - cseq, _ := response.CSeq() - if cseq != nil { - data.CseqNo = cseq.SeqNo - } +// cseq, _ := response.CSeq() +// if cseq != nil { +// data.CseqNo = cseq.SeqNo +// } - // from, _ := response.From() - // to, _ := response.To() - // for k, v := range to.Params.Items() { - // data.Ttag[k] = v.String() - // } - // for k, v := range from.Params.Items() { - // data.Ftag[k] = v.String() - // } - data.Status = 0 +// // from, _ := response.From() +// // to, _ := response.To() +// // for k, v := range to.Params.Items() { +// // data.Ttag[k] = v.String() +// // } +// // for k, v := range from.Params.Items() { +// // data.Ftag[k] = v.String() +// // } +// data.Status = 0 - return data, err -} +// return data, err +// } // sip 停止播放 func SipStopPlay(ssrc string) { diff --git a/pkg/gbs/register.go b/pkg/gbs/register.go index 4d191aa..fe524c3 100644 --- a/pkg/gbs/register.go +++ b/pkg/gbs/register.go @@ -36,7 +36,7 @@ func NewGB28181API(cfg *conf.Bootstrap, store gb28181.GB28181, sms *sms.NodeMana cfg: &cfg.Sip, core: store, sms: sms, - catalog: sip.NewCollector[Channels](func(c1, c2 *Channels) bool { + catalog: sip.NewCollector(func(c1, c2 *Channels) bool { return c1.ChannelID == c2.ChannelID }), streams: &conc.Map[string, *Streams]{}, @@ -141,15 +141,17 @@ func (g *GB28181API) handlerRegister(ctx *sip.Context) { } g.login(ctx, expire) - conn := ctx.Request.GetConnection() - fmt.Printf(">>> %p\n", conn) + // conn := ctx.Request.GetConnection() + // fmt.Printf(">>> %p\n", conn) ctx.Log.Info("设备注册成功") + // ctx.Log.Debug("device info", "source", ctx.Source, "host", ctx.Host) respFn() g.QueryDeviceInfo(ctx) - g.QueryCatalog(dev.DeviceID) + _ = g.QueryCatalog(dev.DeviceID) + _ = g.QueryConfigDownloadBasic(dev.DeviceID, basicParam) } func (g GB28181API) login(ctx *sip.Context, expire string) { diff --git a/pkg/gbs/server.go b/pkg/gbs/server.go index 0347646..72916d3 100644 --- a/pkg/gbs/server.go +++ b/pkg/gbs/server.go @@ -58,6 +58,7 @@ func NewServer(cfg *conf.Bootstrap, store gb28181.GB28181, sc sms.Core) (*Server msg.Handle("Keepalive", api.sipMessageKeepalive) msg.Handle("Catalog", api.sipMessageCatalog) msg.Handle("DeviceInfo", api.sipMessageDeviceInfo) + msg.Handle("ConfigDownload", api.sipMessageConfigDownload) // msg.Handle("RecordInfo", api.handlerMessage) @@ -88,12 +89,17 @@ func NewServer(cfg *conf.Bootstrap, store gb28181.GB28181, sc sms.Core) (*Server func (s *Server) startTickerCheck() { conc.Timer(context.Background(), 60*time.Second, time.Second, func() { now := time.Now() - s.memoryStorer.RangeDevices(func(key string, value *Device) bool { - if !value.IsOnline { + s.memoryStorer.RangeDevices(func(key string, ipc *Device) bool { + if !ipc.IsOnline { return true } - if sub := now.Sub(value.LastKeepaliveAt); sub >= 3*60*time.Second || value.conn == nil { + timeout := time.Duration(ipc.keepaliveTimeout) * time.Duration(ipc.keepaliveInterval) * time.Second + if timeout <= 0 { + timeout = 3 * 60 * time.Second + } + + if sub := now.Sub(ipc.LastKeepaliveAt); sub >= timeout || ipc.conn == nil { s.gb.logout(key, func(d *gb28181.Device) { d.IsOnline = false }) diff --git a/pkg/gbs/sip/parser.go b/pkg/gbs/sip/parser.go index 835830c..ab6cb1e 100644 --- a/pkg/gbs/sip/parser.go +++ b/pkg/gbs/sip/parser.go @@ -3,6 +3,7 @@ package sip import ( "bytes" "fmt" + "io" "log/slog" "strconv" "strings" @@ -583,7 +584,12 @@ func (p *parser) start() { packet = <-p.in startLine, err := packet.nextLine() if err != nil { - slog.Error("start nextLine", "err", err, "line", startLine) + if err != io.EOF { + slog.Error("start nextLine", "err", err, "line", startLine) + } + continue + } + if len(startLine) == 0 { continue } if isRequest(startLine) { @@ -601,7 +607,7 @@ func (p *parser) start() { termErr = NewError(err, "parserMessage", "ParseStatusLine", startLine) } } else { - slog.Error("start unknown", "err", err, "line", startLine) + slog.Error("start unknown", "line", startLine) continue } if termErr != nil { diff --git a/pkg/gbs/sip/server.go b/pkg/gbs/sip/server.go index 4c7e1d4..cceb653 100644 --- a/pkg/gbs/sip/server.go +++ b/pkg/gbs/sip/server.go @@ -20,7 +20,7 @@ var bufferSize uint16 = 65535 - 20 - 8 // IPv4 max size - IPv4 Header size - UDP // Server sip type Server struct { - udpaddr net.Addr + // udpaddr net.Addr udpConn Connection txs *transacionts @@ -248,21 +248,18 @@ func (s *Server) handlerListen(msgs chan Message) { case *Request: req := tmsg - dst := s.udpaddr + // dst := s.udpaddr if req.conn.Network() == "tcp" { - dst = s.tcpaddr + req.SetDestination(s.tcpaddr) } - req.SetDestination(dst) s.handlerRequest(req) case *Response: resp := tmsg - dst := s.udpaddr if resp.conn.Network() == "tcp" { - dst = s.tcpaddr + resp.SetDestination(s.tcpaddr) } - resp.SetDestination(dst) s.handlerResponse(resp) default: // logrus.Errorln("undefind msg type,", tmsg, msg.String()) diff --git a/pkg/gbs/sip/utils.go b/pkg/gbs/sip/utils.go index 1ba7b79..7577026 100644 --- a/pkg/gbs/sip/utils.go +++ b/pkg/gbs/sip/utils.go @@ -186,6 +186,17 @@ func xmlDecode(data []byte, v interface{}) error { return decoder.Decode(v) } +// XMLEncode XML编码器 +func XMLEncode(data any) ([]byte, error) { + b, err := xml.Marshal(data) + if err != nil { + slog.Error("MarshalIndent", "err", err) + return nil, err + } + xmlHeader := "\n" + return Utf8ToGbk([]byte(xmlHeader + string(b))) +} + // Max Max func Max(a, b int64) int64 { if a > b {