71 lines
2.1 KiB
Go
71 lines
2.1 KiB
Go
package rtsp
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/onvif"
|
|
)
|
|
|
|
type Credential struct{ Username, Password string }
|
|
type Result struct {
|
|
Status string `json:"status"`
|
|
LatencyMS int64 `json:"latencyMs"`
|
|
Detail string `json:"detail"`
|
|
}
|
|
type Verifier interface {
|
|
Verify(context.Context, string, Credential) (Result, error)
|
|
}
|
|
type NetVerifier struct {
|
|
Timeout time.Duration
|
|
Policy onvif.Policy
|
|
}
|
|
|
|
func (v NetVerifier) Verify(ctx context.Context, raw string, credential Credential) (Result, error) {
|
|
parsed, ip, err := v.Policy.ValidateURL(ctx, raw, "rtsp")
|
|
if err != nil {
|
|
return Result{}, err
|
|
}
|
|
port := parsed.Port()
|
|
if port == "" {
|
|
port = "554"
|
|
}
|
|
timeout := v.Timeout
|
|
if timeout <= 0 {
|
|
timeout = 5 * time.Second
|
|
}
|
|
started := time.Now()
|
|
connection, err := (&net.Dialer{Timeout: timeout}).DialContext(ctx, "tcp", net.JoinHostPort(ip.String(), port))
|
|
if err != nil {
|
|
return Result{Status: "unreachable", Detail: "无法连接视频端口"}, nil
|
|
}
|
|
defer connection.Close()
|
|
_ = connection.SetDeadline(time.Now().Add(timeout))
|
|
authorization := ""
|
|
if credential.Username != "" {
|
|
authorization = "Authorization: Basic " + base64.StdEncoding.EncodeToString([]byte(credential.Username+":"+credential.Password)) + "\r\n"
|
|
}
|
|
request := fmt.Sprintf("OPTIONS %s RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: YoVision-Sense\r\n%s\r\n", parsed.String(), authorization)
|
|
if _, err = connection.Write([]byte(request)); err != nil {
|
|
return Result{}, err
|
|
}
|
|
line, err := bufio.NewReader(connection).ReadString('\n')
|
|
if err != nil {
|
|
return Result{Status: "timeout", Detail: "等待视频响应超时"}, nil
|
|
}
|
|
result := Result{Status: "ready", Detail: "码流可访问", LatencyMS: time.Since(started).Milliseconds()}
|
|
if strings.Contains(line, " 401 ") {
|
|
result.Status = "authentication_failed"
|
|
result.Detail = "设备拒绝了当前 RTSP 凭据"
|
|
} else if !strings.Contains(line, " 200 ") {
|
|
result.Status = "failed"
|
|
result.Detail = "设备返回非成功状态"
|
|
}
|
|
return result, nil
|
|
}
|