1
1
package main
2
2
3
3
import (
4
+ "bufio"
5
+ "encoding/json"
4
6
"errors"
5
7
"fmt"
8
+ "net/http"
6
9
"net/url"
7
10
"os"
8
11
"strconv"
12
+ "strings"
9
13
10
14
"github.com/google/uuid"
11
15
"github.com/mitchellh/go-homedir"
@@ -27,6 +31,7 @@ var marketCmd = &cli.Command{
27
31
Subcommands : []* cli.Command {
28
32
marketSealCmd ,
29
33
marketImportdataCmd ,
34
+ marketAddOfflineURLCmd ,
30
35
},
31
36
}
32
37
@@ -204,3 +209,162 @@ var marketImportdataCmd = &cli.Command{
204
209
return nil
205
210
},
206
211
}
212
+
213
+ var marketAddOfflineURLCmd = & cli.Command {
214
+ Name : "add-url" ,
215
+ Usage : "Add URL to fetch data for offline deals" ,
216
+ Flags : []cli.Flag {
217
+ & cli.StringFlag {
218
+ Name : "file" ,
219
+ Usage : "CSV file location to use for multiple deal input. Each line in the file should be in the format 'uuid,raw size,url,header1,header2...'\" " ,
220
+ Required : true ,
221
+ },
222
+ & cli.StringFlag {
223
+ Name : "header" ,
224
+ Aliases : []string {"H" },
225
+ Usage : "Custom `HEADER` to include in the HTTP request" ,
226
+ Required : true ,
227
+ },
228
+ & cli.StringFlag {
229
+ Name : "url" ,
230
+ Aliases : []string {"u" },
231
+ Usage : "`URL` to send the request to" ,
232
+ Required : true ,
233
+ },
234
+ },
235
+ ArgsUsage : "<deal UUID> <raw size/car size>" ,
236
+ Action : func (cctx * cli.Context ) error {
237
+ if ! cctx .IsSet ("file" ) && cctx .Args ().Len () != 2 {
238
+ return xerrors .Errorf ("incorrect number of arguments" )
239
+ }
240
+
241
+ ctx := reqcontext .ReqContext (cctx )
242
+ dep , err := deps .GetDepsCLI (ctx , cctx )
243
+ if err != nil {
244
+ return err
245
+ }
246
+
247
+ if cctx .IsSet ("file" ) {
248
+ // Read file line by line
249
+ fileStr := cctx .String ("file" )
250
+ loc , err := homedir .Expand (fileStr )
251
+ if err != nil {
252
+ return err
253
+ }
254
+ file , err := os .Open (loc )
255
+ if err != nil {
256
+ return err
257
+ }
258
+ defer file .Close ()
259
+ scanner := bufio .NewScanner (file )
260
+ for scanner .Scan () {
261
+ line := scanner .Text ()
262
+ // Extract pieceCid, pieceSize and MinerAddr from line
263
+ parts := strings .SplitN (line , "," , 4 )
264
+ if parts [0 ] == "" || parts [1 ] == "" || parts [2 ] == "" {
265
+ return fmt .Errorf ("empty column value in the input file at %s" , line )
266
+ }
267
+
268
+ uuid := parts [0 ]
269
+ size , err := strconv .ParseInt (parts [1 ], 10 , 64 )
270
+ if err != nil {
271
+ return fmt .Errorf ("failed to parse size %w" , err )
272
+ }
273
+
274
+ url := parts [2 ]
275
+
276
+ if parts [3 ] != "" {
277
+ header := http.Header {}
278
+ for _ , s := range strings .Split (parts [3 ], "," ) {
279
+ key , value , found := strings .Cut (s , ":" )
280
+ if ! found {
281
+ return fmt .Errorf ("invalid header format, expected key:value" )
282
+ }
283
+ header .Set (strings .TrimSpace (key ), strings .TrimSpace (value ))
284
+ }
285
+
286
+ hdr , err := json .Marshal (header )
287
+ if err != nil {
288
+ return xerrors .Errorf ("marshalling headers: %w" , err )
289
+ }
290
+ _ , err = dep .DB .Exec (ctx , `INSERT INTO market_offline_urls (
291
+ uuid,
292
+ url,
293
+ headers,
294
+ raw_size
295
+ ) VALUES ($1, $2, $3, $4);` ,
296
+ uuid , url , hdr , size )
297
+ if err != nil {
298
+ return xerrors .Errorf ("adding details to DB: %w" , err )
299
+ }
300
+ } else {
301
+ _ , err = dep .DB .Exec (ctx , `INSERT INTO market_offline_urls (
302
+ uuid,
303
+ url,
304
+ raw_size
305
+ ) VALUES ($1, $2, $3, $4);` ,
306
+ uuid , url , size )
307
+ if err != nil {
308
+ return xerrors .Errorf ("adding details to DB: %w" , err )
309
+ }
310
+ }
311
+
312
+ if err := scanner .Err (); err != nil {
313
+ return err
314
+ }
315
+ }
316
+ }
317
+
318
+ url := cctx .String ("url" )
319
+
320
+ headerValue := cctx .StringSlice ("header" )
321
+
322
+ uuid := cctx .Args ().First ()
323
+
324
+ sizeStr := cctx .Args ().Get (1 )
325
+ size , err := strconv .ParseInt (sizeStr , 10 , 64 )
326
+ if err != nil {
327
+ return xerrors .Errorf ("parsing size: %w" , err )
328
+ }
329
+
330
+ if cctx .IsSet ("header" ) {
331
+ // Split the header into key-value
332
+ header := http.Header {}
333
+ for _ , s := range headerValue {
334
+ key , value , found := strings .Cut (s , ":" )
335
+ if ! found {
336
+ return fmt .Errorf ("invalid header format, expected key:value" )
337
+ }
338
+ header .Set (strings .TrimSpace (key ), strings .TrimSpace (value ))
339
+ }
340
+
341
+ hdr , err := json .Marshal (header )
342
+ if err != nil {
343
+ return xerrors .Errorf ("marshalling headers: %w" , err )
344
+ }
345
+
346
+ _ , err = dep .DB .Exec (ctx , `INSERT INTO market_offline_urls (
347
+ uuid,
348
+ url,
349
+ headers,
350
+ raw_size
351
+ ) VALUES ($1, $2, $3, $4);` ,
352
+ uuid , url , hdr , size )
353
+ if err != nil {
354
+ return xerrors .Errorf ("adding details to DB: %w" , err )
355
+ }
356
+ } else {
357
+ _ , err = dep .DB .Exec (ctx , `INSERT INTO market_offline_urls (
358
+ uuid,
359
+ url,
360
+ raw_size
361
+ ) VALUES ($1, $2, $3, $4);` ,
362
+ uuid , url , size )
363
+ if err != nil {
364
+ return xerrors .Errorf ("adding details to DB: %w" , err )
365
+ }
366
+ }
367
+
368
+ return nil
369
+ },
370
+ }
0 commit comments