Skip to content

Commit d5b45ee

Browse files
committed
refactor: decouple read-write API code
1 parent 7346505 commit d5b45ee

File tree

8 files changed

+94
-44
lines changed

8 files changed

+94
-44
lines changed

gateway/api.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package gateway
2+
3+
import (
4+
"context"
5+
"io"
6+
7+
cid "github.com/ipfs/go-cid"
8+
ipld "github.com/ipfs/go-ipld-format"
9+
"github.com/ipfs/go-libipfs/files"
10+
iface "github.com/ipfs/interface-go-ipfs-core"
11+
options "github.com/ipfs/interface-go-ipfs-core/options"
12+
"github.com/ipfs/interface-go-ipfs-core/path"
13+
)
14+
15+
type ReaderDagAPI interface {
16+
Get(context.Context, cid.Cid) (ipld.Node, error)
17+
}
18+
19+
type ReaderBlockAPI interface {
20+
Get(context.Context, path.Path) (io.Reader, error)
21+
Stat(context.Context, path.Path) (iface.BlockStat, error)
22+
}
23+
24+
type ReaderRoutingAPI interface {
25+
Get(context.Context, string) ([]byte, error)
26+
}
27+
28+
type ReaderUnixFsAPI interface {
29+
Get(context.Context, path.Path) (files.Node, error)
30+
Ls(context.Context, path.Path, ...options.UnixfsLsOption) (<-chan iface.DirEntry, error)
31+
}
32+
33+
// ReaderAPI defines the minimal set of API services required for a read-only
34+
// gateway handler. These are, for the most part, subsets of the core interface.
35+
type ReaderAPI interface {
36+
// UnixFs returns an implementation of Readable UnixFs API.
37+
UnixFs() ReaderUnixFsAPI
38+
39+
// Block returns an implementation of Readable Block API.
40+
Block() ReaderBlockAPI
41+
42+
// Dag returns an implementation of Readable Dag API.
43+
Dag() ReaderDagAPI
44+
45+
// Routing returns an implementation of Readable Routing API.
46+
// Used for returning signed IPNS records, see IPIP-0328
47+
Routing() ReaderRoutingAPI
48+
49+
// ResolvePath resolves the path using UnixFS resolver
50+
ResolvePath(context.Context, path.Path) (path.Resolved, error)
51+
}
52+
53+
type OfflineBlockAPI interface {
54+
Get(context.Context, path.Path) (io.Reader, error)
55+
Stat(context.Context, path.Path) (iface.BlockStat, error)
56+
}
57+
58+
// OfflineAPI defines the API services required to work in offline mode. This
59+
// are used for caching handling when 'Cache-Control: only-if-cached'.
60+
type OfflineAPI interface {
61+
Block() OfflineBlockAPI
62+
}
63+
64+
type WriterUnixFsAPI interface {
65+
Add(context.Context, files.Node, ...options.UnixfsAddOption) (path.Resolved, error)
66+
}
67+
68+
// WriterAPI defines the API services required to work with a writable gateway.
69+
// These are full services from the core interface API. This is EXPERIMENTAL
70+
// and CAN change in the future.
71+
type WriterAPI interface {
72+
UnixFs() WriterUnixFsAPI
73+
Dag() iface.APIDagService
74+
}

gateway/gateway.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,15 @@
11
package gateway
22

33
import (
4-
"context"
54
"net/http"
65
"sort"
7-
8-
coreiface "github.com/ipfs/interface-go-ipfs-core"
9-
path "github.com/ipfs/interface-go-ipfs-core/path"
106
)
117

128
// Config is the configuration that will be applied when creating a new gateway
139
// handler.
1410
type Config struct {
15-
Headers map[string][]string
16-
Writable bool
17-
}
18-
19-
// NodeAPI defines the minimal set of API services required by a gateway handler
20-
type NodeAPI interface {
21-
// Unixfs returns an implementation of Unixfs API
22-
Unixfs() coreiface.UnixfsAPI
23-
24-
// Block returns an implementation of Block API
25-
Block() coreiface.BlockAPI
26-
27-
// Dag returns an implementation of Dag API
28-
Dag() coreiface.APIDagService
29-
30-
// Routing returns an implementation of Routing API.
31-
// Used for returning signed IPNS records, see IPIP-0328
32-
Routing() coreiface.RoutingAPI
33-
34-
// ResolvePath resolves the path using Unixfs resolver
35-
ResolvePath(context.Context, path.Path) (path.Resolved, error)
11+
Headers map[string][]string
12+
WriterAPI WriterAPI
3613
}
3714

3815
// A helper function to clean up a set of headers:

gateway/handler.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ type redirectTemplateData struct {
7272
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
7373
type handler struct {
7474
config Config
75-
api NodeAPI
76-
offlineAPI NodeAPI
75+
api ReaderAPI
76+
offlineAPI OfflineAPI
7777

7878
// generic metrics
7979
firstContentBlockGetMetric *prometheus.HistogramVec
@@ -219,11 +219,11 @@ func newHistogramMetric(name string, help string) *prometheus.HistogramVec {
219219

220220
// NewHandler returns an http.Handler that can act as a gateway to IPFS content
221221
// offlineApi is a version of the API that should not make network requests for missing data
222-
func NewHandler(c Config, api NodeAPI, offlineAPI NodeAPI) http.Handler {
222+
func NewHandler(c Config, api ReaderAPI, offlineAPI OfflineAPI) http.Handler {
223223
return newHandler(c, api, offlineAPI)
224224
}
225225

226-
func newHandler(c Config, api NodeAPI, offlineAPI NodeAPI) *handler {
226+
func newHandler(c Config, api ReaderAPI, offlineAPI OfflineAPI) *handler {
227227
i := &handler{
228228
config: c,
229229
api: api,
@@ -305,7 +305,7 @@ func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
305305
}
306306
}()
307307

308-
if i.config.Writable {
308+
if i.config.WriterAPI != nil {
309309
switch r.Method {
310310
case http.MethodPost:
311311
i.postHandler(w, r)
@@ -330,7 +330,7 @@ func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
330330

331331
errmsg := "Method " + r.Method + " not allowed: "
332332
var status int
333-
if !i.config.Writable {
333+
if i.config.WriterAPI == nil {
334334
status = http.StatusMethodNotAllowed
335335
errmsg = errmsg + "read only access"
336336
w.Header().Add("Allow", http.MethodGet)
@@ -460,7 +460,7 @@ func (i *handler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) {
460460
}
461461

462462
func (i *handler) postHandler(w http.ResponseWriter, r *http.Request) {
463-
p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body))
463+
p, err := i.config.WriterAPI.UnixFs().Add(r.Context(), files.NewReaderFile(r.Body))
464464
if err != nil {
465465
internalWebError(w, err)
466466
return
@@ -503,7 +503,7 @@ func (i *handler) putHandler(w http.ResponseWriter, r *http.Request) {
503503
}
504504

505505
// Create the new file.
506-
newFilePath, err := i.api.Unixfs().Add(ctx, files.NewReaderFile(r.Body))
506+
newFilePath, err := i.config.WriterAPI.UnixFs().Add(ctx, files.NewReaderFile(r.Body))
507507
if err != nil {
508508
webError(w, "WritableGateway: could not create DAG from request", err, http.StatusInternalServerError)
509509
return
@@ -517,7 +517,7 @@ func (i *handler) putHandler(w http.ResponseWriter, r *http.Request) {
517517

518518
// Patch the new file into the old root.
519519

520-
root, err := mfs.NewRoot(ctx, ds, pbnd, nil)
520+
root, err := mfs.NewRoot(ctx, i.config.WriterAPI.Dag(), pbnd, nil)
521521
if err != nil {
522522
webError(w, "WritableGateway: failed to create MFS root", err, http.StatusBadRequest)
523523
return
@@ -598,7 +598,7 @@ func (i *handler) deleteHandler(w http.ResponseWriter, r *http.Request) {
598598

599599
// construct the mfs root
600600

601-
root, err := mfs.NewRoot(ctx, i.api.Dag(), rootNode, nil)
601+
root, err := mfs.NewRoot(ctx, i.config.WriterAPI.Dag(), rootNode, nil)
602602
if err != nil {
603603
webError(w, "WritableGateway: failed to construct the MFS root", err, http.StatusBadRequest)
604604
return

gateway/handler_car.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
cid "github.com/ipfs/go-cid"
1010
blocks "github.com/ipfs/go-libipfs/blocks"
11-
coreiface "github.com/ipfs/interface-go-ipfs-core"
1211
ipath "github.com/ipfs/interface-go-ipfs-core/path"
1312
gocar "github.com/ipld/go-car"
1413
selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse"
@@ -89,7 +88,7 @@ func (i *handler) serveCAR(ctx context.Context, w http.ResponseWriter, r *http.R
8988

9089
// FIXME(@Jorropo): https://github.com/ipld/go-car/issues/315
9190
type dagStore struct {
92-
dag coreiface.APIDagService
91+
dag ReaderDagAPI
9392
ctx context.Context
9493
}
9594

gateway/handler_tar.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func (i *handler) serveTAR(ctx context.Context, w http.ResponseWriter, r *http.R
2323
defer cancel()
2424

2525
// Get Unixfs file
26-
file, err := i.api.Unixfs().Get(ctx, resolvedPath)
26+
file, err := i.api.UnixFs().Get(ctx, resolvedPath)
2727
if err != nil {
2828
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
2929
return

gateway/handler_unixfs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func (i *handler) serveUnixFS(ctx context.Context, w http.ResponseWriter, r *htt
1919
defer span.End()
2020

2121
// Handling UnixFS
22-
dr, err := i.api.Unixfs().Get(ctx, resolvedPath)
22+
dr, err := i.api.UnixFs().Get(ctx, resolvedPath)
2323
if err != nil {
2424
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
2525
return

gateway/handler_unixfs__redirects.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func (i *handler) handleRedirectsFileRules(w http.ResponseWriter, r *http.Reques
120120

121121
func (i *handler) getRedirectRules(r *http.Request, redirectsFilePath ipath.Resolved) ([]redirects.Rule, error) {
122122
// Convert the path into a file node
123-
node, err := i.api.Unixfs().Get(r.Context(), redirectsFilePath)
123+
node, err := i.api.UnixFs().Get(r.Context(), redirectsFilePath)
124124
if err != nil {
125125
return nil, fmt.Errorf("could not get _redirects: %w", err)
126126
}
@@ -170,7 +170,7 @@ func (i *handler) serve4xx(w http.ResponseWriter, r *http.Request, content4xxPat
170170
return err
171171
}
172172

173-
node, err := i.api.Unixfs().Get(r.Context(), resolved4xxPath)
173+
node, err := i.api.UnixFs().Get(r.Context(), resolved4xxPath)
174174
if err != nil {
175175
return err
176176
}
@@ -220,7 +220,7 @@ func (i *handler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request
220220
return false
221221
}
222222

223-
dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path)
223+
dr, err := i.api.UnixFs().Get(r.Context(), resolved404Path)
224224
if err != nil {
225225
return false
226226
}

gateway/handler_unixfs_dir.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (i *handler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *
6161

6262
// Check if directory has index.html, if so, serveFile
6363
idxPath := ipath.Join(contentPath, "index.html")
64-
idx, err := i.api.Unixfs().Get(ctx, idxPath)
64+
idx, err := i.api.UnixFs().Get(ctx, idxPath)
6565
switch err.(type) {
6666
case nil:
6767
f, ok := idx.(files.File)
@@ -107,7 +107,7 @@ func (i *handler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *
107107
// Optimization: use Unixfs.Ls without resolving children, but using the
108108
// cumulative DAG size as the file size. This allows for a fast listing
109109
// while keeping a good enough Size field.
110-
results, err := i.api.Unixfs().Ls(ctx,
110+
results, err := i.api.UnixFs().Ls(ctx,
111111
resolvedPath,
112112
options.Unixfs.ResolveChildren(false),
113113
options.Unixfs.UseCumulativeSize(true),

0 commit comments

Comments
 (0)