The JSON-RPC endpoint accepts requests via URL (GET) and JSON (POST). There is no real point in having client libraries for both modes. A search of the SDK and on GitHub suggests that most usage is via the JSON client (via the New constructor) or websocket (NewWS), and the only uses I found of the NewURI client constructor are in copies of our own test code. This does not change the functionalitiy of the server, so curl and other URL-based clients in other languages will still function as before.pull/7477/head
@ -1,39 +0,0 @@ | |||
package client | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
"github.com/stretchr/testify/require" | |||
) | |||
type Tx []byte | |||
type Foo struct { | |||
Bar int | |||
Baz string | |||
} | |||
func TestArgToJSON(t *testing.T) { | |||
assert := assert.New(t) | |||
require := require.New(t) | |||
cases := []struct { | |||
input interface{} | |||
expected string | |||
}{ | |||
{[]byte("1234"), "0x31323334"}, | |||
{Tx("654"), "0x363534"}, | |||
{Foo{7, "hello"}, `{"Bar":"7","Baz":"hello"}`}, | |||
} | |||
for i, tc := range cases { | |||
args := map[string]interface{}{"data": tc.input} | |||
err := argsToJSON(args) | |||
require.Nil(err, "%d: %+v", i, err) | |||
require.Equal(1, len(args), "%d", i) | |||
data, ok := args["data"].(string) | |||
require.True(ok, "%d: %#v", i, args["data"]) | |||
assert.Equal(tc.expected, data, "%d", i) | |||
} | |||
} |
@ -1,46 +0,0 @@ | |||
package client | |||
import ( | |||
"fmt" | |||
"net/url" | |||
"reflect" | |||
tmjson "github.com/tendermint/tendermint/libs/json" | |||
) | |||
func argsToURLValues(args map[string]interface{}) (url.Values, error) { | |||
values := make(url.Values) | |||
if len(args) == 0 { | |||
return values, nil | |||
} | |||
err := argsToJSON(args) | |||
if err != nil { | |||
return nil, err | |||
} | |||
for key, val := range args { | |||
values.Set(key, val.(string)) | |||
} | |||
return values, nil | |||
} | |||
func argsToJSON(args map[string]interface{}) error { | |||
for k, v := range args { | |||
rt := reflect.TypeOf(v) | |||
isByteSlice := rt.Kind() == reflect.Slice && rt.Elem().Kind() == reflect.Uint8 | |||
if isByteSlice { | |||
bytes := reflect.ValueOf(v).Bytes() | |||
args[k] = fmt.Sprintf("0x%X", bytes) | |||
continue | |||
} | |||
data, err := tmjson.Marshal(v) | |||
if err != nil { | |||
return err | |||
} | |||
args[k] = string(data) | |||
} | |||
return nil | |||
} |
@ -1,85 +0,0 @@ | |||
package client | |||
import ( | |||
"context" | |||
"fmt" | |||
"io" | |||
"net/http" | |||
"strings" | |||
rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" | |||
) | |||
const ( | |||
// URIClientRequestID in a request ID used by URIClient | |||
URIClientRequestID = rpctypes.JSONRPCIntID(-1) | |||
) | |||
// URIClient is a JSON-RPC client, which sends POST form HTTP requests to the | |||
// remote server. | |||
// | |||
// URIClient is safe for concurrent use by multiple goroutines. | |||
type URIClient struct { | |||
address string | |||
client *http.Client | |||
} | |||
var _ HTTPClient = (*URIClient)(nil) | |||
// NewURI returns a new client. | |||
// An error is returned on invalid remote. | |||
// The function panics when remote is nil. | |||
func NewURI(remote string) (*URIClient, error) { | |||
parsedURL, err := newParsedURL(remote) | |||
if err != nil { | |||
return nil, err | |||
} | |||
httpClient, err := DefaultHTTPClient(remote) | |||
if err != nil { | |||
return nil, err | |||
} | |||
parsedURL.SetDefaultSchemeHTTP() | |||
uriClient := &URIClient{ | |||
address: parsedURL.GetTrimmedURL(), | |||
client: httpClient, | |||
} | |||
return uriClient, nil | |||
} | |||
// Call issues a POST form HTTP request. | |||
func (c *URIClient) Call(ctx context.Context, method string, | |||
params map[string]interface{}, result interface{}) (interface{}, error) { | |||
values, err := argsToURLValues(params) | |||
if err != nil { | |||
return nil, fmt.Errorf("failed to encode params: %w", err) | |||
} | |||
req, err := http.NewRequestWithContext( | |||
ctx, | |||
http.MethodPost, | |||
c.address+"/"+method, | |||
strings.NewReader(values.Encode()), | |||
) | |||
if err != nil { | |||
return nil, fmt.Errorf("new request: %w", err) | |||
} | |||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | |||
resp, err := c.client.Do(req) | |||
if err != nil { | |||
return nil, fmt.Errorf("post: %w", err) | |||
} | |||
defer resp.Body.Close() | |||
responseBytes, err := io.ReadAll(resp.Body) | |||
if err != nil { | |||
return nil, fmt.Errorf("read response body: %w", err) | |||
} | |||
return unmarshalResponseBytes(responseBytes, URIClientRequestID, result) | |||
} |