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 }