quorum/private/constellation/node.go

159 lines
3.6 KiB
Go

package constellation
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/tv42/httpunix"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
)
func launchNode(cfgPath string) (*exec.Cmd, error) {
cmd := exec.Command("constellation-node", cfgPath)
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
go io.Copy(os.Stderr, stderr)
if err := cmd.Start(); err != nil {
return nil, err
}
time.Sleep(100 * time.Millisecond)
return cmd, nil
}
func unixTransport(socketPath string) *httpunix.Transport {
t := &httpunix.Transport{
DialTimeout: 1 * time.Second,
RequestTimeout: 5 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
}
t.RegisterLocation("c", socketPath)
return t
}
func unixClient(socketPath string) *http.Client {
return &http.Client{
Transport: unixTransport(socketPath),
}
}
func RunNode(socketPath string) error {
c := unixClient(socketPath)
res, err := c.Get("http+unix://c/upcheck")
if err != nil {
return err
}
if res.StatusCode == 200 {
return nil
}
return errors.New("Constellation Node API did not respond to upcheck request")
}
type Client struct {
httpClient *http.Client
}
func (c *Client) doJson(path string, apiReq interface{}) (*http.Response, error) {
buf := new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(apiReq)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", "http+unix://c/"+path, buf)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
res, err := c.httpClient.Do(req)
if err == nil && res.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 status code: %+v", res)
}
return res, err
}
func (c *Client) SendPayload(pl []byte, b64From string, b64To []string) ([]byte, error) {
buf := bytes.NewBuffer(pl)
req, err := http.NewRequest("POST", "http+unix://c/sendraw", buf)
if err != nil {
return nil, err
}
if b64From != "" {
req.Header.Set("c11n-from", b64From)
}
req.Header.Set("c11n-to", strings.Join(b64To, ","))
req.Header.Set("Content-Type", "application/octet-stream")
res, err := c.httpClient.Do(req)
if res != nil {
defer res.Body.Close()
}
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 status code: %+v", res)
}
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
}
func (c *Client) SendSignedPayload(signedPayload []byte, b64To []string) ([]byte, error) {
buf := bytes.NewBuffer(signedPayload)
req, err := http.NewRequest("POST", "http+unix://c/sendsignedtx", buf)
if err != nil {
return nil, err
}
req.Header.Set("c11n-to", strings.Join(b64To, ","))
req.Header.Set("Content-Type", "application/octet-stream")
res, err := c.httpClient.Do(req)
if res != nil {
defer res.Body.Close()
}
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 status code: %+v", res)
}
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
}
func (c *Client) ReceivePayload(key []byte) ([]byte, error) {
req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil)
if err != nil {
return nil, err
}
req.Header.Set("c11n-key", base64.StdEncoding.EncodeToString(key))
res, err := c.httpClient.Do(req)
if res != nil {
defer res.Body.Close()
}
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 status code: %+v", res)
}
return ioutil.ReadAll(res.Body)
}
func NewClient(socketPath string) (*Client, error) {
return &Client{
httpClient: unixClient(socketPath),
}, nil
}