···
···
IsWrite bool `json:"is_write,omitempty"`
// EditorName is the optional name of the editor or IDE being used
EditorName string `json:"editor_name,omitempty"`
84
+
// Branch is the optional git branch name
85
+
Branch string `json:"branch,omitempty"`
86
+
// Category is the optional activity category
87
+
Category string `json:"category,omitempty"`
88
+
// LineCount is the optional number of lines in the file
89
+
LineCount int `json:"lines,omitempty"`
90
+
// UserAgent is the optional user agent string
91
+
UserAgent string `json:"user_agent,omitempty"`
92
+
// EntityType is the optional entity type (usually redundant with Type)
93
+
EntityType string `json:"entity_type,omitempty"`
94
+
// Dependencies is an optional list of project dependencies
95
+
Dependencies []string `json:"dependencies,omitempty"`
96
+
// ProjectRootCount is the optional number of directories in the project root path
97
+
ProjectRootCount int `json:"project_root_count,omitempty"`
// StatusBarResponse represents the response from the WakaTime Status Bar API endpoint.
···
// SendHeartbeat sends a coding activity heartbeat to the WakaTime API.
// It returns an error if the request fails or returns a non-success status code.
func (c *Client) SendHeartbeat(heartbeat Heartbeat) error {
120
+
// Set the user agent in the heartbeat data
121
+
if heartbeat.UserAgent == "" {
122
+
heartbeat.UserAgent = "wakatime/unset (" + runtime.GOOS + "-" + runtime.GOARCH + ") akami-wakatime/1.0.0"
data, err := json.Marshal(heartbeat)
return fmt.Errorf("%w: %v", ErrMarshalingHeartbeat, err)
···
req.Header.Set("Content-Type", "application/json")
115
-
req.Header.Set("Authorization", "Basic "+c.APIKey)
136
+
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.APIKey)))
137
+
// Set the user agent in the request header as well
138
+
req.Header.Set("User-Agent", "wakatime/unset ("+runtime.GOOS+"-"+runtime.GOARCH+") akami-wakatime/1.0.0")
resp, err := c.HTTPClient.Do(req)
···
146
+
// Read and log the response
147
+
var respBody bytes.Buffer
148
+
_, err = respBody.ReadFrom(resp.Body)
150
+
return fmt.Errorf("failed to read response body: %v", err)
153
+
respContent := respBody.String()
if resp.StatusCode == http.StatusUnauthorized {
124
-
return ErrUnauthorized
156
+
return fmt.Errorf("%w: %s", ErrUnauthorized, respContent)
} else if resp.StatusCode < 200 || resp.StatusCode >= 300 {
126
-
return fmt.Errorf("%w: status code %d", ErrInvalidStatusCode, resp.StatusCode)
158
+
return fmt.Errorf("%w: status code %d, response: %s", ErrInvalidStatusCode, resp.StatusCode, respContent)
···
return StatusBarResponse{}, fmt.Errorf("%w: %v", ErrCreatingRequest, err)
140
-
req.Header.Set("Authorization", "Basic "+c.APIKey)
172
+
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.APIKey)))
resp, err := c.HTTPClient.Do(req)
···
180
+
// Read the response body for potential error messages
181
+
var respBody bytes.Buffer
182
+
_, err = respBody.ReadFrom(resp.Body)
184
+
return StatusBarResponse{}, fmt.Errorf("failed to read response body: %v", err)
187
+
respContent := respBody.String()
if resp.StatusCode == http.StatusUnauthorized {
149
-
return StatusBarResponse{}, ErrUnauthorized
190
+
return StatusBarResponse{}, fmt.Errorf("%w: %s", ErrUnauthorized, respContent)
} else if resp.StatusCode < 200 || resp.StatusCode >= 300 {
151
-
return StatusBarResponse{}, fmt.Errorf("%w: status code %d", ErrInvalidStatusCode, resp.StatusCode)
192
+
return StatusBarResponse{}, fmt.Errorf("%w: status code %d, response: %s", ErrInvalidStatusCode, resp.StatusCode, respContent)
var durationResp StatusBarResponse
155
-
if err := json.NewDecoder(resp.Body).Decode(&durationResp); err != nil {
156
-
return StatusBarResponse{}, fmt.Errorf("%w: %v", ErrDecodingResponse, err)
196
+
if err := json.Unmarshal(respBody.Bytes(), &durationResp); err != nil {
197
+
return StatusBarResponse{}, fmt.Errorf("%w: %v, response: %s", ErrDecodingResponse, err, respContent)