chore(repo): reinitialize repository

This commit is contained in:
2026-03-18 11:29:54 +08:00
commit 24871e213a
288 changed files with 44369 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
package client
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strings"
)
type Response struct {
StatusCode int
Header http.Header
Body []byte
}
type Client struct {
baseURL string
httpClient *http.Client
}
func New(baseURL string, httpClient *http.Client) *Client {
baseURL = strings.TrimSpace(baseURL)
baseURL = strings.TrimRight(baseURL, "/")
if httpClient == nil {
httpClient = http.DefaultClient
}
return &Client{
baseURL: baseURL,
httpClient: httpClient,
}
}
func (c *Client) Do(ctx context.Context, method, path string, headers http.Header, body []byte) (Response, error) {
url, err := c.resolveURL(path)
if err != nil {
return Response{}, err
}
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(body))
if err != nil {
return Response{}, fmt.Errorf("build request: %w", err)
}
for key, values := range headers {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := c.httpClient.Do(req)
if err != nil {
return Response{}, fmt.Errorf("request %s %s: %w", method, url, err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return Response{}, fmt.Errorf("read response body: %w", err)
}
return Response{
StatusCode: resp.StatusCode,
Header: resp.Header.Clone(),
Body: respBody,
}, nil
}
func (c *Client) resolveURL(path string) (string, error) {
path = strings.TrimSpace(path)
if path == "" {
return "", fmt.Errorf("path is required")
}
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
return path, nil
}
if c.baseURL == "" {
return "", fmt.Errorf("base url is required for relative path %q", path)
}
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
return c.baseURL + path, nil
}
+34
View File
@@ -0,0 +1,34 @@
package client
import (
"context"
"net/http"
"net/http/httptest"
"testing"
)
func TestClientDoResolvesRelativePath(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/v2/topics" {
t.Fatalf("path = %q", r.URL.Path)
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"ok":true}`))
}))
defer server.Close()
resp, err := New(server.URL, server.Client()).Do(context.Background(), http.MethodGet, "/api/v2/topics", nil, nil)
if err != nil {
t.Fatalf("Do() error = %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("status = %d", resp.StatusCode)
}
}
func TestClientDoRejectsEmptyPath(t *testing.T) {
_, err := New("http://127.0.0.1:3000", nil).Do(context.Background(), http.MethodGet, "", nil, nil)
if err == nil {
t.Fatal("Do() expected error for empty path")
}
}