merkledag.go 3.72 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package merkledag

import (
4
	"fmt"
Chas Leichner's avatar
Chas Leichner committed
5

6 7
	"code.google.com/p/goprotobuf/proto"

8
	blocks "github.com/jbenet/go-ipfs/blocks"
9
	bserv "github.com/jbenet/go-ipfs/blockservice"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
11
	mh "github.com/jbenet/go-multihash"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12 13
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
14 15 16
// NodeMap maps u.Keys to Nodes.
// We cannot use []byte/Multihash for keys :(
// so have to convert Multihash bytes to string (u.Key)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17 18
type NodeMap map[u.Key]*Node

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
19
// Node represents a node in the IPFS Merkle DAG.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20
// nodes have opaque data and a set of navigable links.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21
type Node struct {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
22 23
	Links []*Link
	Data  []byte
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26

	// cache encoded/marshaled value
	encoded []byte
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27 28
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
29
// Link represents an IPFS Merkle DAG Link between Nodes.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
30
type Link struct {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
31 32
	// utf string name. should be unique per object
	Name string // utf8
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
34 35
	// cumulative size of target object
	Size uint64
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
37 38
	// multihash of the target object
	Hash mh.Multihash
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39 40 41

	// a ptr to the actual node for graph manipulation
	Node *Node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42 43
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
44
// AddNodeLink adds a link to another node.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
func (n *Node) AddNodeLink(name string, that *Node) error {
	s, err := that.Size()
	if err != nil {
		return err
	}

	h, err := that.Multihash()
	if err != nil {
		return err
	}

	n.Links = append(n.Links, &Link{
		Name: name,
		Size: s,
		Hash: h,
60
		Node: that,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61 62 63
	})
	return nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
65 66
// Size returns the total size of the data addressed by node,
// including the total sizes of references.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
67
func (n *Node) Size() (uint64, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68
	b, err := n.Encoded(false)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
69 70 71 72
	if err != nil {
		return 0, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73
	s := uint64(len(b))
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
74 75 76 77
	for _, l := range n.Links {
		s += l.Size
	}
	return s, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
80
// Multihash hashes the encoded data of this node.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81 82 83 84 85 86
func (n *Node) Multihash() (mh.Multihash, error) {
	b, err := n.Encoded(false)
	if err != nil {
		return nil, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87
	return u.Hash(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
88
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
90
// Key returns the Multihash as a key, for maps.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91 92 93 94
func (n *Node) Key() (u.Key, error) {
	h, err := n.Multihash()
	return u.Key(h), err
}
95

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
96 97 98
// DAGService is an IPFS Merkle DAG service.
// - the root is virtual (like a forest)
// - stores nodes' data in a BlockService
99
type DAGService struct {
100
	Blocks *bserv.BlockService
101 102
}

103 104 105 106
// Add adds a node to the DAGService, storing the block in the BlockService
func (n *DAGService) Add(nd *Node) (u.Key, error) {
	k, _ := nd.Key()
	u.DOut("DagService Add [%s]\n", k.Pretty())
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
	if n == nil {
		return "", fmt.Errorf("DAGService is nil")
	}

	d, err := nd.Encoded(false)
	if err != nil {
		return "", err
	}

	b, err := blocks.NewBlock(d)
	if err != nil {
		return "", err
	}

	return n.Blocks.AddBlock(b)
}

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
func (n *DAGService) AddRecursive(nd *Node) error {
	_, err := n.Add(nd)
	if err != nil {
		return err
	}

	for _, link := range nd.Links {
		fmt.Println("Adding link.")
		if link.Node == nil {
			panic("Why does this node have a nil link?\n")
		}
		err := n.AddRecursive(link.Node)
		if err != nil {
			return err
		}
	}

	return nil
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
144
// Get retrieves a node from the DAGService, fetching the block in the BlockService
145 146 147 148 149 150 151 152 153 154 155 156
func (n *DAGService) Get(k u.Key) (*Node, error) {
	if n == nil {
		return nil, fmt.Errorf("DAGService is nil")
	}

	b, err := n.Blocks.GetBlock(k)
	if err != nil {
		return nil, err
	}

	return Decoded(b.Data)
}
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

func FilePBData() []byte {
	pbfile := new(PBData)
	typ := PBData_File
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func FolderPBData() []byte {
	pbfile := new(PBData)
	typ := PBData_Directory
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func WrapData(b []byte) []byte {
	pbdata := new(PBData)
	typ := PBData_Raw
	pbdata.Data = b
	pbdata.Type = &typ

	out, err := proto.Marshal(pbdata)
	if err != nil {
		// This shouldnt happen. seriously.
		panic(err)
	}

	return out
}