github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/exchange/bitswap/network/ipfs_impl.go (about) 1 package network 2 3 import ( 4 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 5 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 6 key "github.com/ipfs/go-ipfs/blocks/key" 7 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" 8 host "github.com/ipfs/go-ipfs/p2p/host" 9 inet "github.com/ipfs/go-ipfs/p2p/net" 10 peer "github.com/ipfs/go-ipfs/p2p/peer" 11 routing "github.com/ipfs/go-ipfs/routing" 12 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 13 ) 14 15 var log = eventlog.Logger("bitswap_network") 16 17 // NewFromIpfsHost returns a BitSwapNetwork supported by underlying IPFS host 18 func NewFromIpfsHost(host host.Host, r routing.IpfsRouting) BitSwapNetwork { 19 bitswapNetwork := impl{ 20 host: host, 21 routing: r, 22 } 23 host.SetStreamHandler(ProtocolBitswap, bitswapNetwork.handleNewStream) 24 host.Network().Notify((*netNotifiee)(&bitswapNetwork)) 25 // TODO: StopNotify. 26 27 return &bitswapNetwork 28 } 29 30 // impl transforms the ipfs network interface, which sends and receives 31 // NetMessage objects, into the bitswap network interface. 32 type impl struct { 33 host host.Host 34 routing routing.IpfsRouting 35 36 // inbound messages from the network are forwarded to the receiver 37 receiver Receiver 38 } 39 40 func (bsnet *impl) newStreamToPeer(ctx context.Context, p peer.ID) (inet.Stream, error) { 41 42 // first, make sure we're connected. 43 // if this fails, we cannot connect to given peer. 44 //TODO(jbenet) move this into host.NewStream? 45 if err := bsnet.host.Connect(ctx, peer.PeerInfo{ID: p}); err != nil { 46 return nil, err 47 } 48 49 return bsnet.host.NewStream(ProtocolBitswap, p) 50 } 51 52 func (bsnet *impl) SendMessage( 53 ctx context.Context, 54 p peer.ID, 55 outgoing bsmsg.BitSwapMessage) error { 56 57 s, err := bsnet.newStreamToPeer(ctx, p) 58 if err != nil { 59 return err 60 } 61 defer s.Close() 62 63 if err := outgoing.ToNet(s); err != nil { 64 log.Debugf("error: %s", err) 65 return err 66 } 67 68 return err 69 } 70 71 func (bsnet *impl) SendRequest( 72 ctx context.Context, 73 p peer.ID, 74 outgoing bsmsg.BitSwapMessage) (bsmsg.BitSwapMessage, error) { 75 76 s, err := bsnet.newStreamToPeer(ctx, p) 77 if err != nil { 78 return nil, err 79 } 80 defer s.Close() 81 82 if err := outgoing.ToNet(s); err != nil { 83 log.Debugf("error: %s", err) 84 return nil, err 85 } 86 87 incoming, err := bsmsg.FromNet(s) 88 if err != nil { 89 log.Debugf("error: %s", err) 90 return incoming, err 91 } 92 93 return incoming, nil 94 } 95 96 func (bsnet *impl) SetDelegate(r Receiver) { 97 bsnet.receiver = r 98 } 99 100 func (bsnet *impl) ConnectTo(ctx context.Context, p peer.ID) error { 101 return bsnet.host.Connect(ctx, peer.PeerInfo{ID: p}) 102 } 103 104 // FindProvidersAsync returns a channel of providers for the given key 105 func (bsnet *impl) FindProvidersAsync(ctx context.Context, k key.Key, max int) <-chan peer.ID { 106 107 // Since routing queries are expensive, give bitswap the peers to which we 108 // have open connections. Note that this may cause issues if bitswap starts 109 // precisely tracking which peers provide certain keys. This optimization 110 // would be misleading. In the long run, this may not be the most 111 // appropriate place for this optimization, but it won't cause any harm in 112 // the short term. 113 connectedPeers := bsnet.host.Network().Peers() 114 out := make(chan peer.ID, len(connectedPeers)) // just enough buffer for these connectedPeers 115 for _, id := range connectedPeers { 116 if id == bsnet.host.ID() { 117 continue // ignore self as provider 118 } 119 out <- id 120 } 121 122 go func() { 123 defer close(out) 124 providers := bsnet.routing.FindProvidersAsync(ctx, k, max) 125 for info := range providers { 126 if info.ID == bsnet.host.ID() { 127 continue // ignore self as provider 128 } 129 bsnet.host.Peerstore().AddAddrs(info.ID, info.Addrs, peer.TempAddrTTL) 130 select { 131 case <-ctx.Done(): 132 return 133 case out <- info.ID: 134 } 135 } 136 }() 137 return out 138 } 139 140 // Provide provides the key to the network 141 func (bsnet *impl) Provide(ctx context.Context, k key.Key) error { 142 return bsnet.routing.Provide(ctx, k) 143 } 144 145 // handleNewStream receives a new stream from the network. 146 func (bsnet *impl) handleNewStream(s inet.Stream) { 147 defer s.Close() 148 149 if bsnet.receiver == nil { 150 return 151 } 152 153 received, err := bsmsg.FromNet(s) 154 if err != nil { 155 go bsnet.receiver.ReceiveError(err) 156 log.Debugf("bitswap net handleNewStream from %s error: %s", s.Conn().RemotePeer(), err) 157 return 158 } 159 160 p := s.Conn().RemotePeer() 161 ctx := context.Background() 162 log.Debugf("bitswap net handleNewStream from %s", s.Conn().RemotePeer()) 163 bsnet.receiver.ReceiveMessage(ctx, p, received) 164 } 165 166 type netNotifiee impl 167 168 func (nn *netNotifiee) impl() *impl { 169 return (*impl)(nn) 170 } 171 172 func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { 173 nn.impl().receiver.PeerConnected(v.RemotePeer()) 174 } 175 176 func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { 177 nn.impl().receiver.PeerDisconnected(v.RemotePeer()) 178 } 179 180 func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {} 181 func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {} 182 func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {} 183 func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}