Skip to content

Commit

Permalink
feat: migrate subdomain and dnslink code
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Feb 6, 2023
1 parent a4e0934 commit 276ccba
Show file tree
Hide file tree
Showing 11 changed files with 1,070 additions and 15 deletions.
2 changes: 1 addition & 1 deletion examples/gateway/car/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Then, you can start the gateway with:
./gateway -c data.car -p 8040
```

Now you can access the gateway in [127.0.0.1:8040](http://127.0.0.1:8040). It will
Now you can access the gateway in [localhost:8040](http://localhost:8040). It will
behave like a regular IPFS Gateway, except for the fact that all contents are provided
from the CAR file. Therefore, things such as IPNS resolution and fetching contents
from nodes in the IPFS network won't work.
25 changes: 19 additions & 6 deletions examples/gateway/car/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ipfs/go-cid"
offline "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-libipfs/examples/gateway/common"
"github.com/ipfs/go-libipfs/gateway"
carblockstore "github.com/ipld/go-car/v2/blockstore"
)

Expand All @@ -26,20 +27,32 @@ func main() {
}
defer f.Close()

gateway, err := common.NewBlocksGateway(blockService, nil)
gwAPI, err := common.NewBlocksGateway(blockService, nil)
if err != nil {
log.Fatal(err)
}
handler := common.NewBlocksHandler(gwAPI, *portPtr)

handler := common.NewBlocksHandler(gateway, *portPtr)
// Initialize the public gateways that we will want to have available through
// Host header rewritting. This step is optional and only required if you're
// running multiple public gateways and want different settings and support
// for DNSLink and Subdomain Gateways.
publicGateways := map[string]*gateway.Specification{
"localhost": {
Paths: []string{"/ipfs", "/ipns"},
NoDNSLink: true,
UseSubdomains: true,
},
}
noDNSLink := true
handler = gateway.WithHostname(handler, gwAPI, publicGateways, noDNSLink)

address := "127.0.0.1:" + strconv.Itoa(*portPtr)
log.Printf("Listening on http://%s", address)
log.Printf("Listening on http://localhost:%d", *portPtr)
for _, cid := range roots {
log.Printf("Hosting CAR root at http://%s/ipfs/%s", address, cid.String())
log.Printf("Hosting CAR root at http://localhost:%d/ipfs/%s", *portPtr, cid.String())
}

if err := http.ListenAndServe(address, handler); err != nil {
if err := http.ListenAndServe(":"+strconv.Itoa(*portPtr), handler); err != nil {
log.Fatal(err)
}
}
Expand Down
14 changes: 14 additions & 0 deletions examples/gateway/common/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"context"
"errors"
"fmt"
"net/http"
gopath "path"
Expand All @@ -24,6 +25,7 @@ import (
uio "github.com/ipfs/go-unixfs/io"
"github.com/ipfs/go-unixfsnode"
iface "github.com/ipfs/interface-go-ipfs-core"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
ifacepath "github.com/ipfs/interface-go-ipfs-core/path"
dagpb "github.com/ipld/go-codec-dagpb"
"github.com/ipld/go-ipld-prime"
Expand Down Expand Up @@ -143,6 +145,18 @@ func (api *BlocksGateway) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte,
return nil, routing.ErrNotSupported
}

func (api *BlocksGateway) GetDNSLinkRecord(ctx context.Context, hostname string) (ifacepath.Path, error) {
if api.namesys != nil {
p, err := api.namesys.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
if err == namesys.ErrResolveRecursion {
err = nil
}
return ifacepath.New(p.String()), err
}

return nil, errors.New("not implemented")
}

func (api *BlocksGateway) IsCached(ctx context.Context, p ifacepath.Path) bool {
rp, err := api.ResolvePath(ctx, p)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion examples/gateway/proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ types. Once you have it, run the proxy gateway with its address as the host para
./verifying-proxy -h https://ipfs.io -p 8040
```

Now you can access the gateway in [127.0.0.1:8040](http://127.0.0.1:8040). It will
Now you can access the gateway in [localhost:8040](http://localhost:8040). It will
behave like a regular IPFS Gateway, except for the fact that it runs no libp2p, and has no local blockstore.
All contents are provided by a remote gateway and fetched as RAW Blocks and Records, and verified locally.
25 changes: 19 additions & 6 deletions examples/gateway/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/ipfs/go-blockservice"
offline "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-libipfs/examples/gateway/common"
"github.com/ipfs/go-libipfs/gateway"
)

func main() {
Expand All @@ -24,16 +25,28 @@ func main() {
routing := newProxyRouting(*gatewayUrlPtr, nil)

// Creates the gateway with the block service and the routing.
gateway, err := common.NewBlocksGateway(blockService, routing)
gwAPI, err := common.NewBlocksGateway(blockService, routing)
if err != nil {
log.Fatal(err)
}
handler := common.NewBlocksHandler(gwAPI, *portPtr)

// Initialize the public gateways that we will want to have available through
// Host header rewritting. This step is optional and only required if you're
// running multiple public gateways and want different settings and support
// for DNSLink and Subdomain Gateways.
publicGateways := map[string]*gateway.Specification{
"localhost": {
Paths: []string{"/ipfs", "/ipns"},
NoDNSLink: true,
UseSubdomains: true,
},
}
noDNSLink := true
handler = gateway.WithHostname(handler, gwAPI, publicGateways, noDNSLink)

handler := common.NewBlocksHandler(gateway, *portPtr)
address := "127.0.0.1:" + strconv.Itoa(*portPtr)
log.Printf("Listening on http://%s", address)

if err := http.ListenAndServe(address, handler); err != nil {
log.Printf("Listening on http://localhost:%d", *portPtr)
if err := http.ListenAndServe(":"+strconv.Itoa(*portPtr), handler); err != nil {
log.Fatal(err)
}
}
6 changes: 6 additions & 0 deletions gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ type API interface {
// from the routing system.
GetIPNSRecord(context.Context, cid.Cid) ([]byte, error)

// GetDNSLinkRecord returns the DNSLink TXT record for the provided FQDN.
// Unlike ResolvePath, it does not perform recursive resolution. It only
// checks for the existence of a DNSLink TXT record with path starting with
// /ipfs/ or /ipns/ and returns the path as-is.
GetDNSLinkRecord(context.Context, string) (path.Path, error)

// IsCached returns whether or not the path exists locally.
IsCached(context.Context, path.Path) bool

Expand Down
103 changes: 103 additions & 0 deletions gateway/gateway_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package gateway

import (
"context"
"errors"
"strings"

cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-libipfs/blocks"
"github.com/ipfs/go-libipfs/files"
"github.com/ipfs/go-namesys"
path "github.com/ipfs/go-path"
iface "github.com/ipfs/interface-go-ipfs-core"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
ipath "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/libp2p/go-libp2p/core/crypto"
)

type mockNamesys map[string]path.Path

func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) {
cfg := nsopts.DefaultResolveOpts()
for _, o := range opts {
o(&cfg)
}
depth := cfg.Depth
if depth == nsopts.UnlimitedDepth {
// max uint
depth = ^uint(0)
}
for strings.HasPrefix(name, "/ipns/") {
if depth == 0 {
return value, namesys.ErrResolveRecursion
}
depth--

var ok bool
value, ok = m[name]
if !ok {
return "", namesys.ErrResolveFailed
}
name = value.String()
}
return value, nil
}

func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsopts.ResolveOpt) <-chan namesys.Result {
out := make(chan namesys.Result, 1)
v, err := m.Resolve(ctx, name, opts...)
out <- namesys.Result{Path: v, Err: err}
close(out)
return out
}

func (m mockNamesys) Publish(ctx context.Context, name crypto.PrivKey, value path.Path, opts ...nsopts.PublishOption) error {
return errors.New("not implemented for mockNamesys")
}

func (m mockNamesys) GetResolver(subs string) (namesys.Resolver, bool) {
return nil, false
}

type mockApi struct {
ns mockNamesys
}

func newMockApi() *mockApi {
return &mockApi{
ns: mockNamesys{},
}
}

func (m *mockApi) GetUnixFsNode(context.Context, ipath.Resolved) (files.Node, error) {
return nil, errors.New("not implemented")
}

func (m *mockApi) LsUnixFsDir(context.Context, ipath.Resolved) (<-chan iface.DirEntry, error) {
return nil, errors.New("not implemented")
}

func (m *mockApi) GetBlock(context.Context, cid.Cid) (blocks.Block, error) {
return nil, errors.New("not implemented")
}

func (m *mockApi) GetIPNSRecord(context.Context, cid.Cid) ([]byte, error) {
return nil, errors.New("not implemented")
}

func (m *mockApi) GetDNSLinkRecord(ctx context.Context, hostname string) (ipath.Path, error) {
p, err := m.ns.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
if err == namesys.ErrResolveRecursion {
err = nil
}
return ipath.New(p.String()), err
}

func (m *mockApi) IsCached(context.Context, ipath.Path) bool {
return false
}

func (m *mockApi) ResolvePath(context.Context, ipath.Path) (ipath.Resolved, error) {
return nil, errors.New("not implemented")
}
Loading

0 comments on commit 276ccba

Please sign in to comment.