package client import ( "bytes" "encoding/json" "fmt" "io" "net/http" "strings" "time" ) type Client struct { BaseURL string Token string HTTP *http.Client UserAgent string } func New(baseURL, token string) *Client { return &Client{ BaseURL: strings.TrimRight(baseURL, "/"), Token: token, HTTP: &http.Client{Timeout: 30 * time.Second}, UserAgent: "drm-agent/1.0", } } type Stream struct { ID int64 `json:"id"` Name string `json:"name"` Title string `json:"title"` App string `json:"app"` Channel string `json:"channel"` MPD string `json:"mpd"` Key string `json:"key"` Enabled bool `json:"enabled"` Health string `json:"health"` LastError string `json:"last_error"` PlaylistAgeS float64 `json:"playlist_age_s"` ClaimedBy string `json:"claimed_by"` } type Credentials struct { MPD string `json:"mpd"` Key string `json:"key"` PSSH string `json:"pssh,omitempty"` Auth string `json:"auth,omitempty"` PID string `json:"pid,omitempty"` } func (c *Client) Health() error { _, err := c.do(http.MethodGet, "/api/health", nil) return err } func (c *Client) ListStreams() ([]Stream, error) { body, err := c.do(http.MethodGet, "/api/streams", nil) if err != nil { return nil, err } var wrap struct { Streams []Stream `json:"streams"` } if err := json.Unmarshal(body, &wrap); err != nil { return nil, err } return wrap.Streams, nil } func (c *Client) Claim(id int64, agentID string, ttlSec int) error { payload := map[string]any{"agent_id": agentID, "ttl_sec": ttlSec} _, err := c.do(http.MethodPost, fmt.Sprintf("/api/streams/%d/claim", id), payload) return err } func (c *Client) ReleaseClaim(id int64, agentID string) error { payload := map[string]any{"agent_id": agentID} _, err := c.do(http.MethodPost, fmt.Sprintf("/api/streams/%d/claim/release", id), payload) return err } func (c *Client) PostCredentials(id int64, cred Credentials) error { _, err := c.do(http.MethodPost, fmt.Sprintf("/api/streams/%d/credentials", id), cred) return err } func (c *Client) do(method, path string, payload any) ([]byte, error) { var rdr io.Reader if payload != nil { b, err := json.Marshal(payload) if err != nil { return nil, err } rdr = bytes.NewReader(b) } req, err := http.NewRequest(method, c.BaseURL+path, rdr) if err != nil { return nil, err } if payload != nil { req.Header.Set("Content-Type", "application/json") } req.Header.Set("User-Agent", c.UserAgent) if c.Token != "" { req.Header.Set("Authorization", "Bearer "+c.Token) } resp, err := c.HTTP.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode >= 300 { return nil, fmt.Errorf("%s %s: %s — %s", method, path, resp.Status, strings.TrimSpace(string(body))) } return body, nil }