@@ -3,35 +3,59 @@ package core
3
3
import (
4
4
"crypto/rand"
5
5
"encoding/base64"
6
- "errors"
7
6
8
7
ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
9
8
dsync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
9
+ goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
10
10
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11
+ bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
11
12
key "github.com/ipfs/go-ipfs/blocks/key"
13
+ bserv "github.com/ipfs/go-ipfs/blockservice"
14
+ offline "github.com/ipfs/go-ipfs/exchange/offline"
15
+ dag "github.com/ipfs/go-ipfs/merkledag"
12
16
ci "github.com/ipfs/go-ipfs/p2p/crypto"
17
+ peer "github.com/ipfs/go-ipfs/p2p/peer"
18
+ path "github.com/ipfs/go-ipfs/path"
19
+ pin "github.com/ipfs/go-ipfs/pin"
13
20
repo "github.com/ipfs/go-ipfs/repo"
14
21
cfg "github.com/ipfs/go-ipfs/repo/config"
15
22
)
16
23
17
- var ErrAlreadyBuilt = errors .New ("this builder has already been used" )
24
+ type BuildCfg struct {
25
+ // If online is set, the node will have networking enabled
26
+ Online bool
18
27
19
- // NodeBuilder is an object used to generate an IpfsNode
20
- type NodeBuilder struct {
21
- online bool
22
- routing RoutingOption
23
- peerhost HostOption
24
- repo repo.Repo
25
- built bool
26
- nilrepo bool
28
+ // If NilRepo is set, a repo backed by a nil datastore will be constructed
29
+ NilRepo bool
30
+
31
+ Routing RoutingOption
32
+ Host HostOption
33
+ Repo repo.Repo
27
34
}
28
35
29
- func NewNodeBuilder () * NodeBuilder {
30
- return & NodeBuilder {
31
- online : false ,
32
- routing : DHTOption ,
33
- peerhost : DefaultHostOption ,
36
+ func (cfg * BuildCfg ) fillDefaults () error {
37
+ if cfg .Repo == nil {
38
+ var d ds.Datastore
39
+ d = ds .NewMapDatastore ()
40
+ if cfg .NilRepo {
41
+ d = ds .NewNullDatastore ()
42
+ }
43
+ r , err := defaultRepo (dsync .MutexWrap (d ))
44
+ if err != nil {
45
+ return err
46
+ }
47
+ cfg .Repo = r
48
+ }
49
+
50
+ if cfg .Routing == nil {
51
+ cfg .Routing = DHTOption
52
+ }
53
+
54
+ if cfg .Host == nil {
55
+ cfg .Host = DefaultHostOption
34
56
}
57
+
58
+ return nil
35
59
}
36
60
37
61
func defaultRepo (dstore ds.ThreadSafeDatastore ) (repo.Repo , error ) {
@@ -62,53 +86,71 @@ func defaultRepo(dstore ds.ThreadSafeDatastore) (repo.Repo, error) {
62
86
}, nil
63
87
}
64
88
65
- func ( nb * NodeBuilder ) Online () * NodeBuilder {
66
- nb . online = true
67
- return nb
68
- }
89
+ func NewNode ( ctx context. Context , cfg * BuildCfg ) ( * IpfsNode , error ) {
90
+ if cfg == nil {
91
+ cfg = new ( BuildCfg )
92
+ }
69
93
70
- func ( nb * NodeBuilder ) Offline () * NodeBuilder {
71
- nb . online = false
72
- return nb
73
- }
94
+ err := cfg . fillDefaults ()
95
+ if err != nil {
96
+ return nil , err
97
+ }
74
98
75
- func (nb * NodeBuilder ) SetRouting (ro RoutingOption ) * NodeBuilder {
76
- nb .routing = ro
77
- return nb
78
- }
99
+ n := & IpfsNode {
100
+ mode : offlineMode ,
101
+ Repo : cfg .Repo ,
102
+ ctx : ctx ,
103
+ Peerstore : peer .NewPeerstore (),
104
+ }
105
+ if cfg .Online {
106
+ n .mode = onlineMode
107
+ }
79
108
80
- func (nb * NodeBuilder ) SetHost (ho HostOption ) * NodeBuilder {
81
- nb .peerhost = ho
82
- return nb
83
- }
109
+ // TODO: this is a weird circular-ish dependency, rework it
110
+ n .proc = goprocessctx .WithContextAndTeardown (ctx , n .teardown )
84
111
85
- func (nb * NodeBuilder ) SetRepo (r repo.Repo ) * NodeBuilder {
86
- nb .repo = r
87
- return nb
88
- }
112
+ success := false
113
+ defer func () {
114
+ if ! success {
115
+ n .teardown ()
116
+ }
117
+ }()
89
118
90
- func ( nb * NodeBuilder ) NilRepo () * NodeBuilder {
91
- nb . nilrepo = true
92
- return nb
93
- }
119
+ // setup local peer ID (private key is loaded in online setup)
120
+ if err := n . loadID (); err != nil {
121
+ return nil , err
122
+ }
94
123
95
- func ( nb * NodeBuilder ) Build ( ctx context. Context ) ( * IpfsNode , error ) {
96
- if nb . built {
97
- return nil , ErrAlreadyBuilt
124
+ n . Blockstore , err = bstore . WriteCached ( bstore . NewBlockstore ( n . Repo . Datastore ()), kSizeBlockstoreWriteCache )
125
+ if err != nil {
126
+ return nil , err
98
127
}
99
- nb .built = true
100
- if nb .repo == nil {
101
- var d ds.Datastore
102
- d = ds .NewMapDatastore ()
103
- if nb .nilrepo {
104
- d = ds .NewNullDatastore ()
105
- }
106
- r , err := defaultRepo (dsync .MutexWrap (d ))
107
- if err != nil {
128
+
129
+ if cfg .Online {
130
+ do := setupDiscoveryOption (n .Repo .Config ().Discovery )
131
+ if err := n .startOnlineServices (ctx , cfg .Routing , cfg .Host , do ); err != nil {
108
132
return nil , err
109
133
}
110
- nb .repo = r
134
+ } else {
135
+ n .Exchange = offline .Exchange (n .Blockstore )
111
136
}
112
- conf := standardWithRouting (nb .repo , nb .online , nb .routing , nb .peerhost )
113
- return NewIPFSNode (ctx , conf )
137
+
138
+ n .Blocks , err = bserv .New (n .Blockstore , n .Exchange )
139
+ if err != nil {
140
+ return nil , err
141
+ }
142
+
143
+ n .DAG = dag .NewDAGService (n .Blocks )
144
+ n .Pinning , err = pin .LoadPinner (n .Repo .Datastore (), n .DAG )
145
+ if err != nil {
146
+ // TODO: we should move towards only running 'NewPinner' explicity on
147
+ // node init instead of implicitly here as a result of the pinner keys
148
+ // not being found in the datastore.
149
+ // this is kinda sketchy and could cause data loss
150
+ n .Pinning = pin .NewPinner (n .Repo .Datastore (), n .DAG )
151
+ }
152
+ n .Resolver = & path.Resolver {DAG : n .DAG }
153
+
154
+ success = true
155
+ return n , nil
114
156
}
0 commit comments