Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit 046ddfb

Browse files
committed
use a request builder
This allows specifying custom options.
1 parent 2960bf9 commit 046ddfb

File tree

5 files changed

+153
-22
lines changed

5 files changed

+153
-22
lines changed

request.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ func (r *Response) Close() error {
5555
return nil
5656
}
5757

58+
func (r *Response) Decode(dec interface{}) error {
59+
defer r.Close()
60+
if r.Error != nil {
61+
return r.Error
62+
}
63+
64+
return json.NewDecoder(r.Output).Decode(dec)
65+
}
66+
5867
type Error struct {
5968
Command string
6069
Message string

requestbuilder.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package shell
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"io"
8+
"strconv"
9+
"strings"
10+
)
11+
12+
// RequestBuilder is an IPFS commands request builder.
13+
type RequestBuilder struct {
14+
command string
15+
args []string
16+
opts map[string]string
17+
headers map[string]string
18+
body io.Reader
19+
20+
shell *Shell
21+
}
22+
23+
// Arguments adds the arguments to the args.
24+
func (r *RequestBuilder) Arguments(args ...string) *RequestBuilder {
25+
r.args = append(r.args, args...)
26+
return r
27+
}
28+
29+
// BodyString sets the request body to the given string.
30+
func (r *RequestBuilder) BodyString(body string) *RequestBuilder {
31+
return r.Body(strings.NewReader(body))
32+
}
33+
34+
// BodyBytes sets the request body to the given buffer.
35+
func (r *RequestBuilder) BodyBytes(body []byte) *RequestBuilder {
36+
return r.Body(bytes.NewReader(body))
37+
}
38+
39+
// Body sets the request body to the given reader.
40+
func (r *RequestBuilder) Body(body io.Reader) *RequestBuilder {
41+
r.body = body
42+
return r
43+
}
44+
45+
// Option sets the given option.
46+
func (r *RequestBuilder) Option(key string, value interface{}) *RequestBuilder {
47+
var s string
48+
switch v := value.(type) {
49+
case bool:
50+
s = strconv.FormatBool(v)
51+
case string:
52+
s = v
53+
case []byte:
54+
s = string(v)
55+
default:
56+
// slow case.
57+
s = fmt.Sprint(value)
58+
}
59+
if r.opts == nil {
60+
r.opts = make(map[string]string, 1)
61+
}
62+
r.opts[key] = s
63+
return r
64+
}
65+
66+
// Header sets the given header.
67+
func (r *RequestBuilder) Header(name, value string) *RequestBuilder {
68+
if r.headers == nil {
69+
r.headers = make(map[string]string, 1)
70+
}
71+
r.headers[name] = value
72+
return r
73+
}
74+
75+
// Send sends the request and return the response.
76+
func (r *RequestBuilder) Send(ctx context.Context) (*Response, error) {
77+
req := r.shell.newRequest(ctx, r.command, r.args...)
78+
req.Opts = r.opts
79+
req.Headers = r.headers
80+
req.Body = r.body
81+
return req.Send(r.shell.httpcli)
82+
}
83+
84+
// Exec sends the request a request and decodes the response.
85+
func (r *RequestBuilder) Exec(ctx context.Context, res interface{}) error {
86+
httpRes, err := r.Send(ctx)
87+
if err != nil {
88+
return err
89+
}
90+
91+
if res == nil {
92+
httpRes.Close()
93+
return httpRes.Error
94+
}
95+
96+
return httpRes.Decode(res)
97+
}

requestbuilder_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package shell
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/cheekybits/is"
8+
)
9+
10+
func TestRequestBuilder(t *testing.T) {
11+
is := is.New(t)
12+
13+
now := time.Now()
14+
r := RequestBuilder{}
15+
r.Arguments("1", "2", "3")
16+
r.Arguments("4")
17+
r.Option("stringkey", "stringvalue")
18+
r.Option("bytekey", []byte("bytevalue"))
19+
r.Option("boolkey", true)
20+
r.Option("otherkey", now)
21+
r.Header("some-header", "header-value")
22+
r.Header("some-header-2", "header-value-2")
23+
24+
is.Equal(r.args, []string{"1", "2", "3", "4"})
25+
is.Equal(r.opts, map[string]string{
26+
"stringkey": "stringvalue",
27+
"bytekey": "bytevalue",
28+
"boolkey": "true",
29+
"otherkey": now.String(),
30+
})
31+
is.Equal(r.headers, map[string]string{
32+
"some-header": "header-value",
33+
"some-header-2": "header-value-2",
34+
})
35+
}

shell.go

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,12 @@ func (s *Shell) newRequest(ctx context.Context, command string, args ...string)
9494
return NewRequest(ctx, s.url, command, args...)
9595
}
9696

97-
func (s *Shell) Request(ctx context.Context, command string, args ...string) (*Request, *Response, error) {
98-
req := s.newRequest(ctx, command, args...)
99-
res, err := req.Send(s.httpcli)
100-
return req, res, err
101-
}
102-
103-
func (s *Shell) RequestDecode(ctx context.Context, dec interface{}, command string, args ...string) error {
104-
_, res, err := s.Request(ctx, command, args...)
105-
if err != nil {
106-
return err
107-
}
108-
defer res.Close()
109-
if res.Error != nil {
110-
return res.Error
97+
func (s *Shell) Request(command string, args ...string) *RequestBuilder {
98+
return &RequestBuilder{
99+
command: command,
100+
args: args,
101+
shell: s,
111102
}
112-
113-
return json.NewDecoder(res.Output).Decode(dec)
114103
}
115104

116105
type IdOutput struct {
@@ -855,9 +844,9 @@ func (s *Shell) ObjectStat(key string) (*ObjectStats, error) {
855844

856845
// ObjectStat gets stats for the DAG object named by key. It returns
857846
// the stats of the requested Object or an error.
858-
func (s *Shell) StatsBW() (*p2pmetrics.Stats, error) {
847+
func (s *Shell) StatsBW(ctx context.Context) (*p2pmetrics.Stats, error) {
859848
v := &p2pmetrics.Stats{}
860-
err := s.RequestDecode(context.TODO(), &v, "stats/bw")
849+
err := s.Request("stats/bw").Exec(ctx, &v)
861850
return v, err
862851
}
863852

@@ -878,8 +867,8 @@ type SwarmConnInfos struct {
878867
}
879868

880869
// SwarmPeers gets all the swarm peers
881-
func (s *Shell) SwarmPeers() (*SwarmConnInfos, error) {
870+
func (s *Shell) SwarmPeers(ctx context.Context) (*SwarmConnInfos, error) {
882871
v := &SwarmConnInfos{}
883-
err := s.RequestDecode(context.TODO(), &v, "swarm/peers")
872+
err := s.Request("swarm/peers").Exec(ctx, &v)
884873
return v, err
885874
}

shell_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package shell
22

33
import (
44
"bytes"
5+
"context"
56
"crypto/md5"
67
"fmt"
78
"io"
@@ -246,13 +247,13 @@ func TestDagPut(t *testing.T) {
246247
func TestStatsBW(t *testing.T) {
247248
is := is.New(t)
248249
s := NewShell(shellUrl)
249-
_, err := s.StatsBW()
250+
_, err := s.StatsBW(context.Background())
250251
is.Nil(err)
251252
}
252253

253254
func TestSwarmPeers(t *testing.T) {
254255
is := is.New(t)
255256
s := NewShell(shellUrl)
256-
_, err := s.SwarmPeers()
257+
_, err := s.SwarmPeers(context.Background())
257258
is.Nil(err)
258259
}

0 commit comments

Comments
 (0)