Ctrl K
ComunidadGuías…

internal/updatecdn/client.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package updatecdn

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type Resolver interface {
	Resolve(ctx context.Context, req ResolveRequest) (*ResolvedUpdate, error)
}

type Client struct {
	baseURL string
	http    *http.Client
}

func NewClient(baseURL string, timeout time.Duration) (*Client, error) {
	baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/")
	parsed, err := url.Parse(baseURL)
	if err != nil {
		return nil, fmt.Errorf("parse update service URL: %w", err)
	}
	if (parsed.Scheme != "http" && parsed.Scheme != "https") || parsed.Hostname() == "" || parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" {
		return nil, fmt.Errorf("update service URL must be an HTTP(S) base URL without credentials, query, or fragment")
	}
	if timeout <= 0 {
		timeout = 2 * time.Second
	}
	return &Client{baseURL: baseURL, http: &http.Client{Timeout: timeout}}, nil
}

func (c *Client) Resolve(ctx context.Context, request ResolveRequest) (*ResolvedUpdate, error) {
	u, err := url.Parse(c.baseURL + "/v1/resolve")
	if err != nil {
		return nil, err
	}
	query := u.Query()
	query.Set("platform", request.Platform)
	query.Set("channel", request.Channel)
	query.Set("version", request.Version)
	query.Set("source", request.Source)
	query.Set("lang_code", request.LangCode)
	u.RawQuery = query.Encode()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("build update resolve request: %w", err)
	}
	resp, err := c.http.Do(req)
	if err != nil {
		return nil, fmt.Errorf("resolve application update: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNoContent {
		return nil, nil
	}
	if resp.StatusCode != http.StatusOK {
		_, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, 4<<10))
		return nil, fmt.Errorf("resolve application update: HTTP %d", resp.StatusCode)
	}
	var resolved ResolvedUpdate
	decoder := json.NewDecoder(io.LimitReader(resp.Body, 256<<10))
	decoder.DisallowUnknownFields()
	if err := decoder.Decode(&resolved); err != nil {
		return nil, fmt.Errorf("decode application update: %w", err)
	}
	if resolved.ID <= 0 || strings.TrimSpace(resolved.Version) == "" || strings.TrimSpace(resolved.Text) == "" {
		return nil, fmt.Errorf("resolve application update: incomplete response")
	}
	return &resolved, nil
}