diff --git a/cmd/internal/statsapi/client.go b/cmd/internal/statsapi/client.go index 72a80d9..4d13caa 100644 --- a/cmd/internal/statsapi/client.go +++ b/cmd/internal/statsapi/client.go @@ -24,35 +24,43 @@ import ( "github.com/evanphx/json-patch/v5" ) +// DefaultClient is a statsapi.Client instantiated using http.DefaultClient. var DefaultClient = NewClient(http.DefaultClient) +// RequestSchedule uses DefaultClient to access the schedule endpoint. func RequestSchedule(sportId, teamId, date string) ([]byte, error) { return DefaultClient.RequestSchedule(sportId, teamId, date) } +// RequestFeed uses DefaultClient to access the feed endpoint. func RequestFeed(gamePk string) ([]byte, error) { return DefaultClient.RequestFeed(gamePk) } +// RequestDiffPatch uses DefaultClient to access the diffpatch endpoint. func RequestDiffPatch(gamePk, startTimecode, pushUpdateId string) (DiffPatchResponse, error) { return DefaultClient.RequestDiffPatch(gamePk, startTimecode, pushUpdateId) } +// RequestContent uses DefaultClient to access the content endpoint. func RequestContent(gamePk string) ([]byte, error) { return DefaultClient.RequestContent(gamePk) } +// RequestStandings uses DefaultClient to access the standings endpoint. func RequestStandings(leagueId string) ([]byte, error) { return DefaultClient.RequestStandings(leagueId) } type DiffPatchResponse []byte +// Client is a struct used for making Stats API requests. type Client struct { baseURL url.URL httpClient *http.Client } +// NewClient returns a statsapi.Client with statsapi.mlb.com as the base URL. func NewClient(c *http.Client) *Client { return &Client{ baseURL: url.URL{ @@ -63,6 +71,9 @@ func NewClient(c *http.Client) *Client { } } +// ExtractPatches extracts a list of jsonpatch.Patch structs from the response +// given by the diffpatch endpoint. These patches can then be applied more +// easily than the raw response. func (resp *DiffPatchResponse) ExtractPatches() ([]jsonpatch.Patch, error) { var patches []jsonpatch.Patch @@ -80,6 +91,7 @@ func (resp *DiffPatchResponse) ExtractPatches() ([]jsonpatch.Patch, error) { return patches, err } +// RequestSchedule accesses the schedule endpoint. func (c *Client) RequestSchedule(sportId, teamId, date string) ([]byte, error) { endpoint := url.URL{Path: "api/v1/schedule"} query := endpoint.Query() @@ -91,11 +103,13 @@ func (c *Client) RequestSchedule(sportId, teamId, date string) ([]byte, error) { return c.get(&endpoint) } +// RequestFeed accesses the feed endpoint. func (c *Client) RequestFeed(gamePk string) ([]byte, error) { endpoint := url.URL{Path: "api/v1.1/game/" + gamePk + "/feed/live"} return c.get(&endpoint) } +// RequestDiffPatch accesses the diffpatch endpoint. func (c *Client) RequestDiffPatch(gamePk, startTimecode, pushUpdateId string) (DiffPatchResponse, error) { endpoint := url.URL{Path: "api/v1.1/game/" + gamePk + "/feed/live/diffPatch"} query := endpoint.Query() @@ -107,11 +121,13 @@ func (c *Client) RequestDiffPatch(gamePk, startTimecode, pushUpdateId string) (D return c.get(&endpoint) } +// RequestContent accesses the content endpoint. func (c *Client) RequestContent(gamePk string) ([]byte, error) { endpoint := url.URL{Path: "api/v1/game/" + gamePk + "/content"} return c.get(&endpoint) } +// RequestStandings accesses the standings endpoint. func (c *Client) RequestStandings(leagueId string) ([]byte, error) { endpoint := url.URL{Path: "api/v1/standings"} query := endpoint.Query() @@ -121,6 +137,8 @@ func (c *Client) RequestStandings(leagueId string) ([]byte, error) { return c.get(&endpoint) } +// get makes a GET request to the given endpoint and returns the bytes from the +// body of the response. func (c *Client) get(endpoint *url.URL) ([]byte, error) { url := c.baseURL.ResolveReference(endpoint) diff --git a/cmd/internal/statsapi/sports.go b/cmd/internal/statsapi/sports.go index 88797f9..b028496 100644 --- a/cmd/internal/statsapi/sports.go +++ b/cmd/internal/statsapi/sports.go @@ -17,6 +17,8 @@ package statsapi type SportID int +// These are all the Sport IDs used in some of the API calls, like the schedule +// endpoint. const ( MLB SportID = 1 TripleA SportID = 11 diff --git a/cmd/internal/statsapi/websocket.go b/cmd/internal/statsapi/websocket.go index 4d84063..fba6c01 100644 --- a/cmd/internal/statsapi/websocket.go +++ b/cmd/internal/statsapi/websocket.go @@ -22,6 +22,8 @@ import ( "github.com/gorilla/websocket" ) +// Push is a struct for holding data sent to us through the websocket that we +// care about. type Push struct { UpdateId string } @@ -31,11 +33,15 @@ const ( GameUnavailableCode = 4400 ) +// GamedayWebsocket is a struct for establishing a websocket connection with +// the Stats API. type GamedayWebsocket struct { baseURL url.URL *websocket.Conn } +// NewGamedayWebsocket creates a statsapi.GamedayWebsocket using the Stats API +// websocket URL and establishes a connection. func NewGamedayWebsocket(gamePk string) (*GamedayWebsocket, error) { ws := GamedayWebsocket{ baseURL: url.URL{ @@ -60,12 +66,16 @@ func (g *GamedayWebsocket) init(gamePk string) error { return err } +// SendKeepAlive sends the keep-alive message observed to be sent by MLB +// Gameday ("Gameday5"). func (g *GamedayWebsocket) SendKeepAlive() error { msg := []byte("Gameday5") err := g.Conn.WriteMessage(websocket.TextMessage, msg) return err } +// KeepAlive sends the keep-alive message on a certain interval and sends any +// errors to ch. func (g *GamedayWebsocket) KeepAlive(interval time.Duration, ch chan<- error) { ticker := time.NewTicker(interval) defer ticker.Stop()