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

import (
4 5
	"io"

6
	blocks "github.com/jbenet/go-ipfs/blocks"
7
	pb "github.com/jbenet/go-ipfs/exchange/bitswap/message/internal/pb"
8
	inet "github.com/jbenet/go-ipfs/net"
9
	u "github.com/jbenet/go-ipfs/util"
10

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11
	ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
12 13
)

14 15 16
// 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

17
type BitSwapMessage interface {
18 19
	// Wantlist returns a slice of unique keys that represent data wanted by
	// the sender.
20
	Wantlist() []u.Key
21 22

	// Blocks returns a slice of unique blocks
Jeromy's avatar
Jeromy committed
23
	Blocks() []*blocks.Block
24 25 26 27 28 29 30 31 32 33 34 35

	// AddWanted adds the key to the Wantlist.
	//
	// Insertion order determines priority. That is, earlier insertions are
	// deemed higher priority than keys inserted later.
	//
	// t = 0, msg.AddWanted(A)
	// t = 1, msg.AddWanted(B)
	//
	// implies Priority(A) > Priority(B)
	AddWanted(u.Key)

Jeromy's avatar
Jeromy committed
36
	AddBlock(*blocks.Block)
37 38 39 40
	Exportable
}

type Exportable interface {
41
	ToProto() *pb.Message
42
	ToNet(w io.Writer) error
43 44
}

45
type impl struct {
Jeromy's avatar
Jeromy committed
46 47 48
	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
49 50
}

51
func New() BitSwapMessage {
52
	return &impl{
Jeromy's avatar
Jeromy committed
53
		blocks:           make(map[u.Key]*blocks.Block),
54 55
		existsInWantlist: make(map[u.Key]struct{}),
		wantlist:         make([]u.Key, 0),
56
	}
57 58
}

59
func newMessageFromProto(pbm pb.Message) BitSwapMessage {
60 61
	m := New()
	for _, s := range pbm.GetWantlist() {
62
		m.AddWanted(u.Key(s))
63 64
	}
	for _, d := range pbm.GetBlocks() {
65
		b := blocks.NewBlock(d)
Jeromy's avatar
Jeromy committed
66
		m.AddBlock(b)
67
	}
68
	return m
69 70
}

71
func (m *impl) Wantlist() []u.Key {
72
	return m.wantlist
73 74
}

Jeromy's avatar
Jeromy committed
75 76
func (m *impl) Blocks() []*blocks.Block {
	bs := make([]*blocks.Block, 0)
77 78 79 80
	for _, block := range m.blocks {
		bs = append(bs, block)
	}
	return bs
81 82
}

83
func (m *impl) AddWanted(k u.Key) {
84 85 86 87 88 89
	_, exists := m.existsInWantlist[k]
	if exists {
		return
	}
	m.existsInWantlist[k] = struct{}{}
	m.wantlist = append(m.wantlist, k)
90 91
}

Jeromy's avatar
Jeromy committed
92
func (m *impl) AddBlock(b *blocks.Block) {
93
	m.blocks[b.Key()] = b
94 95
}

96 97 98
func FromNet(r io.Reader) (BitSwapMessage, error) {
	pbr := ggio.NewDelimitedReader(r, inet.MessageSizeMax)

99
	pb := new(pb.Message)
100
	if err := pbr.ReadMsg(pb); err != nil {
101 102
		return nil, err
	}
103

104
	m := newMessageFromProto(*pb)
105
	return m, nil
106 107
}

108
func (m *impl) ToProto() *pb.Message {
109
	pb := new(pb.Message)
110 111 112 113 114 115 116
	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
117 118
}

119 120 121 122 123 124 125
func (m *impl) ToNet(w io.Writer) error {
	pbw := ggio.NewDelimitedWriter(w)

	if err := pbw.WriteMsg(m.ToProto()); err != nil {
		return err
	}
	return nil
126
}