package controlplane import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "time" ) type Backend struct { Host string `json:"host"` Port int `json:"port"` } type ResolveResponse struct { ServerID string `json:"serverId"` Slug string `json:"slug"` Status string `json:"status"` JoinToStartEnabled bool `json:"joinToStartEnabled"` Edition string `json:"edition"` Backend *Backend `json:"backend"` Action string `json:"action"` Message string `json:"message,omitempty"` } type StartResponse struct { Resolve ResolveResponse `json:"resolve"` Started bool `json:"started"` JobID string `json:"jobId,omitempty"` QueuePosition int `json:"queuePosition,omitempty"` } type Client struct { baseURL string edgeKey string httpClient *http.Client } func NewClient(baseURL, edgeKey string) *Client { return &Client{ baseURL: baseURL, edgeKey: edgeKey, httpClient: &http.Client{ Timeout: 15 * time.Second, }, } } func (c *Client) Resolve(slug, clientIP string) (*ResolveResponse, error) { endpoint := fmt.Sprintf("%s/internal/edge/v1/resolve/%s", c.baseURL, url.PathEscape(slug)) if clientIP != "" { endpoint = endpoint + "?clientIp=" + url.QueryEscape(clientIP) } req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { return nil, err } c.applyHeaders(req) resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode == http.StatusNotFound { return nil, fmt.Errorf("unknown slug") } if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("resolve failed: %s", string(body)) } var result ResolveResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return &result, nil } func (c *Client) Start(slug, clientIP string) (*StartResponse, error) { endpoint := fmt.Sprintf("%s/internal/edge/v1/start/%s", c.baseURL, url.PathEscape(slug)) payload, err := json.Marshal(map[string]string{"clientIp": clientIP}) if err != nil { return nil, err } req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(payload)) if err != nil { return nil, err } c.applyHeaders(req) req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("start failed: %s", string(body)) } var result StartResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return &result, nil } func (c *Client) applyHeaders(req *http.Request) { req.Header.Set("X-HexaHost-Edge-Key", c.edgeKey) }