From ce5c94e4719586bbf81906cb90104babf79af0fe Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Fri, 19 Jun 2015 12:32:40 +0200 Subject: [PATCH] added attach over http/rpc support --- rpc/comms/comms.go | 23 +++++++++ rpc/comms/http.go | 114 +++++++++++++++++++++++++++++++++++++++++++-- rpc/comms/ipc.go | 3 +- 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/rpc/comms/comms.go b/rpc/comms/comms.go index 7aa94b1ea..29ad11b3c 100644 --- a/rpc/comms/comms.go +++ b/rpc/comms/comms.go @@ -7,6 +7,8 @@ import ( "fmt" "strings" + "strconv" + "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rpc/api" @@ -82,7 +84,28 @@ func ClientFromEndpoint(endpoint string, c codec.Codec) (EthereumClient, error) } if strings.HasPrefix(endpoint, "rpc:") { + parts := strings.Split(endpoint, ":") + addr := "http://localhost" + port := uint(8545) + if len(parts) >= 3 { + addr = parts[1] + ":" + parts[2] + } + if len(parts) >= 4 { + p, err := strconv.Atoi(parts[3]) + + if err != nil { + return nil, err + } + port = uint(p) + } + + cfg := HttpConfig{ + ListenAddress: addr, + ListenPort: port, + } + + return NewHttpClient(cfg, codec.JSON), nil } return nil, fmt.Errorf("Invalid endpoint") diff --git a/rpc/comms/http.go b/rpc/comms/http.go index 04630d937..6a543c0ed 100644 --- a/rpc/comms/http.go +++ b/rpc/comms/http.go @@ -5,10 +5,14 @@ import ( "net/http" "strings" + "bytes" + "io/ioutil" + "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/shared" "github.com/rs/cors" ) @@ -65,13 +69,19 @@ func StopHttp() { } type httpClient struct { - codec codec.ApiCoder + address string + port uint + codec codec.ApiCoder + lastRes interface{} + lastErr error } // Create a new in process client -func NewHttpClient(cfg HttpConfig, codec codec.Codec) *httpClient { +func NewHttpClient(cfg HttpConfig, c codec.Codec) *httpClient { return &httpClient{ - codec: codec.New(nil), + address: cfg.ListenAddress, + port: cfg.ListenPort, + codec: c.New(nil), } } @@ -80,9 +90,103 @@ func (self *httpClient) Close() { } func (self *httpClient) Send(req interface{}) error { - return nil + var body []byte + var err error + + self.lastRes = nil + self.lastErr = nil + + if body, err = self.codec.Encode(req); err != nil { + return err + } + + httpReq, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) + if err != nil { + return err + } + httpReq.Header.Set("Content-Type", "application/json") + + client := http.Client{} + resp, err := client.Do(httpReq) + if err != nil { + return err + } + + defer resp.Body.Close() + + if resp.Status == "200 OK" { + reply, _ := ioutil.ReadAll(resp.Body) + var rpcSuccessResponse shared.SuccessResponse + if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil { + self.lastRes = rpcSuccessResponse.Result + self.lastErr = err + return nil + } else { + var rpcErrorResponse shared.ErrorResponse + if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil { + self.lastRes = rpcErrorResponse.Error + self.lastErr = err + return nil + } else { + return err + } + } + } + + return fmt.Errorf("Not implemented") } func (self *httpClient) Recv() (interface{}, error) { - return nil, nil + return self.lastRes, self.lastErr +} + +func (self *httpClient) SupportedModules() (map[string]string, error) { + var body []byte + var err error + + payload := shared.Request{ + Id: 1, + Jsonrpc: "2.0", + Method: "modules", + } + + if body, err = self.codec.Encode(payload); err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + client := http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + if resp.Status == "200 OK" { + reply, _ := ioutil.ReadAll(resp.Body) + var rpcRes shared.SuccessResponse + if err = self.codec.Decode(reply, &rpcRes); err != nil { + return nil, err + } + + result := make(map[string]string) + if modules, ok := rpcRes.Result.(map[string]interface{}); ok { + for a, v := range modules { + result[a] = fmt.Sprintf("%s", v) + } + return result, nil + } + err = fmt.Errorf("Unable to parse module response - %v", rpcRes.Result) + } else { + fmt.Printf("resp.Status = %s\n", resp.Status) + fmt.Printf("err = %v\n", err) + } + + return nil, err } diff --git a/rpc/comms/ipc.go b/rpc/comms/ipc.go index 7e7375eaf..7f5219300 100644 --- a/rpc/comms/ipc.go +++ b/rpc/comms/ipc.go @@ -4,10 +4,11 @@ import ( "fmt" "net" + "encoding/json" + "github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/shared" - "encoding/json" ) type IpcConfig struct {