@@ -13,6 +13,7 @@ import (
13
13
"github.com/qri-io/dag"
14
14
"github.com/qri-io/dag/dsync"
15
15
"github.com/qri-io/qri/actions"
16
+ "github.com/qri-io/qri/base"
16
17
"github.com/qri-io/qri/p2p"
17
18
"github.com/qri-io/qri/repo"
18
19
@@ -24,10 +25,10 @@ const allowedDagInfoSize uint64 = 10 * 1024 * 1024
24
25
25
26
// RemoteRequests encapsulates business logic of remote operation
26
27
type RemoteRequests struct {
27
- cli * rpc.Client
28
- node * p2p.QriNode
29
- Receivers * dsync.Receivers
30
- SessionIDs map [string ]* dag. Info
28
+ cli * rpc.Client
29
+ node * p2p.QriNode
30
+ Receivers * dsync.Receivers
31
+ Sessions map [string ]* ReceiveParams
31
32
}
32
33
33
34
// NewRemoteRequests creates a RemoteRequests pointer from either a node or an rpc.Client
@@ -36,15 +37,20 @@ func NewRemoteRequests(node *p2p.QriNode, cli *rpc.Client) *RemoteRequests {
36
37
panic (fmt .Errorf ("both repo and client supplied to NewRemoteRequests" ))
37
38
}
38
39
return & RemoteRequests {
39
- cli : cli ,
40
- node : node ,
41
- SessionIDs : make (map [string ]* dag. Info ),
40
+ cli : cli ,
41
+ node : node ,
42
+ Sessions : make (map [string ]* ReceiveParams ),
42
43
}
43
44
}
44
45
45
46
// CoreRequestsName implements the Requests interface
46
47
func (RemoteRequests ) CoreRequestsName () string { return "remote" }
47
48
49
+ // TODO(dlong): Split this function into smaller steps, move them to actions/ or base/ as
50
+ // appropriate
51
+
52
+ // TODO(dlong): Add tests
53
+
48
54
// PushToRemote posts a dagInfo to a remote
49
55
func (r * RemoteRequests ) PushToRemote (p * PushParams , out * bool ) error {
50
56
if r .cli != nil {
@@ -69,12 +75,23 @@ func (r *RemoteRequests) PushToRemote(p *PushParams, out *bool) error {
69
75
return fmt .Errorf ("remote name \" %s\" not found" , p .RemoteName )
70
76
}
71
77
72
- data , err := json .Marshal (dinfo )
78
+ // Post the dataset's dag.Info to the remote.
79
+ fmt .Printf ("Posting to /dsync/push...\n " )
80
+
81
+ params := ReceiveParams {
82
+ Peername : ref .Peername ,
83
+ Name : ref .Name ,
84
+ ProfileID : ref .ProfileID ,
85
+ Dinfo : dinfo ,
86
+ }
87
+
88
+ data , err := json .Marshal (params )
73
89
if err != nil {
74
90
return err
75
91
}
76
92
77
- req , err := http .NewRequest ("POST" , fmt .Sprintf ("%s/dataset" , location ), bytes .NewReader (data ))
93
+ dsyncPushURL := fmt .Sprintf ("%s/dsync/push" , location )
94
+ req , err := http .NewRequest ("POST" , dsyncPushURL , bytes .NewReader (data ))
78
95
if err != nil {
79
96
return err
80
97
}
@@ -90,13 +107,14 @@ func (r *RemoteRequests) PushToRemote(p *PushParams, out *bool) error {
90
107
return fmt .Errorf ("error code %d: %v" , res .StatusCode , rejectionReason (res .Body ))
91
108
}
92
109
93
- env := struct {Data ReceiveResult }{}
110
+ env := struct { Data ReceiveResult }{}
94
111
if err := json .NewDecoder (res .Body ).Decode (& env ); err != nil {
95
112
return err
96
113
}
97
114
res .Body .Close ()
98
115
99
- ctx := context .Background ()
116
+ // Run dsync to transfer all of the blocks of the dataset.
117
+ fmt .Printf ("Running dsync...\n " )
100
118
101
119
ng , err := newNodeGetter (r .node )
102
120
if err != nil {
@@ -107,6 +125,7 @@ func (r *RemoteRequests) PushToRemote(p *PushParams, out *bool) error {
107
125
URL : fmt .Sprintf ("%s/dsync" , location ),
108
126
}
109
127
128
+ ctx := context .Background ()
110
129
send , err := dsync .NewSend (ctx , ng , dinfo .Manifest , remote )
111
130
if err != nil {
112
131
return err
@@ -117,7 +136,36 @@ func (r *RemoteRequests) PushToRemote(p *PushParams, out *bool) error {
117
136
return err
118
137
}
119
138
120
- // TODO(dlong): Pin the data.
139
+ // Finish the send, pin the dataset in IPFS
140
+ fmt .Printf ("Writing dsref and pinning...\n " )
141
+
142
+ completeParams := CompleteParams {
143
+ SessionID : env .Data .SessionID ,
144
+ }
145
+
146
+ data , err = json .Marshal (completeParams )
147
+ if err != nil {
148
+ return err
149
+ }
150
+
151
+ dsyncCompleteURL := fmt .Sprintf ("%s/dsync/complete" , location )
152
+ req , err = http .NewRequest ("POST" , dsyncCompleteURL , bytes .NewReader (data ))
153
+ if err != nil {
154
+ return err
155
+ }
156
+ req .Header .Set ("Content-Type" , "application/json" )
157
+
158
+ res , err = httpClient .Do (req )
159
+ if err != nil {
160
+ return err
161
+ }
162
+
163
+ if res .StatusCode != http .StatusOK {
164
+ return fmt .Errorf ("error code %d: %v" , res .StatusCode , rejectionReason (res .Body ))
165
+ }
166
+
167
+ // Success!
168
+ fmt .Printf ("Success!\n " )
121
169
122
170
* out = true
123
171
return nil
@@ -142,12 +190,6 @@ func (r *RemoteRequests) Receive(p *ReceiveParams, res *ReceiveResult) (err erro
142
190
143
191
res .Success = false
144
192
145
- dinfo := dag.Info {}
146
- err = json .Unmarshal ([]byte (p .Body ), & dinfo )
147
- if err != nil {
148
- return err
149
- }
150
-
151
193
// TODO(dlong): Customization for how to decide to accept the dataset.
152
194
if Config .API .RemoteAcceptSizeMax == 0 {
153
195
res .RejectReason = "not accepting any datasets"
@@ -157,7 +199,7 @@ func (r *RemoteRequests) Receive(p *ReceiveParams, res *ReceiveResult) (err erro
157
199
// If size is -1, accept any size of dataset. Otherwise, check if the size is allowed.
158
200
if Config .API .RemoteAcceptSizeMax != - 1 {
159
201
var totalSize uint64
160
- for _ , s := range dinfo .Sizes {
202
+ for _ , s := range p . Dinfo .Sizes {
161
203
totalSize += s
162
204
}
163
205
@@ -167,7 +209,7 @@ func (r *RemoteRequests) Receive(p *ReceiveParams, res *ReceiveResult) (err erro
167
209
}
168
210
}
169
211
170
- if dinfo .Manifest == nil {
212
+ if p . Dinfo .Manifest == nil {
171
213
res .RejectReason = "manifest is nil"
172
214
return nil
173
215
}
@@ -177,21 +219,57 @@ func (r *RemoteRequests) Receive(p *ReceiveParams, res *ReceiveResult) (err erro
177
219
return nil
178
220
}
179
221
180
- sid , diff , err := r .Receivers .ReqSend (dinfo .Manifest )
222
+ sid , diff , err := r .Receivers .ReqSend (p . Dinfo .Manifest )
181
223
if err != nil {
182
224
res .RejectReason = fmt .Sprintf ("could not begin send: %s" , err )
183
225
return nil
184
226
}
185
227
186
- // TODO: Timeout for sessionIDs. Add a callback to dsync.Receivers when dsync finishes,
187
- // then create a version of the dataset for ds_refs.
188
- r .SessionIDs [sid ] = & dinfo
228
+ // TODO: Timeout for sessions. Remove sessions when they complete or timeout
229
+ r .Sessions [sid ] = p
189
230
res .Success = true
190
231
res .SessionID = sid
191
232
res .Diff = diff
192
233
return nil
193
234
}
194
235
236
+ // Complete is used to complete a dataset that has been pushed to this remote
237
+ func (r * RemoteRequests ) Complete (p * CompleteParams , res * bool ) (err error ) {
238
+ sid := p .SessionID
239
+ session , ok := r .Sessions [sid ]
240
+ if ! ok {
241
+ return fmt .Errorf ("session %s not found" , sid )
242
+ }
243
+
244
+ if session .Dinfo .Manifest == nil || len (session .Dinfo .Manifest .Nodes ) == 0 {
245
+ return fmt .Errorf ("dataset manifest is invalid" )
246
+ }
247
+
248
+ path := fmt .Sprintf ("/ipfs/%s" , session .Dinfo .Manifest .Nodes [0 ])
249
+
250
+ ref := repo.DatasetRef {
251
+ Peername : session .Peername ,
252
+ ProfileID : session .ProfileID ,
253
+ Name : session .Name ,
254
+ Path : path ,
255
+ Published : true ,
256
+ }
257
+
258
+ // Save ref to ds_refs.json
259
+ err = r .node .Repo .PutRef (ref )
260
+ if err != nil {
261
+ return err
262
+ }
263
+
264
+ // Pin the dataset in IPFS
265
+ err = base .PinDataset (r .node .Repo , ref )
266
+ if err != nil {
267
+ return err
268
+ }
269
+
270
+ return nil
271
+ }
272
+
195
273
func rejectionReason (r io.Reader ) string {
196
274
text , err := ioutil .ReadAll (r )
197
275
if err != nil {
0 commit comments