From 8f6f9326de5bbeba2b1bdcf93f360d9f179fb831 Mon Sep 17 00:00:00 2001 From: fangdingjun Date: Sat, 20 Oct 2018 17:29:50 +0800 Subject: [PATCH] v0.0.1 --- README.md | 35 ++++++++++++++ jsonrpc.go | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ jsonrpc_test.go | 44 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 README.md create mode 100644 jsonrpc.go create mode 100644 jsonrpc_test.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1286b4 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +jsonrpc +======= + +simple jsonrpc 2.0 client + + +usage +==== +example + + package main + + import ( + "github.com/fangdingjun/jsonrpc" + "log" + ) + + type result struct{ + R1 string `json:"r1"` + R2 string `json:"r2"` + } + + func main(){ + client, _ := jsonrpc.NewClient("http://admin:123@127.0.0.1:2312/jsonrpc") + // client.Debug = true + // client.HTTPClient = &http.Client{...} + + var ret result + var args = []interface{}{1, "a", 2} + err := client.Call("some_method", args, &ret) + if err != nil{ + log.Fatal(err) + } + log.Println(ret) + } diff --git a/jsonrpc.go b/jsonrpc.go new file mode 100644 index 0000000..bac9ba0 --- /dev/null +++ b/jsonrpc.go @@ -0,0 +1,120 @@ +package jsonrpc + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" +) + +// Client json rpc client +type Client struct { + // URL is remote url, ex http://username:password@192.168.1.3:1001/jsonrpc + URL string + // http client, default is http.DefaultClient + HTTPClient *http.Client + id uint64 + // Debug set to true, log the send/recevied http data + Debug bool +} + +type request struct { + Version string `json:"jsonrpc"` + Method string `json:"method"` + Params interface{} `json:"params"` + ID uint64 `json:"id"` +} + +type response struct { + Version string `json:"jsonrpc"` + Result json.RawMessage `json:"result"` + Error *errorObj `json:"error"` + ID uint64 `json:"id"` +} + +type errorObj struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} + +// NewClient create a new jsonrpc client +func NewClient(url string) (*Client, error) { + return &Client{URL: url, HTTPClient: http.DefaultClient}, nil +} + +func (c *Client) nextID() uint64 { + c.id++ + return c.id +} + +// Call invoke a method with args and return reply +func (c *Client) Call(method string, args interface{}, reply interface{}) error { + client := c.HTTPClient + if client == nil { + client = http.DefaultClient + } + + if args == nil { + args = []string{} + } + + r := &request{ + Version: "2.0", + Method: method, + Params: args, + ID: c.nextID(), + } + + data, err := json.Marshal(r) + if err != nil { + return err + } + + if c.Debug { + log.Println("send", string(data)) + } + + body := bytes.NewBuffer(data) + + req, err := http.NewRequest("POST", c.URL, body) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("http error: %s", resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if c.Debug { + log.Println("recevied", string(data)) + } + + var res response + + if err = json.Unmarshal(data, &res); err != nil { + return err + } + + if res.Error != nil { + return fmt.Errorf("%d: %s", res.Error.Code, res.Error.Message) + } + + return json.Unmarshal(res.Result, &reply) +} diff --git a/jsonrpc_test.go b/jsonrpc_test.go new file mode 100644 index 0000000..a976f8a --- /dev/null +++ b/jsonrpc_test.go @@ -0,0 +1,44 @@ +package jsonrpc + +import ( + "log" + "testing" +) + +func TestCall(t *testing.T) { + url := "http://192.168.56.101:8542/" + c, _ := NewClient(url) + c.Debug = true + var ret interface{} + err := c.Call("eth_getBalance", []string{"0x00CB25f6fD16a52e24eDd2c8fd62071dc29A035c", "latest"}, &ret) + if err != nil { + t.Error(err) + return + } + log.Printf("result: %+v", ret) + + url = "http://admin2:123@192.168.56.101:19011/" + + c, _ = NewClient(url) + c.Debug = true + + err = c.Call("getbalance", []string{}, &ret) + if err != nil { + t.Error(err) + return + } + + log.Printf("result: %+v", ret) + + if err = c.Call("fuck", []string{}, &ret); err == nil { + t.Errorf("expected error, got nil") + return + } + log.Println("got", err) + + if err = c.Call("listreceivedbyaddress", []interface{}{0, false}, &ret); err != nil { + t.Error(err) + return + } + log.Printf("result: %+v", ret) +}