isle/go/daemon/jsonrpc2/client_http.go

91 lines
1.9 KiB
Go
Raw Normal View History

package jsonrpc2
import (
"bytes"
"context"
"encoding/json"
2024-11-18 21:25:49 +00:00
"errors"
"fmt"
"net/http"
"net/url"
"github.com/tv42/httpunix"
)
type httpClient struct {
c *http.Client
url string
}
// NewHTTPClient returns a Client which will use HTTP POST requests against the
// given URL as a transport for JSONRPC2 method calls.
func NewHTTPClient(urlStr string) Client {
return &httpClient{
c: &http.Client{
Transport: http.DefaultTransport.(*http.Transport).Clone(),
},
url: urlStr,
}
}
// NewUnixHTTPClient returns a Client which will use HTTP POST requests against
// the given unix socket as a transport for JSONRPC2 method calls. The given
// path will be used as the path portion of the HTTP request.
func NewUnixHTTPClient(unixSocketPath, reqPath string) Client {
const host = "uds"
u := &url.URL{
Scheme: httpunix.Scheme,
Host: host,
Path: reqPath,
}
transport := new(httpunix.Transport)
transport.RegisterLocation(host, unixSocketPath)
return &httpClient{
c: &http.Client{Transport: transport},
url: u.String(),
}
}
func (c *httpClient) Call(
ctx context.Context, rcv any, method string, args ...any,
) error {
var (
body = new(bytes.Buffer)
enc = json.NewEncoder(body)
)
id, err := encodeRequest(ctx, enc, method, args)
if err != nil {
return fmt.Errorf("encoding request: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", c.url, body)
if err != nil {
return fmt.Errorf("constructing POST request to %q: %w", c.url, err)
}
res, err := c.c.Do(req)
if err != nil {
return fmt.Errorf("performing request: %w", err)
}
defer res.Body.Close()
dec := json.NewDecoder(res.Body)
resID, err := decodeResponse(dec, rcv)
2024-11-18 21:25:49 +00:00
if errors.As(err, new(Error)) {
return err
} else if err != nil {
return fmt.Errorf("decoding response: %w", err)
} else if resID != id {
return fmt.Errorf(
"expected response with ID %q, got %q", id, resID,
)
}
return nil
}