162 lines
3.9 KiB
Go
162 lines
3.9 KiB
Go
// Package client provides HTTP client for Wild Central daemon API
|
|
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// Client is the HTTP client for the Wild Central daemon
|
|
type Client struct {
|
|
baseURL string
|
|
httpClient *http.Client
|
|
}
|
|
|
|
// NewClient creates a new API client
|
|
func NewClient(baseURL string) *Client {
|
|
return &Client{
|
|
baseURL: baseURL,
|
|
httpClient: &http.Client{
|
|
Timeout: 30 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
// APIResponse is the API response format
|
|
type APIResponse struct {
|
|
Data map[string]interface{}
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// Get makes a GET request to the API
|
|
func (c *Client) Get(path string) (*APIResponse, error) {
|
|
return c.doRequest("GET", path, nil)
|
|
}
|
|
|
|
// Post makes a POST request to the API
|
|
func (c *Client) Post(path string, body interface{}) (*APIResponse, error) {
|
|
return c.doRequest("POST", path, body)
|
|
}
|
|
|
|
// Put makes a PUT request to the API
|
|
func (c *Client) Put(path string, body interface{}) (*APIResponse, error) {
|
|
return c.doRequest("PUT", path, body)
|
|
}
|
|
|
|
// Delete makes a DELETE request to the API
|
|
func (c *Client) Delete(path string) (*APIResponse, error) {
|
|
return c.doRequest("DELETE", path, nil)
|
|
}
|
|
|
|
// Patch makes a PATCH request to the API
|
|
func (c *Client) Patch(path string, body interface{}) (*APIResponse, error) {
|
|
return c.doRequest("PATCH", path, body)
|
|
}
|
|
|
|
// doRequest performs the actual HTTP request
|
|
func (c *Client) doRequest(method, path string, body interface{}) (*APIResponse, error) {
|
|
url := c.baseURL + path
|
|
|
|
var reqBody io.Reader
|
|
if body != nil {
|
|
jsonData, err := json.Marshal(body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal request body: %w", err)
|
|
}
|
|
reqBody = bytes.NewBuffer(jsonData)
|
|
}
|
|
|
|
req, err := http.NewRequest(method, url, reqBody)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
|
|
if body != nil {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
}
|
|
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("request failed: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
respBody, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read response: %w", err)
|
|
}
|
|
|
|
// Check for HTTP error status
|
|
if resp.StatusCode >= 400 {
|
|
// Try to parse error response
|
|
var errResp map[string]interface{}
|
|
if err := json.Unmarshal(respBody, &errResp); err == nil {
|
|
if errMsg, ok := errResp["error"].(string); ok {
|
|
return nil, fmt.Errorf("API error: %s", errMsg)
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(respBody))
|
|
}
|
|
|
|
// Parse response data directly (daemon doesn't wrap in "data" field)
|
|
var data map[string]interface{}
|
|
if err := json.Unmarshal(respBody, &data); err != nil {
|
|
return nil, fmt.Errorf("failed to parse response: %w\nResponse: %s", err, string(respBody))
|
|
}
|
|
|
|
return &APIResponse{Data: data}, nil
|
|
}
|
|
|
|
// GetData extracts data from API response
|
|
func (r *APIResponse) GetData(key string) interface{} {
|
|
if r.Data == nil {
|
|
return nil
|
|
}
|
|
return r.Data[key]
|
|
}
|
|
|
|
// GetString extracts string data from API response
|
|
func (r *APIResponse) GetString(key string) string {
|
|
val := r.GetData(key)
|
|
if str, ok := val.(string); ok {
|
|
return str
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetMap extracts map data from API response
|
|
func (r *APIResponse) GetMap(key string) map[string]interface{} {
|
|
val := r.GetData(key)
|
|
if m, ok := val.(map[string]interface{}); ok {
|
|
return m
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetArray extracts array data from API response
|
|
func (r *APIResponse) GetArray(key string) []interface{} {
|
|
val := r.GetData(key)
|
|
if arr, ok := val.([]interface{}); ok {
|
|
return arr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetBool extracts boolean data from API response
|
|
func (r *APIResponse) GetBool(key string) bool {
|
|
val := r.GetData(key)
|
|
if b, ok := val.(bool); ok {
|
|
return b
|
|
}
|
|
return false
|
|
}
|
|
|
|
// BaseURL returns the base URL of the client
|
|
func (c *Client) BaseURL() string {
|
|
return c.baseURL
|
|
}
|