jldb/lib/rep/http-client.go

110 lines
2.0 KiB
Go

package rep
import (
"encoding/json"
"net"
"net/http"
"strings"
"sync"
"time"
"git.crumpington.com/public/jldb/lib/errs"
"git.crumpington.com/public/jldb/lib/httpconn"
"git.crumpington.com/public/jldb/lib/wal"
)
type client struct {
client *http.Client
// The following are constant.
endpoint string
pskBytes [64]byte
timeout time.Duration
lock sync.Mutex
conn net.Conn
}
func newClient(endpoint, psk string, timeout time.Duration) *client {
httpClient := &http.Client{
Timeout: timeout,
}
if !strings.HasSuffix(endpoint, "/") {
endpoint += "/"
}
return &client{
client: httpClient,
endpoint: endpoint,
pskBytes: pskToBytes(psk),
timeout: timeout,
}
}
func (c *client) GetInfo() (info Info, err error) {
req, err := http.NewRequest(http.MethodGet, c.endpoint+pathGetInfo, nil)
if err != nil {
return info, errs.Unexpected.WithErr(err)
}
req.SetBasicAuth("", string(c.pskBytes[:]))
resp, err := c.client.Do(req)
if err != nil {
return info, errs.IO.WithErr(err)
}
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return info, errs.IO.WithErr(err)
}
return info, nil
}
func (c *client) RecvState(recv func(net.Conn) error) error {
err := c.dialConnect(c.endpoint + pathSendState)
if err != nil {
return err
}
defer c.conn.Close()
return recv(c.conn)
}
func (c *client) StreamWAL(w *wal.WAL) error {
err := c.dialConnect(c.endpoint + pathStreamWAL)
if err != nil {
return err
}
defer c.conn.Close()
return w.Recv(c.conn, c.timeout)
}
func (c *client) Close() {
c.lock.Lock()
defer c.lock.Unlock()
if c.conn != nil {
c.conn.Close()
}
}
// ----------------------------------------------------------------------------
func (c *client) dialConnect(endpoint string) error {
conn, err := httpconn.Dial(endpoint)
if err != nil {
return err
}
conn.SetWriteDeadline(time.Now().Add(c.timeout))
if _, err := conn.Write(c.pskBytes[:]); err != nil {
return errs.IO.WithErr(err)
}
c.lock.Lock()
defer c.lock.Unlock()
c.conn = conn
return nil
}