-
Notifications
You must be signed in to change notification settings - Fork 0
/
cid-calculator.go
105 lines (91 loc) · 3.15 KB
/
cid-calculator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package main
import (
"bytes"
"context"
"fmt"
"path/filepath"
blockservice "github.com/ipfs/boxo/blockservice"
blockstore "github.com/ipfs/boxo/blockstore"
chunker "github.com/ipfs/boxo/chunker"
merkledag "github.com/ipfs/boxo/ipld/merkledag"
unixfs "github.com/ipfs/boxo/ipld/unixfs"
balanced "github.com/ipfs/boxo/ipld/unixfs/importer/balanced"
helpers "github.com/ipfs/boxo/ipld/unixfs/importer/helpers"
mfs "github.com/ipfs/boxo/mfs"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/sync"
)
// Computes the CID for an arbitrary bytestring with a given filename
// by adding the file to an empty directory at the root level of the IPFS node.
//
// Only the last segment of the filename will be used, ie, `/home/alice/foo.zip`
// will be stripped to `foo.zip`.
func singleFileDirIPFSCid(data []byte, filename string) (cid.Cid, error) {
ds := sync.MutexWrap(datastore.NewMapDatastore())
bsvc := blockservice.New(blockstore.NewBlockstore(ds), nil)
dag := merkledag.NewDAGService(bsvc)
cidBuilder := merkledag.V1CidPrefix()
// Strip the leading path segments to get the file name
filename = filepath.Base(filename)
// Create the root node, an empty directory
rootNode := unixfs.EmptyDirNode()
err := rootNode.SetCidBuilder(cidBuilder)
if err != nil {
return cid.Cid{}, fmt.Errorf("error creating the CID builder: %w", err)
}
root, err := mfs.NewRoot(context.Background(), dag, rootNode, nil)
if err != nil {
return cid.Cid{}, fmt.Errorf("error setting new MFS root: %w", err)
}
// Create a chunker-reader from the compressed data
chnk, err := chunker.FromString(bytes.NewReader(data), "size-1048576")
if err != nil {
return cid.Cid{}, fmt.Errorf("error creating chunker-reader from compressed bytes: %w", err)
}
// Create a DAG builder using the same settings as web3storage
params := helpers.DagBuilderParams{
Dagserv: dag,
RawLeaves: true,
Maxlinks: 1024,
CidBuilder: cidBuilder,
}
ufsBuilder, err := params.New(chnk)
if err != nil {
return cid.Cid{}, fmt.Errorf("error creating params from chunk: %w", err)
}
// Create the node for the file in the DAG
node, err := balanced.Layout(ufsBuilder)
if err != nil {
return cid.Cid{}, fmt.Errorf("error creating DAG layout: %w", err)
}
// Add the file to the root directory
err = mfs.PutNode(root, filename, node)
if err != nil {
return cid.Cid{}, fmt.Errorf("error adding node to DAG: %w", err)
}
// Add the file to the dag
_, err = mfs.NewFile(filename, node, nil, dag)
if err != nil {
return cid.Cid{}, fmt.Errorf("error adding compressed file to DAG: %w", err)
}
// Finalize the dag and get the cid
rootDir := root.GetDirectory()
err = rootDir.Flush()
if err != nil {
return cid.Cid{}, fmt.Errorf("error flushing DAG root dir: %w", err)
}
err = root.Close()
if err != nil {
return cid.Cid{}, fmt.Errorf("error closing DAG root: %w", err)
}
rootDirNode, err := rootDir.GetNode()
if err != nil {
return cid.Cid{}, fmt.Errorf("error getting DAG root node: %w", err)
}
err = ufsBuilder.Add(rootDirNode)
if err != nil {
return cid.Cid{}, fmt.Errorf("error adding DAG root to UFS builder: %w", err)
}
return rootDirNode.Cid(), nil
}