message.go 2.35 KB
Newer Older
1 2 3
package message

import (
4
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
5
	blocks "github.com/jbenet/go-ipfs/blocks"
6
	pb "github.com/jbenet/go-ipfs/exchange/bitswap/message/internal/pb"
7
	netmsg "github.com/jbenet/go-ipfs/net/message"
8 9 10 11 12
	nm "github.com/jbenet/go-ipfs/net/message"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

13 14 15
// TODO move message.go into the bitswap package
// TODO move bs/msg/internal/pb to bs/internal/pb and rename pb package to bitswap_pb

16 17 18
type BitSwapMessage interface {
	Wantlist() []u.Key
	Blocks() []blocks.Block
19
	AddWanted(k u.Key)
20
	AddBlock(b blocks.Block)
21 22 23 24
	Exportable
}

type Exportable interface {
25
	ToProto() *pb.Message
26
	ToNet(p peer.Peer) (nm.NetMessage, error)
27 28
}

29
type impl struct {
30 31 32
	existsInWantlist map[u.Key]struct{}     // map to detect duplicates
	wantlist         []u.Key                // slice to preserve ordering
	blocks           map[u.Key]blocks.Block // map to detect duplicates
33 34
}

35
func New() BitSwapMessage {
36
	return &impl{
37 38 39
		blocks:           make(map[u.Key]blocks.Block),
		existsInWantlist: make(map[u.Key]struct{}),
		wantlist:         make([]u.Key, 0),
40
	}
41 42
}

43
func newMessageFromProto(pbm pb.Message) BitSwapMessage {
44 45
	m := New()
	for _, s := range pbm.GetWantlist() {
46
		m.AddWanted(u.Key(s))
47 48
	}
	for _, d := range pbm.GetBlocks() {
49
		b := blocks.NewBlock(d)
50
		m.AddBlock(*b)
51
	}
52
	return m
53 54
}

55
func (m *impl) Wantlist() []u.Key {
56
	return m.wantlist
57 58
}

59
func (m *impl) Blocks() []blocks.Block {
60 61 62 63 64
	bs := make([]blocks.Block, 0)
	for _, block := range m.blocks {
		bs = append(bs, block)
	}
	return bs
65 66
}

67
func (m *impl) AddWanted(k u.Key) {
68 69 70 71 72 73
	_, exists := m.existsInWantlist[k]
	if exists {
		return
	}
	m.existsInWantlist[k] = struct{}{}
	m.wantlist = append(m.wantlist, k)
74 75
}

76
func (m *impl) AddBlock(b blocks.Block) {
77
	m.blocks[b.Key()] = b
78 79 80
}

func FromNet(nmsg netmsg.NetMessage) (BitSwapMessage, error) {
81
	pb := new(pb.Message)
82 83 84
	if err := proto.Unmarshal(nmsg.Data(), pb); err != nil {
		return nil, err
	}
85
	m := newMessageFromProto(*pb)
86
	return m, nil
87 88
}

89
func (m *impl) ToProto() *pb.Message {
90
	pb := new(pb.Message)
91 92 93 94 95 96 97
	for _, k := range m.Wantlist() {
		pb.Wantlist = append(pb.Wantlist, string(k))
	}
	for _, b := range m.Blocks() {
		pb.Blocks = append(pb.Blocks, b.Data)
	}
	return pb
98 99
}

100
func (m *impl) ToNet(p peer.Peer) (nm.NetMessage, error) {
101 102
	return nm.FromObject(p, m.ToProto())
}