144 lines
4.7 KiB
Go
144 lines
4.7 KiB
Go
package mtx
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
mediamtxapi "yovision/sense/internal/mtx/generated"
|
|
)
|
|
|
|
var ErrPathNotFound = errors.New("MediaMTX path not found")
|
|
|
|
type APIError struct {
|
|
Operation string
|
|
StatusCode int
|
|
}
|
|
|
|
func (e *APIError) Error() string {
|
|
return fmt.Sprintf("MediaMTX %s failed with HTTP status %d", e.Operation, e.StatusCode)
|
|
}
|
|
|
|
type PathConfig struct {
|
|
Name string
|
|
Source string
|
|
}
|
|
|
|
type pathAPI interface {
|
|
ConfigPathsAddWithResponse(context.Context, string, mediamtxapi.ConfigPathsAddJSONRequestBody, ...mediamtxapi.RequestEditorFn) (*mediamtxapi.ConfigPathsAddResponse, error)
|
|
ConfigPathsGetWithResponse(context.Context, string, ...mediamtxapi.RequestEditorFn) (*mediamtxapi.ConfigPathsGetResponse, error)
|
|
ConfigPathsPatchWithResponse(context.Context, string, mediamtxapi.ConfigPathsPatchJSONRequestBody, ...mediamtxapi.RequestEditorFn) (*mediamtxapi.ConfigPathsPatchResponse, error)
|
|
ConfigPathsDeleteWithResponse(context.Context, string, ...mediamtxapi.RequestEditorFn) (*mediamtxapi.ConfigPathsDeleteResponse, error)
|
|
PathsGetWithResponse(context.Context, string, ...mediamtxapi.RequestEditorFn) (*mediamtxapi.PathsGetResponse, error)
|
|
}
|
|
|
|
type Client struct {
|
|
api pathAPI
|
|
}
|
|
|
|
func NewClient(baseURL string, httpClient *http.Client) (*Client, error) {
|
|
options := make([]mediamtxapi.ClientOption, 0, 1)
|
|
if httpClient != nil {
|
|
options = append(options, mediamtxapi.WithHTTPClient(httpClient))
|
|
}
|
|
generated, err := mediamtxapi.NewClientWithResponses(strings.TrimRight(baseURL, "/"), options...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create MediaMTX client: %w", err)
|
|
}
|
|
return &Client{api: generated}, nil
|
|
}
|
|
|
|
func newClientWithAPI(api pathAPI) *Client {
|
|
return &Client{api: api}
|
|
}
|
|
|
|
func (c *Client) CreatePath(ctx context.Context, name, source string) error {
|
|
response, err := c.api.ConfigPathsAddWithResponse(ctx, name, mediamtxapi.PathConf{Source: &source})
|
|
if err != nil {
|
|
return fmt.Errorf("MediaMTX create path transport: %w", err)
|
|
}
|
|
if response.StatusCode() != http.StatusOK {
|
|
return &APIError{Operation: "create path", StatusCode: response.StatusCode()}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) GetPath(ctx context.Context, name string) (PathConfig, error) {
|
|
response, err := c.api.ConfigPathsGetWithResponse(ctx, name)
|
|
if err != nil {
|
|
return PathConfig{}, fmt.Errorf("MediaMTX read path transport: %w", err)
|
|
}
|
|
if response.StatusCode() == http.StatusNotFound {
|
|
return PathConfig{}, ErrPathNotFound
|
|
}
|
|
if response.StatusCode() != http.StatusOK || response.JSON200 == nil {
|
|
return PathConfig{}, &APIError{Operation: "read path", StatusCode: response.StatusCode()}
|
|
}
|
|
result := PathConfig{Name: name}
|
|
if response.JSON200.Name != nil {
|
|
result.Name = *response.JSON200.Name
|
|
}
|
|
if response.JSON200.Source != nil {
|
|
result.Source = *response.JSON200.Source
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (c *Client) DeletePath(ctx context.Context, name string) error {
|
|
response, err := c.api.ConfigPathsDeleteWithResponse(ctx, name)
|
|
if err != nil {
|
|
return fmt.Errorf("MediaMTX delete path transport: %w", err)
|
|
}
|
|
if response.StatusCode() == http.StatusNotFound {
|
|
return ErrPathNotFound
|
|
}
|
|
if response.StatusCode() != http.StatusOK {
|
|
return &APIError{Operation: "delete path", StatusCode: response.StatusCode()}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// EnsurePath converges one desired path. It never enumerates or deletes orphans.
|
|
func (c *Client) EnsurePath(ctx context.Context, name, source string) (bool, error) {
|
|
current, err := c.GetPath(ctx, name)
|
|
if errors.Is(err, ErrPathNotFound) {
|
|
if err := c.CreatePath(ctx, name, source); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if current.Source == source {
|
|
return false, nil
|
|
}
|
|
response, err := c.api.ConfigPathsPatchWithResponse(ctx, name, mediamtxapi.PathConf{Source: &source})
|
|
if err != nil {
|
|
return false, fmt.Errorf("MediaMTX patch path transport: %w", err)
|
|
}
|
|
if response.StatusCode() != http.StatusOK {
|
|
return false, &APIError{Operation: "patch path", StatusCode: response.StatusCode()}
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (c *Client) PathReady(ctx context.Context, name string) (bool, error) {
|
|
response, err := c.api.PathsGetWithResponse(ctx, name)
|
|
if err != nil {
|
|
return false, fmt.Errorf("MediaMTX probe path transport: %w", err)
|
|
}
|
|
if response.StatusCode() == http.StatusNotFound {
|
|
return false, ErrPathNotFound
|
|
}
|
|
if response.StatusCode() != http.StatusOK || response.JSON200 == nil {
|
|
return false, &APIError{Operation: "probe path", StatusCode: response.StatusCode()}
|
|
}
|
|
if response.JSON200.Online == nil || response.JSON200.Available == nil {
|
|
return false, &APIError{Operation: "probe path response", StatusCode: response.StatusCode()}
|
|
}
|
|
return *response.JSON200.Online && *response.JSON200.Available, nil
|
|
}
|