Skip to content

Commit

Permalink
feat: add check using only a CID
Browse files Browse the repository at this point in the history
Fixes #6
  • Loading branch information
2color committed Aug 21, 2024
1 parent 91cf699 commit 06155c5
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 28 deletions.
109 changes: 82 additions & 27 deletions daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package main

import (
"context"
"errors"
"fmt"
"log"
"net/url"
"sync"
"time"

Expand Down Expand Up @@ -38,6 +36,10 @@ type daemon struct {
createTestHost func() (host.Host, error)
}

// number of providers at which to stop looking for providers in the DHT
// When doing a check only with a CID
var MaxProvidersCount = 3

func newDaemon(ctx context.Context, acceleratedDHT bool) (*daemon, error) {
rm, err := NewResourceManager()
if err != nil {
Expand Down Expand Up @@ -108,18 +110,79 @@ func (d *daemon) mustStart() {

}

func (d *daemon) runCheck(query url.Values) (*output, error) {
maStr := query.Get("multiaddr")
cidStr := query.Get("cid")
type providerOutput struct {
ID string
Addrs []string
ConnectionMaddrs []string
BitswapCheckOutput BitswapCheckOutput
}

if maStr == "" {
return nil, errors.New("missing 'multiaddr' argument")
func (d *daemon) runCidCheck(cidStr string) (*[]providerOutput, error) {
cid, err := cid.Decode(cidStr)
if err != nil {
return nil, err

Check warning on line 123 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L120-L123

Added lines #L120 - L123 were not covered by tests
}

if cidStr == "" {
return nil, errors.New("missing 'cid' argument")
ctx := context.Background()
out := make([]providerOutput, 0, 3)

Check warning on line 127 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L126-L127

Added lines #L126 - L127 were not covered by tests

queryCtx, cancel := context.WithCancel(ctx)
defer cancel()
provsCh := d.dht.FindProvidersAsync(queryCtx, cid, MaxProvidersCount)

Check warning on line 131 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L129-L131

Added lines #L129 - L131 were not covered by tests

for provider := range provsCh {
addrs := make([]string, len(provider.Addrs))
for i, addr := range provider.Addrs {
addrs[i] = addr.String()

Check warning on line 136 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L133-L136

Added lines #L133 - L136 were not covered by tests
}

provOutput := providerOutput{
ID: provider.ID.String(),
Addrs: addrs,
BitswapCheckOutput: BitswapCheckOutput{},

Check warning on line 142 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L139-L142

Added lines #L139 - L142 were not covered by tests
}

testHost, err := d.createTestHost()
if err != nil {
return nil, fmt.Errorf("server error: %w", err)

Check warning on line 147 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L145-L147

Added lines #L145 - L147 were not covered by tests
}
defer testHost.Close()

Check warning on line 149 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L149

Added line #L149 was not covered by tests

// Test Is the target connectable
dialCtx, dialCancel := context.WithTimeout(ctx, time.Second*15)

Check warning on line 152 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L152

Added line #L152 was not covered by tests

// we call NewStream to force NAT hole punching
// See https://github.com/libp2p/go-libp2p/issues/2714
testHost.Connect(dialCtx, provider)
_, connErr := testHost.NewStream(dialCtx, provider.ID, "/ipfs/bitswap/1.2.0", "/ipfs/bitswap/1.1.0", "/ipfs/bitswap/1.0.0", "/ipfs/bitswap")
dialCancel()

Check warning on line 158 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L156-L158

Added lines #L156 - L158 were not covered by tests

if connErr != nil {
provOutput.BitswapCheckOutput.Error = fmt.Sprintf("error dialing to peer: %s", connErr.Error())
} else {

Check warning on line 162 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L160-L162

Added lines #L160 - L162 were not covered by tests
// TODO: Modify checkBitswapCID and vole to accept `AddrInfo` so that it can test any of the connections
provOutput.BitswapCheckOutput = checkBitswapCID(ctx, testHost, cid, provider.Addrs[0])

Check warning on line 164 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L164

Added line #L164 was not covered by tests

for _, c := range testHost.Network().ConnsToPeer(provider.ID) {
provOutput.ConnectionMaddrs = append(provOutput.ConnectionMaddrs, c.RemoteMultiaddr().String())

Check warning on line 167 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L166-L167

Added lines #L166 - L167 were not covered by tests
}
}

out = append(out, provOutput)

Check warning on line 171 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L171

Added line #L171 was not covered by tests
}

return &out, nil

Check warning on line 174 in daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon.go#L174

Added line #L174 was not covered by tests
}

type peerCheckOutput struct {
ConnectionError string
PeerFoundInDHT map[string]int
CidInDHT bool
ConnectionMaddrs []string
DataAvailableOverBitswap BitswapCheckOutput
}

func (d *daemon) runPeerCheck(maStr, cidStr string) (*peerCheckOutput, error) {
ma, err := multiaddr.NewMultiaddr(maStr)
if err != nil {
return nil, err
Expand All @@ -139,11 +202,11 @@ func (d *daemon) runCheck(query url.Values) (*output, error) {
}

ctx := context.Background()
out := &output{}
out := &peerCheckOutput{}

connectionFailed := false

out.CidInDHT = providerRecordInDHT(ctx, d.dht, c, ai.ID)
out.CidInDHT = providerRecordForPeerInDHT(ctx, d.dht, c, ai.ID)

addrMap, peerAddrDHTErr := peerAddrsInDHT(ctx, d.dht, d.dhtMessenger, ai.ID)
out.PeerFoundInDHT = addrMap
Expand Down Expand Up @@ -202,6 +265,13 @@ func (d *daemon) runCheck(query url.Values) (*output, error) {
return out, nil
}

type BitswapCheckOutput struct {
Duration time.Duration
Found bool
Responded bool
Error string
}

func checkBitswapCID(ctx context.Context, host host.Host, c cid.Cid, ma multiaddr.Multiaddr) BitswapCheckOutput {
log.Printf("Start of Bitswap check for cid %s by attempting to connect to ma: %v with the temporary peer: %s", c, ma, host.ID())
out := BitswapCheckOutput{}
Expand All @@ -223,21 +293,6 @@ func checkBitswapCID(ctx context.Context, host host.Host, c cid.Cid, ma multiadd
return out
}

type BitswapCheckOutput struct {
Duration time.Duration
Found bool
Responded bool
Error string
}

type output struct {
ConnectionError string
PeerFoundInDHT map[string]int
CidInDHT bool
ConnectionMaddrs []string
DataAvailableOverBitswap BitswapCheckOutput
}

func peerAddrsInDHT(ctx context.Context, d kademlia, messenger *dhtpb.ProtocolMessenger, p peer.ID) (map[string]int, error) {
closestPeers, err := d.GetClosestPeers(ctx, string(p))
if err != nil {
Expand Down Expand Up @@ -281,7 +336,7 @@ func peerAddrsInDHT(ctx context.Context, d kademlia, messenger *dhtpb.ProtocolMe
return addrMap, nil
}

func providerRecordInDHT(ctx context.Context, d kademlia, c cid.Cid, p peer.ID) bool {
func providerRecordForPeerInDHT(ctx context.Context, d kademlia, c cid.Cid, p peer.ID) bool {
queryCtx, cancel := context.WithCancel(ctx)
defer cancel()
provsCh := d.FindProvidersAsync(queryCtx, c, 0)
Expand Down
19 changes: 18 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/subtle"
"encoding/json"
"errors"
"log"
"net"
"net/http"
Expand Down Expand Up @@ -77,7 +78,23 @@ func startServer(ctx context.Context, d *daemon, tcpListener, metricsUsername, m

checkHandler := func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")
data, err := d.runCheck(r.URL.Query())

maStr := r.URL.Query().Get("multiaddr")
cidStr := r.URL.Query().Get("cid")

if cidStr == "" {
err = errors.New("missing 'cid' argument")

Check warning on line 86 in main.go

View check run for this annotation

Codecov / codecov/patch

main.go#L86

Added line #L86 was not covered by tests
}

var err error
var data interface{}

if maStr == "" {
data, err = d.runCidCheck(cidStr)

Check warning on line 93 in main.go

View check run for this annotation

Codecov / codecov/patch

main.go#L93

Added line #L93 was not covered by tests
} else {
data, err = d.runPeerCheck(maStr, cidStr)
}

if err == nil {
w.Header().Add("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(data)
Expand Down

0 comments on commit 06155c5

Please sign in to comment.