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

Commit 53761df

Browse files
committed
migrate to go-libp2p-core.
1 parent a1ca6a6 commit 53761df

31 files changed

+128
-180
lines changed

bitswap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
metrics "github.com/ipfs/go-metrics-interface"
3030
process "github.com/jbenet/goprocess"
3131
procctx "github.com/jbenet/goprocess/context"
32-
peer "github.com/libp2p/go-libp2p-peer"
32+
peer "github.com/libp2p/go-libp2p-core/peer"
3333
)
3434

3535
var log = logging.Logger("bitswap")

decision/engine.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
logging "github.com/ipfs/go-log"
1717
"github.com/ipfs/go-peertaskqueue"
1818
"github.com/ipfs/go-peertaskqueue/peertask"
19-
peer "github.com/libp2p/go-libp2p-peer"
19+
peer "github.com/libp2p/go-libp2p-core/peer"
2020
)
2121

2222
// TODO consider taking responsibility for other types of requests. For

decision/engine_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
ds "github.com/ipfs/go-datastore"
1616
dssync "github.com/ipfs/go-datastore/sync"
1717
blockstore "github.com/ipfs/go-ipfs-blockstore"
18-
peer "github.com/libp2p/go-libp2p-peer"
18+
peer "github.com/libp2p/go-libp2p-core/peer"
1919
testutil "github.com/libp2p/go-testutil"
2020
)
2121

decision/ledger.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
wl "github.com/ipfs/go-bitswap/wantlist"
88

99
cid "github.com/ipfs/go-cid"
10-
peer "github.com/libp2p/go-libp2p-peer"
10+
peer "github.com/libp2p/go-libp2p-core/peer"
1111
)
1212

1313
func newLedger(p peer.ID) *ledger {

go.mod

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module github.com/ipfs/go-bitswap
22

33
require (
4-
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c // indirect
54
github.com/cskr/pubsub v1.0.2
65
github.com/davecgh/go-spew v1.1.1 // indirect
76
github.com/gogo/protobuf v1.2.1
@@ -22,31 +21,19 @@ require (
2221
github.com/ipfs/go-metrics-interface v0.0.1
2322
github.com/ipfs/go-peertaskqueue v0.0.4
2423
github.com/jbenet/goprocess v0.1.3
25-
github.com/libp2p/go-libp2p v0.0.30
26-
github.com/libp2p/go-libp2p-host v0.0.3
27-
github.com/libp2p/go-libp2p-interface-connmgr v0.0.5
28-
github.com/libp2p/go-libp2p-loggables v0.0.1
29-
github.com/libp2p/go-libp2p-net v0.0.2
30-
github.com/libp2p/go-libp2p-netutil v0.0.1
31-
github.com/libp2p/go-libp2p-peer v0.2.0
32-
github.com/libp2p/go-libp2p-peerstore v0.1.0
33-
github.com/libp2p/go-libp2p-protocol v0.1.0
34-
github.com/libp2p/go-libp2p-routing v0.0.1
35-
github.com/libp2p/go-libp2p-yamux v0.1.3 // indirect
36-
github.com/libp2p/go-mplex v0.0.4 // indirect
37-
github.com/libp2p/go-stream-muxer v0.1.0 // indirect
24+
github.com/libp2p/go-libp2p v0.1.0
25+
github.com/libp2p/go-libp2p-core v0.0.2
26+
github.com/libp2p/go-libp2p-loggables v0.1.0
27+
github.com/libp2p/go-libp2p-netutil v0.1.0
28+
github.com/libp2p/go-libp2p-testing v0.0.3
3829
github.com/libp2p/go-testutil v0.0.1
39-
github.com/libp2p/go-yamux v1.2.3 // indirect
4030
github.com/mattn/go-colorable v0.1.2 // indirect
41-
github.com/minio/sha256-simd v0.1.0 // indirect
4231
github.com/multiformats/go-multiaddr v0.0.4
43-
github.com/multiformats/go-multistream v0.1.0 // indirect
44-
github.com/onsi/ginkgo v1.8.0 // indirect
45-
github.com/onsi/gomega v1.5.0 // indirect
4632
github.com/opentracing/opentracing-go v1.1.0 // indirect
47-
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f // indirect
4833
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
4934
golang.org/x/sys v0.0.0-20190524122548-abf6ff778158 // indirect
5035
golang.org/x/text v0.3.2 // indirect
5136
gopkg.in/yaml.v2 v2.2.2 // indirect
5237
)
38+
39+
replace github.com/ipfs/go-ipfs-routing => ../go-ipfs-routing

go.sum

Lines changed: 41 additions & 88 deletions
Large diffs are not rendered by default.

message/message.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import (
1010

1111
ggio "github.com/gogo/protobuf/io"
1212
cid "github.com/ipfs/go-cid"
13-
inet "github.com/libp2p/go-libp2p-net"
13+
14+
"github.com/libp2p/go-libp2p-core/network"
1415
)
1516

1617
// BitSwapMessage is the basic interface for interacting building, encoding,
@@ -169,7 +170,7 @@ func (m *impl) AddBlock(b blocks.Block) {
169170

170171
// FromNet generates a new BitswapMessage from incoming data on an io.Reader.
171172
func FromNet(r io.Reader) (BitSwapMessage, error) {
172-
pbr := ggio.NewDelimitedReader(r, inet.MessageSizeMax)
173+
pbr := ggio.NewDelimitedReader(r, network.MessageSizeMax)
173174
return FromPBReader(pbr)
174175
}
175176

messagequeue/messagequeue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
bsnet "github.com/ipfs/go-bitswap/network"
1010
wantlist "github.com/ipfs/go-bitswap/wantlist"
1111
logging "github.com/ipfs/go-log"
12-
peer "github.com/libp2p/go-libp2p-peer"
12+
peer "github.com/libp2p/go-libp2p-core/peer"
1313
)
1414

1515
var log = logging.Logger("bitswap")

messagequeue/messagequeue_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
bsmsg "github.com/ipfs/go-bitswap/message"
1111
bsnet "github.com/ipfs/go-bitswap/network"
12-
peer "github.com/libp2p/go-libp2p-peer"
12+
peer "github.com/libp2p/go-libp2p-core/peer"
1313
)
1414

1515
type fakeMessageNetwork struct {

network/interface.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import (
66
bsmsg "github.com/ipfs/go-bitswap/message"
77

88
cid "github.com/ipfs/go-cid"
9-
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
10-
peer "github.com/libp2p/go-libp2p-peer"
11-
protocol "github.com/libp2p/go-libp2p-protocol"
9+
10+
"github.com/libp2p/go-libp2p-core/connmgr"
11+
"github.com/libp2p/go-libp2p-core/peer"
12+
"github.com/libp2p/go-libp2p-core/protocol"
1213
)
1314

1415
var (
@@ -38,7 +39,7 @@ type BitSwapNetwork interface {
3839

3940
NewMessageSender(context.Context, peer.ID) (MessageSender, error)
4041

41-
ConnectionManager() ifconnmgr.ConnManager
42+
ConnectionManager() connmgr.ConnManager
4243

4344
Stats() Stats
4445

network/ipfs_impl.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import (
88
"time"
99

1010
bsmsg "github.com/ipfs/go-bitswap/message"
11+
"github.com/libp2p/go-libp2p-core/helpers"
1112

1213
ggio "github.com/gogo/protobuf/io"
1314
cid "github.com/ipfs/go-cid"
1415
logging "github.com/ipfs/go-log"
15-
host "github.com/libp2p/go-libp2p-host"
16-
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
17-
inet "github.com/libp2p/go-libp2p-net"
18-
peer "github.com/libp2p/go-libp2p-peer"
19-
pstore "github.com/libp2p/go-libp2p-peerstore"
20-
routing "github.com/libp2p/go-libp2p-routing"
16+
"github.com/libp2p/go-libp2p-core/connmgr"
17+
"github.com/libp2p/go-libp2p-core/host"
18+
"github.com/libp2p/go-libp2p-core/network"
19+
"github.com/libp2p/go-libp2p-core/peer"
20+
peerstore "github.com/libp2p/go-libp2p-core/peerstore"
21+
"github.com/libp2p/go-libp2p-core/routing"
2122
ma "github.com/multiformats/go-multiaddr"
2223
)
2324

@@ -47,11 +48,11 @@ type impl struct {
4748
}
4849

4950
type streamMessageSender struct {
50-
s inet.Stream
51+
s network.Stream
5152
}
5253

5354
func (s *streamMessageSender) Close() error {
54-
return inet.FullClose(s.s)
55+
return helpers.FullClose(s.s)
5556
}
5657

5758
func (s *streamMessageSender) Reset() error {
@@ -62,7 +63,7 @@ func (s *streamMessageSender) SendMsg(ctx context.Context, msg bsmsg.BitSwapMess
6263
return msgToStream(ctx, s.s, msg)
6364
}
6465

65-
func msgToStream(ctx context.Context, s inet.Stream, msg bsmsg.BitSwapMessage) error {
66+
func msgToStream(ctx context.Context, s network.Stream, msg bsmsg.BitSwapMessage) error {
6667
deadline := time.Now().Add(sendMessageTimeout)
6768
if dl, ok := ctx.Deadline(); ok {
6869
deadline = dl
@@ -102,7 +103,7 @@ func (bsnet *impl) NewMessageSender(ctx context.Context, p peer.ID) (MessageSend
102103
return &streamMessageSender{s: s}, nil
103104
}
104105

105-
func (bsnet *impl) newStreamToPeer(ctx context.Context, p peer.ID) (inet.Stream, error) {
106+
func (bsnet *impl) newStreamToPeer(ctx context.Context, p peer.ID) (network.Stream, error) {
106107
return bsnet.host.NewStream(ctx, p, ProtocolBitswap, ProtocolBitswapOne, ProtocolBitswapNoVers)
107108
}
108109

@@ -123,7 +124,7 @@ func (bsnet *impl) SendMessage(
123124
atomic.AddUint64(&bsnet.stats.MessagesSent, 1)
124125

125126
// TODO(https://github.com/libp2p/go-libp2p-net/issues/28): Avoid this goroutine.
126-
go inet.AwaitEOF(s)
127+
go helpers.AwaitEOF(s)
127128
return s.Close()
128129

129130
}
@@ -139,7 +140,7 @@ func (bsnet *impl) SetDelegate(r Receiver) {
139140
}
140141

141142
func (bsnet *impl) ConnectTo(ctx context.Context, p peer.ID) error {
142-
return bsnet.host.Connect(ctx, pstore.PeerInfo{ID: p})
143+
return bsnet.host.Connect(ctx, peer.AddrInfo{ID: p})
143144
}
144145

145146
// FindProvidersAsync returns a channel of providers for the given key.
@@ -152,7 +153,7 @@ func (bsnet *impl) FindProvidersAsync(ctx context.Context, k cid.Cid, max int) <
152153
if info.ID == bsnet.host.ID() {
153154
continue // ignore self as provider
154155
}
155-
bsnet.host.Peerstore().AddAddrs(info.ID, info.Addrs, pstore.TempAddrTTL)
156+
bsnet.host.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.TempAddrTTL)
156157
select {
157158
case <-ctx.Done():
158159
return
@@ -169,15 +170,15 @@ func (bsnet *impl) Provide(ctx context.Context, k cid.Cid) error {
169170
}
170171

171172
// handleNewStream receives a new stream from the network.
172-
func (bsnet *impl) handleNewStream(s inet.Stream) {
173+
func (bsnet *impl) handleNewStream(s network.Stream) {
173174
defer s.Close()
174175

175176
if bsnet.receiver == nil {
176177
s.Reset()
177178
return
178179
}
179180

180-
reader := ggio.NewDelimitedReader(s, inet.MessageSizeMax)
181+
reader := ggio.NewDelimitedReader(s, network.MessageSizeMax)
181182
for {
182183
received, err := bsmsg.FromPBReader(reader)
183184
if err != nil {
@@ -197,7 +198,7 @@ func (bsnet *impl) handleNewStream(s inet.Stream) {
197198
}
198199
}
199200

200-
func (bsnet *impl) ConnectionManager() ifconnmgr.ConnManager {
201+
func (bsnet *impl) ConnectionManager() connmgr.ConnManager {
201202
return bsnet.host.ConnManager()
202203
}
203204

@@ -214,15 +215,15 @@ func (nn *netNotifiee) impl() *impl {
214215
return (*impl)(nn)
215216
}
216217

217-
func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
218+
func (nn *netNotifiee) Connected(n network.Network, v network.Conn) {
218219
nn.impl().receiver.PeerConnected(v.RemotePeer())
219220
}
220221

221-
func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
222+
func (nn *netNotifiee) Disconnected(n network.Network, v network.Conn) {
222223
nn.impl().receiver.PeerDisconnected(v.RemotePeer())
223224
}
224225

225-
func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
226-
func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
227-
func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {}
228-
func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}
226+
func (nn *netNotifiee) OpenedStream(n network.Network, v network.Stream) {}
227+
func (nn *netNotifiee) ClosedStream(n network.Network, v network.Stream) {}
228+
func (nn *netNotifiee) Listen(n network.Network, a ma.Multiaddr) {}
229+
func (nn *netNotifiee) ListenClose(n network.Network, a ma.Multiaddr) {}

network/ipfs_impl_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99
tn "github.com/ipfs/go-bitswap/testnet"
1010
blocksutil "github.com/ipfs/go-ipfs-blocksutil"
1111
mockrouting "github.com/ipfs/go-ipfs-routing/mock"
12-
peer "github.com/libp2p/go-libp2p-peer"
12+
13+
"github.com/libp2p/go-libp2p-core/peer"
14+
"github.com/libp2p/go-libp2p-testing/net"
1315
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
14-
testutil "github.com/libp2p/go-testutil"
1516
)
1617

1718
// Receiver is an interface for receiving messages from the GraphSyncNetwork.
@@ -62,8 +63,8 @@ func TestMessageSendAndReceive(t *testing.T) {
6263
if err != nil {
6364
t.Fatal("Unable to setup network")
6465
}
65-
p1 := testutil.RandIdentityOrFatal(t)
66-
p2 := testutil.RandIdentityOrFatal(t)
66+
p1 := tnet.RandIdentityOrFatal(t)
67+
p2 := tnet.RandIdentityOrFatal(t)
6768

6869
bsnet1 := streamNet.Adapter(p1)
6970
bsnet2 := streamNet.Adapter(p2)

peermanager/peermanager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
bsmsg "github.com/ipfs/go-bitswap/message"
77
wantlist "github.com/ipfs/go-bitswap/wantlist"
88

9-
peer "github.com/libp2p/go-libp2p-peer"
9+
peer "github.com/libp2p/go-libp2p-core/peer"
1010
)
1111

1212
// PeerQueue provides a queer of messages to be sent for a single peer.

peermanager/peermanager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
bsmsg "github.com/ipfs/go-bitswap/message"
1212
wantlist "github.com/ipfs/go-bitswap/wantlist"
13-
"github.com/libp2p/go-libp2p-peer"
13+
"github.com/libp2p/go-libp2p-core/peer"
1414
)
1515

1616
type messageSent struct {

providerquerymanager/providerquerymanager.go

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

99
"github.com/ipfs/go-cid"
1010
logging "github.com/ipfs/go-log"
11-
peer "github.com/libp2p/go-libp2p-peer"
11+
peer "github.com/libp2p/go-libp2p-core/peer"
1212
)
1313

1414
var log = logging.Logger("bitswap")

providerquerymanager/providerquerymanager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/ipfs/go-bitswap/testutil"
1212

1313
cid "github.com/ipfs/go-cid"
14-
"github.com/libp2p/go-libp2p-peer"
14+
"github.com/libp2p/go-libp2p-core/peer"
1515
)
1616

1717
type fakeProviderNetwork struct {

session/session.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
blocks "github.com/ipfs/go-block-format"
1111
cid "github.com/ipfs/go-cid"
1212
logging "github.com/ipfs/go-log"
13+
peer "github.com/libp2p/go-libp2p-core/peer"
1314
loggables "github.com/libp2p/go-libp2p-loggables"
14-
peer "github.com/libp2p/go-libp2p-peer"
1515

1616
bssrs "github.com/ipfs/go-bitswap/sessionrequestsplitter"
1717
)

session/session_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/ipfs/go-bitswap/testutil"
1313
cid "github.com/ipfs/go-cid"
1414
blocksutil "github.com/ipfs/go-ipfs-blocksutil"
15-
peer "github.com/libp2p/go-libp2p-peer"
15+
peer "github.com/libp2p/go-libp2p-core/peer"
1616
)
1717

1818
type wantReq struct {

sessionmanager/sessionmanager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
bssession "github.com/ipfs/go-bitswap/session"
1111
exchange "github.com/ipfs/go-ipfs-exchange-interface"
12-
peer "github.com/libp2p/go-libp2p-peer"
12+
peer "github.com/libp2p/go-libp2p-core/peer"
1313
)
1414

1515
// Session is a session that is managed by the session manager

sessionmanager/sessionmanager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
blocks "github.com/ipfs/go-block-format"
1313
cid "github.com/ipfs/go-cid"
14-
peer "github.com/libp2p/go-libp2p-peer"
14+
peer "github.com/libp2p/go-libp2p-core/peer"
1515
)
1616

1717
type fakeSession struct {

sessionpeermanager/sessionpeermanager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"math/rand"
77

88
cid "github.com/ipfs/go-cid"
9-
peer "github.com/libp2p/go-libp2p-peer"
9+
peer "github.com/libp2p/go-libp2p-core/peer"
1010
)
1111

1212
const (

sessionpeermanager/sessionpeermanager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/ipfs/go-bitswap/testutil"
1111

1212
cid "github.com/ipfs/go-cid"
13-
peer "github.com/libp2p/go-libp2p-peer"
13+
peer "github.com/libp2p/go-libp2p-core/peer"
1414
)
1515

1616
type fakePeerProviderFinder struct {

sessionrequestsplitter/sessionrequestsplitter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"context"
55

66
"github.com/ipfs/go-cid"
7-
"github.com/libp2p/go-libp2p-peer"
7+
"github.com/libp2p/go-libp2p-core/peer"
88
)
99

1010
const (

0 commit comments

Comments
 (0)