package bitswap import ( "code.google.com/p/goprotobuf/proto" blocks "github.com/jbenet/go-ipfs/blocks" peer "github.com/jbenet/go-ipfs/peer" routing "github.com/jbenet/go-ipfs/routing" swarm "github.com/jbenet/go-ipfs/swarm" u "github.com/jbenet/go-ipfs/util" ds "github.com/jbenet/datastore.go" "errors" "time" ) // PartnerWantListMax is the bound for the number of keys we'll store per // partner. These are usually taken from the top of the Partner's WantList // advertisements. WantLists are sorted in terms of priority. const PartnerWantListMax = 10 // KeySet is just a convenient alias for maps of keys, where we only care // access/lookups. type KeySet map[u.Key]struct{} // BitSwap instances implement the bitswap protocol. type BitSwap struct { // peer is the identity of this (local) node. peer *peer.Peer // net holds the connections to all peers. net swarm.Network meschan *swarm.Chan // datastore is the local database // Ledgers of known datastore ds.Datastore // routing interface for communication routing routing.IpfsRouting listener *swarm.MesListener // partners is a map of currently active bitswap relationships. // The Ledger has the peer.ID, and the peer connection works through net. // Ledgers of known relationships (active or inactive) stored in datastore. // Changes to the Ledger should be committed to the datastore. partners map[u.Key]*Ledger // haveList is the set of keys we have values for. a map for fast lookups. // haveList KeySet -- not needed. all values in datastore? // wantList is the set of keys we want values for. a map for fast lookups. wantList KeySet haltChan chan struct{} } // NewBitSwap creates a new BitSwap instance. It does not check its parameters. func NewBitSwap(p *peer.Peer, net swarm.Network, d ds.Datastore, r routing.IpfsRouting) *BitSwap { bs := &BitSwap{ peer: p, net: net, datastore: d, partners: LedgerMap{}, wantList: KeySet{}, routing: r, meschan: net.GetChannel(swarm.PBWrapper_BITSWAP), haltChan: make(chan struct{}), } go bs.handleMessages() return bs } // GetBlock attempts to retrieve a particular block from peers, within timeout. func (bs *BitSwap) GetBlock(k u.Key, timeout time.Time) ( *blocks.Block, error) { begin := time.Now() _, err := bs.routing.FindProviders(k, timeout) if err != nil { u.PErr("GetBlock error: %s\n", err) return } tleft := timeout.Sub(time.Now().Sub(begin)) return nil, errors.New("not implemented") } func (bs *BitSwap) getBlock(k u.Key, p *peer.Peer, timeout time.Duration) ([]byte, error) { mes := new(PBMessage) mes.Id = proto.Uint64(swarm.GenerateID()) mes.Key = proto.String(k) typ := PBMessage_GET_BLOCK mes.Type = &typ after := time.After(timeout) resp := bs.listener.Listen(mes.GetId(), 1, timeout) smes := swarm.NewMessage(p, mes) bs.meschan.Outgoing <- smes select { case resp_mes := <-resp: case <-after: u.PErr("getBlock for '%s' timed out.", k) return nil, u.ErrTimeout } } // HaveBlock announces the existance of a block to BitSwap, potentially sending // it to peers (Partners) whose WantLists include it. func (bs *BitSwap) HaveBlock(k u.Key) (*blocks.Block, error) { return nil, errors.New("not implemented") } func (bs *BitSwap) handleMessages() { for { select { case mes := bs.meschan.Incoming: case <-bs.haltChan: } } }