Skip to content

Commit 6637bd7

Browse files
authored
Merge pull request #5 from qurami/feat-proxy-support
HTTP Proxy support
2 parents b2c5426 + 66323b8 commit 6637bd7

File tree

5 files changed

+127
-47
lines changed

5 files changed

+127
-47
lines changed

README.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# gojsonrpc
2+
3+
This package provides a client to JSON RPC services.
4+
5+
## Usage example
6+
7+
```go
8+
package main
9+
10+
import (
11+
"log"
12+
"github.com/qurami/gojsonrpc"
13+
)
14+
15+
func main() {
16+
client := gojsonrpc.NewClient("http://mock.rpcservice.url")
17+
18+
// you can optionally set a HTTP proxy for the connection
19+
proxyURL, _ := "http://proxy.url:3128"
20+
client.SetHTTPProxy(proxyURL)
21+
22+
// you can also optionally set the connection timeout
23+
client.SetTimeout(120)
24+
25+
args := map[string]interface{}{}
26+
names := make([]string, 0)
27+
28+
err := client.Run("GetNames", args, &names)
29+
if err != nil {
30+
log.Fatal(err)
31+
}
32+
log.Println(names)
33+
}
34+
```

client.go

+50-38
Original file line numberDiff line numberDiff line change
@@ -6,70 +6,56 @@ import (
66
"errors"
77
"io/ioutil"
88
"net/http"
9+
"net/url"
910
"strings"
1011
"time"
1112
)
1213

14+
// Client executes JSON RPC calls to remote servers.
1315
type Client struct {
14-
Url string
15-
Timeout int
16+
serverURL string
17+
httpClient *http.Client
1618
}
1719

20+
// NewClient returns a newly istantiated Client pointing to the given url.
1821
func NewClient(url string) *Client {
19-
client := new(Client)
20-
21-
client.Url = url
22-
client.Timeout = DEFAULT_TIMEOUT
23-
24-
return client
25-
}
26-
27-
func (this *Client) sendJsonRequest(jsonRequest []byte) ([]byte, error) {
28-
var jsonResponse []byte
29-
3022
httpClient := &http.Client{
31-
Timeout: time.Duration(time.Duration(this.Timeout) * time.Second),
23+
Timeout: time.Duration(time.Duration(defaultTimeout) * time.Second),
3224
Transport: &http.Transport{
3325
TLSClientConfig: &tls.Config{
3426
InsecureSkipVerify: true,
3527
},
28+
Proxy: http.ProxyFromEnvironment,
3629
},
3730
}
3831

39-
httpRequest, err := http.NewRequest("POST", this.Url, strings.NewReader(string(jsonRequest)))
40-
httpRequest.Header.Set("Content-Type", "application/json")
41-
httpRequest.Header.Set("Content-Length", "")
42-
httpRequest.Header.Set("Accept", "application/json")
43-
httpRequest.Header.Set("Connection", "close")
44-
45-
httpResponse, err := httpClient.Do(httpRequest)
46-
if err != nil {
47-
return jsonResponse, err
48-
}
49-
50-
defer httpResponse.Body.Close()
51-
52-
jsonResponse, err = ioutil.ReadAll(httpResponse.Body)
53-
if err != nil {
54-
return jsonResponse, err
32+
return &Client{
33+
serverURL: url,
34+
httpClient: httpClient,
5535
}
36+
}
5637

57-
return jsonResponse, nil
38+
// SetTimeout sets the client timeout to the given value.
39+
func (c *Client) SetTimeout(timeout int) {
40+
c.httpClient.Timeout = time.Duration(timeout) * time.Second
5841
}
5942

60-
func (this *Client) SetTimeout(timeout int) {
61-
this.Timeout = timeout
43+
// SetHTTPProxyURL tells the client to use the given proxyURL as proxy address.
44+
func (c *Client) SetHTTPProxyURL(proxyURL *url.URL) {
45+
c.httpClient.Transport.(*http.Transport).Proxy = http.ProxyURL(proxyURL)
6246
}
6347

64-
func (this *Client) Run(method string, params interface{}, result interface{}) error {
48+
// Run executes the given method having the given params setting the response
49+
// value in the given result interface.
50+
func (c *Client) Run(method string, params interface{}, result interface{}) error {
6551
request := NewRequest(method, params, RandInt(10000000, 99999999))
6652

6753
jsonRequest, err := json.Marshal(request)
6854
if err != nil {
6955
return err
7056
}
7157

72-
jsonResponse, err := this.sendJsonRequest(jsonRequest)
58+
jsonResponse, err := c.sendJSONRequest(jsonRequest)
7359
if err != nil {
7460
return err
7561
}
@@ -89,18 +75,44 @@ func (this *Client) Run(method string, params interface{}, result interface{}) e
8975
return nil
9076
}
9177

92-
func (this *Client) Notify(method string, params interface{}) error {
78+
// Notify executes the given method with the given parameters.
79+
// Doesn't expect any result.
80+
func (c *Client) Notify(method string, params interface{}) error {
9381
request := NewRequest(method, params, 0)
9482

95-
requestJson, err := json.Marshal(request)
83+
jsonRequest, err := json.Marshal(request)
9684
if err != nil {
9785
return err
9886
}
9987

100-
_, err = this.sendJsonRequest(requestJson)
88+
_, err = c.sendJSONRequest(jsonRequest)
10189
if err != nil {
10290
return err
10391
}
10492

10593
return nil
10694
}
95+
96+
func (c *Client) sendJSONRequest(jsonRequest []byte) ([]byte, error) {
97+
var jsonResponse []byte
98+
99+
httpRequest, err := http.NewRequest("POST", c.serverURL, strings.NewReader(string(jsonRequest)))
100+
httpRequest.Header.Set("Content-Type", "application/json")
101+
httpRequest.Header.Set("Content-Length", "")
102+
httpRequest.Header.Set("Accept", "application/json")
103+
httpRequest.Header.Set("Connection", "close")
104+
105+
httpResponse, err := c.httpClient.Do(httpRequest)
106+
if err != nil {
107+
return jsonResponse, err
108+
}
109+
110+
defer httpResponse.Body.Close()
111+
112+
jsonResponse, err = ioutil.ReadAll(httpResponse.Body)
113+
if err != nil {
114+
return jsonResponse, err
115+
}
116+
117+
return jsonResponse, nil
118+
}

client_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package gojsonrpc
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"net/url"
7+
"testing"
8+
)
9+
10+
func TestThatSetHTTPProxyURLSetsAnHTTPProxyInClient(t *testing.T) {
11+
proxyCalled := false
12+
13+
mockProxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14+
proxyCalled = true
15+
}))
16+
17+
mockRPCServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18+
}))
19+
20+
sut := NewClient(mockRPCServer.URL)
21+
22+
mockHTTPProxyURL, _ := url.Parse(mockProxy.URL)
23+
24+
sut.SetHTTPProxyURL(mockHTTPProxyURL)
25+
_ = sut.Notify("SometMethod", nil)
26+
27+
if !proxyCalled {
28+
t.Fatal("expected proxy was not called")
29+
}
30+
}

constants.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package gojsonrpc
22

33
const (
4-
DEFAULT_TIMEOUT = 300
4+
defaultTimeout = 300
55
)

pool.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ import (
55
"strings"
66
)
77

8+
// Pool executes JSON RPC calls to remote servers using a pool of Clients.
89
type Pool struct {
910
clients chan (*Client)
1011
}
1112

13+
// NewPool returns a newly initialized Pool of clients pointing to the given url.
1214
func NewPool(url string, n int, additionalParameters ...interface{}) *Pool {
1315
pool := new(Pool)
1416
pool.clients = make(chan (*Client), n)
15-
timeout := DEFAULT_TIMEOUT
17+
timeout := defaultTimeout
1618

1719
if len(additionalParameters) == 1 {
1820
timeoutIntVal, ok := additionalParameters[0].(int)
@@ -30,17 +32,19 @@ func NewPool(url string, n int, additionalParameters ...interface{}) *Pool {
3032
return pool
3133
}
3234

33-
func (this *Pool) getClient() *Client {
34-
return <-this.clients
35+
func (p *Pool) getClient() *Client {
36+
return <-p.clients
3537
}
3638

37-
func (this *Pool) releaseClient(c *Client) {
38-
this.clients <- c
39+
func (p *Pool) releaseClient(c *Client) {
40+
p.clients <- c
3941
}
4042

41-
func (this *Pool) Do(command, methodName string, params interface{}, result interface{}) error {
42-
c := this.getClient()
43-
defer this.releaseClient(c)
43+
// Do executes the given command (Run or Notify) using the given methodName and params
44+
// and building the response in the given result interface.
45+
func (p *Pool) Do(command, methodName string, params interface{}, result interface{}) error {
46+
c := p.getClient()
47+
defer p.releaseClient(c)
4448

4549
switch strings.ToLower(command) {
4650
case "run":

0 commit comments

Comments
 (0)