forked from OpenBazaar/openbazaar-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
api_router.go
129 lines (109 loc) · 3.8 KB
/
api_router.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package ipfs
import (
"bytes"
"context"
"encoding/base64"
"errors"
"golang.org/x/net/proxy"
"io/ioutil"
"net/http"
"time"
"gx/ipfs/QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN/go-cid"
peer "gx/ipfs/QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h/go-libp2p-peer"
routing "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing"
ropts "gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing/options"
pstore "gx/ipfs/QmaCTz9RkrU13bm9kMB54f7atgqM4qkjDZpRwRoJiWXEqs/go-libp2p-peerstore"
record "gx/ipfs/QmbeHtaBy9nZsW4cHRcvgVY4CnDhXudE2Dr6qDxS7yg9rX/go-libp2p-record"
)
var apiRouterHTTPClient = &http.Client{
Timeout: time.Second * 30,
}
// ensure APIRouter satisfies the interface
var _ routing.IpfsRouting = &APIRouter{}
// ErrNotStarted is returned if a method is called before the router
// is started using the Start() method.
var ErrNotStarted = errors.New("API router not started")
// APIRouter is a routing.IpfsRouting compliant struct backed by an API. It only
// provides the features offerened by routing.ValueStore and marks the others as
// unsupported.
type APIRouter struct {
uri string
started chan (struct{})
validator record.Validator
}
// NewAPIRouter creates a new APIRouter backed by the given URI.
func NewAPIRouter(uri string, validator record.Validator) APIRouter {
return APIRouter{uri: uri, started: make(chan (struct{})), validator: validator}
}
func (r *APIRouter) Start(proxyDialer proxy.Dialer) {
if proxyDialer != nil {
tbTransport := &http.Transport{Dial: proxyDialer.Dial}
apiRouterHTTPClient.Transport = tbTransport
}
close(r.started)
}
// Bootstrap is a no-op. We don't need any setup to query the API.
func (r APIRouter) Bootstrap(_ context.Context) error {
return nil
}
// PutValue writes the given value to the API for the given key
func (r APIRouter) PutValue(ctx context.Context, key string, value []byte, opts ...ropts.Option) error {
<-r.started
path := r.pathForKey(key)
req, err := http.NewRequest("PUT", path, bytes.NewBuffer(value))
if err != nil {
return err
}
log.Debugf("write value to %s", path)
_, err = apiRouterHTTPClient.Do(req)
return err
}
// GetValue reads the value for the given key
func (r APIRouter) GetValue(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
<-r.started
path := r.pathForKey(key)
resp, err := apiRouterHTTPClient.Get(path)
if err != nil {
return nil, err
}
defer resp.Body.Close()
log.Debugf("read value from %s", path)
value, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return value, r.validator.Validate(key, value)
}
// GetValues reads the value for the given key. The API does not return multiple
// values.
func (r APIRouter) GetValues(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
<-r.started
return r.GetValue(ctx, key, opts...)
}
// SearchValue returns the value for the given key. It return either an error or
// a closed channel containing one value.
func (r APIRouter) SearchValue(ctx context.Context, key string, opts ...ropts.Option) (<-chan []byte, error) {
value, err := r.GetValue(ctx, key, opts...)
if err != nil {
return nil, err
}
valueCh := make(chan []byte, 1)
valueCh <- value
close(valueCh)
return valueCh, nil
}
// FindPeer is unsupported
func (r APIRouter) FindPeer(_ context.Context, id peer.ID) (pstore.PeerInfo, error) {
return pstore.PeerInfo{}, routing.ErrNotSupported
}
// FindProvidersAsync is unsupported
func (r APIRouter) FindProvidersAsync(_ context.Context, _ cid.Cid, _ int) <-chan pstore.PeerInfo {
return nil
}
// Provide is unsupported
func (r APIRouter) Provide(_ context.Context, _ cid.Cid, _ bool) error {
return routing.ErrNotSupported
}
func (r APIRouter) pathForKey(key string) string {
return r.uri + "/value/" + base64.URLEncoding.EncodeToString([]byte(key))
}