Browse Source

support full urls (with eg tcp:// prefix)

pull/456/head
Ethan Buchman 9 years ago
parent
commit
479510be0e
5 changed files with 65 additions and 32 deletions
  1. +37
    -21
      client/http_client.go
  2. +7
    -3
      client/ws_client.go
  3. +2
    -2
      rpc_test.go
  4. +18
    -5
      server/http_server.go
  5. +1
    -1
      version.go

+ 37
- 21
client/http_client.go View File

@ -8,26 +8,40 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"strings"
. "github.com/tendermint/go-common" . "github.com/tendermint/go-common"
"github.com/tendermint/go-rpc/types" "github.com/tendermint/go-rpc/types"
"github.com/tendermint/go-wire" "github.com/tendermint/go-wire"
) )
// Set the net.Dial manually so we can do http over tcp or unix.
// Get/Post require a dummyDomain but it's over written by the Transport
var dummyDomain = "http://dummyDomain"
// TODO: Deprecate support for IP:PORT or /path/to/socket
func makeHTTPDialer(remoteAddr string) (string, func(string, string) (net.Conn, error)) {
func dialer(remote string) func(string, string) (net.Conn, error) {
return func(proto, addr string) (conn net.Conn, err error) {
return net.Dial(rpctypes.SocketType(remote), remote)
parts := strings.SplitN(remoteAddr, "://", 2)
var protocol, address string
if len(parts) != 2 {
log.Warn("WARNING (go-rpc): Please use fully formed listening addresses, including the tcp:// or unix:// prefix")
protocol = rpctypes.SocketType(remoteAddr)
address = remoteAddr
} else {
protocol, address = parts[0], parts[1]
}
trimmedAddress := strings.Replace(address, "/", ".", -1) // replace / with . for http requests (dummy domain)
return trimmedAddress, func(proto, addr string) (net.Conn, error) {
return net.Dial(protocol, address)
} }
} }
// remote is IP:PORT or /path/to/socket
func socketTransport(remote string) *http.Transport {
return &http.Transport{
Dial: dialer(remote),
// We overwrite the http.Client.Dial so we can do http over tcp or unix.
// remoteAddr should be fully featured (eg. with tcp:// or unix://)
func makeHTTPClient(remoteAddr string) (string, *http.Client) {
address, dialer := makeHTTPDialer(remoteAddr)
return "http://" + address, &http.Client{
Transport: &http.Transport{
Dial: dialer,
},
} }
} }
@ -40,14 +54,15 @@ type Client interface {
// JSON rpc takes params as a slice // JSON rpc takes params as a slice
type ClientJSONRPC struct { type ClientJSONRPC struct {
remote string
client *http.Client
address string
client *http.Client
} }
func NewClientJSONRPC(remote string) *ClientJSONRPC { func NewClientJSONRPC(remote string) *ClientJSONRPC {
address, client := makeHTTPClient(remote)
return &ClientJSONRPC{ return &ClientJSONRPC{
remote: remote,
client: &http.Client{Transport: socketTransport(remote)},
address: address,
client: client,
} }
} }
@ -66,7 +81,7 @@ func (c *ClientJSONRPC) call(method string, params []interface{}, result interfa
requestBytes := wire.JSONBytes(request) requestBytes := wire.JSONBytes(request)
requestBuf := bytes.NewBuffer(requestBytes) requestBuf := bytes.NewBuffer(requestBytes)
// log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes))) // log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes)))
httpResponse, err := c.client.Post(dummyDomain, "text/json", requestBuf)
httpResponse, err := c.client.Post(c.address, "text/json", requestBuf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,14 +98,15 @@ func (c *ClientJSONRPC) call(method string, params []interface{}, result interfa
// URI takes params as a map // URI takes params as a map
type ClientURI struct { type ClientURI struct {
remote string
client *http.Client
address string
client *http.Client
} }
func NewClientURI(remote string) *ClientURI { func NewClientURI(remote string) *ClientURI {
address, client := makeHTTPClient(remote)
return &ClientURI{ return &ClientURI{
remote: remote,
client: &http.Client{Transport: socketTransport(remote)},
address: address,
client: client,
} }
} }
@ -103,8 +119,8 @@ func (c *ClientURI) call(method string, params map[string]interface{}, result in
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Info(Fmt("URI request to %v (%v): %v", c.remote, method, values))
resp, err := c.client.PostForm(dummyDomain+"/"+method, values)
log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
resp, err := c.client.PostForm(c.address+"/"+method, values)
if err != nil { if err != nil {
return nil, err return nil, err
} }


+ 7
- 3
client/ws_client.go View File

@ -3,6 +3,7 @@ package rpcclient
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"net/http" "net/http"
"time" "time"
@ -21,15 +22,18 @@ type WSClient struct {
QuitService QuitService
Address string // IP:PORT or /path/to/socket Address string // IP:PORT or /path/to/socket
Endpoint string // /websocket/url/endpoint Endpoint string // /websocket/url/endpoint
Dialer func(string, string) (net.Conn, error)
*websocket.Conn *websocket.Conn
ResultsCh chan json.RawMessage // closes upon WSClient.Stop() ResultsCh chan json.RawMessage // closes upon WSClient.Stop()
ErrorsCh chan error // closes upon WSClient.Stop() ErrorsCh chan error // closes upon WSClient.Stop()
} }
// create a new connection // create a new connection
func NewWSClient(addr, endpoint string) *WSClient {
func NewWSClient(remoteAddr, endpoint string) *WSClient {
addr, dialer := makeHTTPDialer(remoteAddr)
wsClient := &WSClient{ wsClient := &WSClient{
Address: addr, Address: addr,
Dialer: dialer,
Endpoint: endpoint, Endpoint: endpoint,
Conn: nil, Conn: nil,
ResultsCh: make(chan json.RawMessage, wsResultsChannelCapacity), ResultsCh: make(chan json.RawMessage, wsResultsChannelCapacity),
@ -57,11 +61,11 @@ func (wsc *WSClient) dial() error {
// Dial // Dial
dialer := &websocket.Dialer{ dialer := &websocket.Dialer{
NetDial: dialer(wsc.Address),
NetDial: wsc.Dialer,
Proxy: http.ProxyFromEnvironment, Proxy: http.ProxyFromEnvironment,
} }
rHeader := http.Header{} rHeader := http.Header{}
con, _, err := dialer.Dial("ws://"+dummyDomain+wsc.Endpoint, rHeader)
con, _, err := dialer.Dial("ws://"+wsc.Address+wsc.Endpoint, rHeader)
if err != nil { if err != nil {
return err return err
} }


+ 2
- 2
rpc_test.go View File

@ -13,8 +13,8 @@ import (
// Client and Server should work over tcp or unix sockets // Client and Server should work over tcp or unix sockets
var ( var (
tcpAddr = "0.0.0.0:46657"
unixAddr = "/tmp/go-rpc.sock" // NOTE: must remove file for test to run again
tcpAddr = "tcp://0.0.0.0:46657"
unixAddr = "unix:///tmp/go-rpc.sock" // NOTE: must remove file for test to run again
websocketEndpoint = "/websocket/endpoint" websocketEndpoint = "/websocket/endpoint"
) )


+ 18
- 5
server/http_server.go View File

@ -8,6 +8,7 @@ import (
"net" "net"
"net/http" "net/http"
"runtime/debug" "runtime/debug"
"strings"
"time" "time"
. "github.com/tendermint/go-common" . "github.com/tendermint/go-common"
@ -15,11 +16,23 @@ import (
//"github.com/tendermint/go-wire" //"github.com/tendermint/go-wire"
) )
func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, error) {
// listenAddr is `IP:PORT` or /path/to/socket
socketType := SocketType(listenAddr)
log.Notice(Fmt("Starting RPC HTTP server on %s socket %v", socketType, listenAddr))
listener, err := net.Listen(socketType, listenAddr)
func StartHTTPServer(listenAddr string, handler http.Handler) (listener net.Listener, err error) {
// listenAddr should be fully formed including tcp:// or unix:// prefix
var proto, addr string
parts := strings.SplitN(listenAddr, "://", 2)
if len(parts) != 2 {
log.Warn("WARNING (go-rpc): Please use fully formed listening addresses, including the tcp:// or unix:// prefix")
// we used to allow addrs without tcp/unix prefix by checking for a colon
// TODO: Deprecate
proto = SocketType(listenAddr)
addr = listenAddr
// return nil, fmt.Errorf("Invalid listener address %s", lisenAddr)
} else {
proto, addr = parts[0], parts[1]
}
log.Notice(Fmt("Starting RPC HTTP server on %s socket %v", proto, addr))
listener, err = net.Listen(proto, addr)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to listen to %v: %v", listenAddr, err) return nil, fmt.Errorf("Failed to listen to %v: %v", listenAddr, err)
} }


+ 1
- 1
version.go View File

@ -2,6 +2,6 @@ package rpc
const Maj = "0" const Maj = "0"
const Min = "5" // refactored out of tendermint/tendermint; RPCResponse.Result is RawJSON const Min = "5" // refactored out of tendermint/tendermint; RPCResponse.Result is RawJSON
const Fix = "0"
const Fix = "1" // support tcp:// or unix:// prefixes
const Version = Maj + "." + Min + "." + Fix const Version = Maj + "." + Min + "." + Fix

Loading…
Cancel
Save