2016-11-13 21:16:20 -08:00
|
|
|
package constellation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"github.com/tv42/httpunix"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2018-02-08 13:16:40 -08:00
|
|
|
"strings"
|
2016-11-13 21:16:20 -08:00
|
|
|
"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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 13:16:40 -08:00
|
|
|
func RunNode(socketPath string) error {
|
|
|
|
c := unixClient(socketPath)
|
2016-11-13 21:16:20 -08:00
|
|
|
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 {
|
2018-02-08 13:16:40 -08:00
|
|
|
httpClient *http.Client
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
|
|
|
|
2018-02-08 13:16:40 -08:00
|
|
|
func (c *Client) doJson(path string, apiReq interface{}) (*http.Response, error) {
|
2016-11-13 21:16:20 -08:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
err := json.NewEncoder(buf).Encode(apiReq)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-11-13 21:35:27 -08:00
|
|
|
req, err := http.NewRequest("POST", "http+unix://c/"+path, buf)
|
2016-11-13 21:16:20 -08:00
|
|
|
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) {
|
2018-02-08 13:16:40 -08:00
|
|
|
buf := bytes.NewBuffer(pl)
|
|
|
|
req, err := http.NewRequest("POST", "http+unix://c/sendraw", buf)
|
2016-11-13 21:16:20 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-02-08 13:16:40 -08:00
|
|
|
if b64From != "" {
|
|
|
|
req.Header.Set("c11n-from", b64From)
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
2018-02-08 13:16:40 -08:00
|
|
|
req.Header.Set("c11n-to", strings.Join(b64To, ","))
|
|
|
|
req.Header.Set("Content-Type", "application/octet-stream")
|
|
|
|
res, err := c.httpClient.Do(req)
|
2018-08-22 06:32:59 -07:00
|
|
|
|
|
|
|
if res != nil {
|
|
|
|
defer res.Body.Close()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if res.StatusCode != 200 {
|
2018-02-08 13:16:40 -08:00
|
|
|
return nil, fmt.Errorf("Non-200 status code: %+v", res)
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
2018-08-22 06:32:59 -07:00
|
|
|
|
2018-02-21 13:12:19 -08:00
|
|
|
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) ReceivePayload(key []byte) ([]byte, error) {
|
2018-02-08 13:16:40 -08:00
|
|
|
req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil)
|
2016-11-13 21:16:20 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-02-08 13:16:40 -08:00
|
|
|
req.Header.Set("c11n-key", base64.StdEncoding.EncodeToString(key))
|
|
|
|
res, err := c.httpClient.Do(req)
|
2018-08-22 06:32:59 -07:00
|
|
|
|
|
|
|
if res != nil {
|
|
|
|
defer res.Body.Close()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if res.StatusCode != 200 {
|
2018-02-08 13:16:40 -08:00
|
|
|
return nil, fmt.Errorf("Non-200 status code: %+v", res)
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
2018-08-22 06:32:59 -07:00
|
|
|
|
2018-02-08 13:16:40 -08:00
|
|
|
return ioutil.ReadAll(res.Body)
|
2016-11-13 21:16:20 -08:00
|
|
|
}
|
|
|
|
|
2018-02-08 13:16:40 -08:00
|
|
|
func NewClient(socketPath string) (*Client, error) {
|
2016-11-13 21:16:20 -08:00
|
|
|
return &Client{
|
2018-02-08 13:16:40 -08:00
|
|
|
httpClient: unixClient(socketPath),
|
2016-11-13 21:16:20 -08:00
|
|
|
}, nil
|
|
|
|
}
|