mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-28 16:51:47 +08:00
135 lines
3.4 KiB
Go
135 lines
3.4 KiB
Go
package plugin_gb28181pro
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/emiago/sipgo"
|
|
"github.com/emiago/sipgo/sip"
|
|
myip "github.com/husanpao/ip"
|
|
"github.com/icholy/digest"
|
|
"github.com/rs/zerolog"
|
|
"m7s.live/v5/pkg/task"
|
|
gb28181 "m7s.live/v5/plugin/gb28181pro/pkg"
|
|
)
|
|
|
|
type Client struct {
|
|
task.Job
|
|
*sipgo.Client
|
|
srv *sipgo.Server
|
|
conf *GB28181ProPlugin
|
|
recipient sip.Uri
|
|
tp string
|
|
sn int
|
|
}
|
|
|
|
type KeepAlive struct {
|
|
task.TickTask
|
|
client *Client
|
|
}
|
|
|
|
func (k *KeepAlive) GetTickInterval() time.Duration {
|
|
return time.Second * 60
|
|
}
|
|
|
|
func (k *KeepAlive) Tick(any) {
|
|
req := sip.NewRequest("OnMessage", k.client.recipient)
|
|
req.SetTransport(k.client.tp)
|
|
req.SetBody(gb28181.BuildKeepAliveXML(k.client.sn, k.client.recipient.User))
|
|
k.client.sn++
|
|
_, err := k.client.Do(k.client.conf, req)
|
|
if err != nil {
|
|
k.client.conf.Error("keepalive", "error", err.Error())
|
|
}
|
|
}
|
|
|
|
func (c *Client) Start() (err error) {
|
|
netWork, parent, _ := strings.Cut(c.conf.Parent, ":")
|
|
sip.ParseUri(fmt.Sprintf("sip:%s", parent), &c.recipient)
|
|
|
|
// Check if host is private/internal network IP
|
|
//if util.IsPrivateIP(c.recipient.Host) {
|
|
c.Client, err = sipgo.NewClient(c.conf.ua, sipgo.WithClientLogger(zerolog.New(os.Stdout)), sipgo.WithClientHostname(myip.InternalIPv4()), sipgo.WithClientPort(5061))
|
|
//} else {
|
|
// c.Client, err = sipgo.NewClient(c.conf.ua, sipgo.WithClientLogger(zerolog.New(os.Stdout)), sipgo.WithClientHostname(util.Routes[myip.InternalIPv4()]), sipgo.WithClientPort(5061))
|
|
//}
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.srv, _ = sipgo.NewServer(c.conf.ua, sipgo.WithServerLogger(zerolog.New(os.Stdout)))
|
|
contactHDR := sip.ContactHeader{
|
|
Address: sip.Uri{
|
|
User: c.conf.Serial,
|
|
Host: c.conf.Realm,
|
|
},
|
|
}
|
|
// sipgo.NewDialogServer(c.Client, contactHDR)
|
|
req := sip.NewRequest("REGISTER", c.recipient)
|
|
req.AppendHeader(&contactHDR)
|
|
c.tp = strings.ToUpper(netWork)
|
|
req.SetTransport(c.tp)
|
|
var res *sip.Response
|
|
res, err = c.Do(c.conf, req)
|
|
if err != nil {
|
|
c.conf.Error("register", "error", err.Error())
|
|
} else {
|
|
c.conf.Info("register", "response", res.String())
|
|
if res.StatusCode == 401 {
|
|
// Get WwW-Authenticate
|
|
wwwAuth := res.GetHeader("WWW-Authenticate")
|
|
var chal *digest.Challenge
|
|
chal, err = digest.ParseChallenge(wwwAuth.Value())
|
|
if err != nil {
|
|
c.conf.Error("register", "error", err.Error())
|
|
}
|
|
|
|
// Reply with digest
|
|
cred, _ := digest.Digest(chal, digest.Options{
|
|
Method: req.Method.String(),
|
|
URI: c.recipient.Host,
|
|
Username: c.conf.Username,
|
|
Password: c.conf.Password,
|
|
})
|
|
|
|
newReq := req.Clone()
|
|
newReq.RemoveHeader("Via") // Must be regenerated by tranport layer
|
|
newReq.AppendHeader(sip.NewHeader("Authorization", cred.String()))
|
|
|
|
ctx := context.Background()
|
|
var tx sip.ClientTransaction
|
|
tx, err = c.TransactionRequest(ctx, newReq, sipgo.ClientRequestAddVia)
|
|
if err != nil {
|
|
c.conf.Error("register", "error", err.Error())
|
|
}
|
|
defer tx.Terminate()
|
|
|
|
res, err = getResponse(tx)
|
|
if err != nil {
|
|
c.conf.Error("register", "error", err.Error())
|
|
return
|
|
}
|
|
}
|
|
var ka KeepAlive
|
|
ka.client = c
|
|
c.AddTask(&ka)
|
|
}
|
|
return
|
|
}
|
|
|
|
func getResponse(tx sip.ClientTransaction) (*sip.Response, error) {
|
|
select {
|
|
case <-tx.Done():
|
|
return nil, fmt.Errorf("transaction died")
|
|
case res := <-tx.Responses():
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
func (c *Client) Run() (err error) {
|
|
return
|
|
}
|