From 5fa8472e51ebd09dc693d5ed2492cbb767addce6 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Nov 2023 11:41:25 +0000 Subject: [PATCH 01/10] fix dmsgcurl readme and example files --- docs/dmsgcurl.md | 6 +++--- .../dmsg-example-http-server/dmsg-example-http-server.go | 0 examples/{dmsgget => dmsgcurl}/gen-keys/gen-keys.go | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename examples/{dmsgget => dmsgcurl}/dmsg-example-http-server/dmsg-example-http-server.go (100%) rename examples/{dmsgget => dmsgcurl}/gen-keys/gen-keys.go (100%) diff --git a/docs/dmsgcurl.md b/docs/dmsgcurl.md index 5176b4cd6..caca22565 100644 --- a/docs/dmsgcurl.md +++ b/docs/dmsgcurl.md @@ -41,17 +41,17 @@ $ mkdir /tmp/dmsghttp -p $ echo 'Hello World!' > /tmp/dmsghttp/hello.txt ``` -Next, let's serve this over `http` via `dmsg` as transport. We have an example exec for this located within `/example/dmsgget/dmsg-example-http-server`. +Next, let's serve this over `http` via `dmsg` as transport. We have an example exec for this located within `/example/dmsgcurl/dmsg-example-http-server`. ```shell script # Generate public/private key pair -$ go run ./examples/dmsgget/gen-keys/gen-keys.go +$ go run ./examples/dmsgcurl/gen-keys/gen-keys.go # PK: 038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851 # SK: e5740e093bd472c2730b0a58944a5dee220d415de62acf45d1c559f56eea2b2d # Run dmsg http server. # (replace 'e5740e093bd472c2730b0a58944a5dee220d415de62acf45d1c559f56eea2b2d' with the SK returned from above command) -$ go run ./examples/dmsgget/dmsg-example-http-server/dmsg-example-http-server.go --dir /tmp/dmsghttp --sk e5740e093bd472c2730b0a58944a5dee220d415de62acf45d1c559f56eea2b2d +$ go run ./examples/dmsgcurl/dmsg-example-http-server/dmsg-example-http-server.go --dir /tmp/dmsghttp --sk e5740e093bd472c2730b0a58944a5dee220d415de62acf45d1c559f56eea2b2d ``` Now we can use `dmsgcurl` to download the hosted file. Open a new terminal and run the following. diff --git a/examples/dmsgget/dmsg-example-http-server/dmsg-example-http-server.go b/examples/dmsgcurl/dmsg-example-http-server/dmsg-example-http-server.go similarity index 100% rename from examples/dmsgget/dmsg-example-http-server/dmsg-example-http-server.go rename to examples/dmsgcurl/dmsg-example-http-server/dmsg-example-http-server.go diff --git a/examples/dmsgget/gen-keys/gen-keys.go b/examples/dmsgcurl/gen-keys/gen-keys.go similarity index 100% rename from examples/dmsgget/gen-keys/gen-keys.go rename to examples/dmsgcurl/gen-keys/gen-keys.go From 0a564dead2637e1436460c59dc63c43bb228c95a Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Nov 2023 12:49:04 +0000 Subject: [PATCH 02/10] add flag --fullpath for get file from dmsg by dmsgcurl --- cmd/dmsgcurl/commands/dmsgcurl.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index 56780ab92..66ebf5cfa 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "io/fs" "log" "net/http" "net/url" @@ -42,6 +43,7 @@ var ( dmsgcurlWait int dmsgcurlOutput string stdout bool + fullpath bool ) func init() { @@ -51,6 +53,7 @@ func init() { RootCmd.Flags().StringVarP(&dmsgcurlData, "data", "d", "", "dmsghttp POST data") // RootCmd.Flags().StringVarP(&dmsgcurlHeader, "header", "H", "", "Pass custom header(s) to server") RootCmd.Flags().StringVarP(&dmsgcurlOutput, "out", "o", ".", "output filepath") + RootCmd.Flags().BoolVar(&fullpath, "fullpath", false, "download in fullpath or file name only") RootCmd.Flags().BoolVarP(&stdout, "stdout", "n", false, "output to STDOUT") RootCmd.Flags().IntVarP(&dmsgcurlTries, "try", "t", 1, "download attempts (0 unlimits)") RootCmd.Flags().IntVarP(&dmsgcurlWait, "wait", "w", 0, "time to wait between fetches") @@ -138,7 +141,7 @@ var RootCmd = &cobra.Command{ fmt.Println(string(respBody)) } else { - file, err := parseOutputFile(dmsgcurlOutput, u.URL.Path) + file, err := parseOutputFile(dmsgcurlOutput, u.URL.Path, fullpath) if err != nil { return fmt.Errorf("failed to prepare output file: %w", err) } @@ -243,7 +246,7 @@ func parseURL(args []string) (*URL, error) { return &out, nil } -func parseOutputFile(name string, urlPath string) (*os.File, error) { +func parseOutputFile(name string, urlPath string, fullpath bool) (*os.File, error) { stat, statErr := os.Stat(name) if statErr != nil { if os.IsNotExist(statErr) { @@ -256,8 +259,15 @@ func parseOutputFile(name string, urlPath string) (*os.File, error) { return nil, statErr } + urlSlice := strings.Split(urlPath, "/") + fileName := urlSlice[len(urlSlice)-1] + if stat.IsDir() { - f, err := os.Create(filepath.Join(name, urlPath)) //nolint + if fullpath { + os.Mkdir(strings.Replace(urlPath, fileName, "", 1)[1:], fs.ModePerm) //nolint + fileName = urlPath + } + f, err := os.Create(filepath.Join(name, fileName)) //nolint if err != nil { return nil, err } From 5980da258513380baed0f3c5bf6d826ab59261dd Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Nov 2023 12:57:33 +0000 Subject: [PATCH 03/10] update dmsgcurl readme --- docs/dmsgcurl.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/dmsgcurl.md b/docs/dmsgcurl.md index caca22565..186d0f186 100644 --- a/docs/dmsgcurl.md +++ b/docs/dmsgcurl.md @@ -35,10 +35,11 @@ First, lets create a folder where we will host files to serve over `dmsg` and cr ```shell script // Create serving folder. -$ mkdir /tmp/dmsghttp -p +$ mkdir /tmp/dmsghttp/inner -p -// Create file. +// Create files. $ echo 'Hello World!' > /tmp/dmsghttp/hello.txt +$ echo 'Hello World!, Inner!' > /tmp/dmsghttp/inner/inner-hello.txt ``` Next, let's serve this over `http` via `dmsg` as transport. We have an example exec for this located within `/example/dmsgcurl/dmsg-example-http-server`. @@ -59,10 +60,16 @@ Now we can use `dmsgcurl` to download the hosted file. Open a new terminal and r ```shell script # Replace '038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851' with the generated PK. $ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/hello.txt +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt --fullpath +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt # Check downloaded file. $ cat hello.txt # Hello World! +$ cat inner/inner-hello.txt +# Hello World!, Inner! +$ cat inner-hello.txt +# Hello World!, Inner! ``` Note: If you set `-d` or `--data` flag, then curl work as post method (upload), and if not then work as get method (download). From ff0d91fda9297b850ffacb42c428dc03f8f67a61 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sat, 9 Dec 2023 22:43:35 +0000 Subject: [PATCH 04/10] set loglvl to panic if we use stdout flag --- cmd/dmsgcurl/commands/dmsgcurl.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index 66ebf5cfa..6152a1df8 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -91,6 +91,9 @@ var RootCmd = &cobra.Command{ if dmsgcurlLog == nil { dmsgcurlLog = logging.MustGetLogger("dmsgcurl") } + if stdout { + logLvl = "panic" + } if logLvl != "" { if lvl, err := logging.LevelFromString(logLvl); err == nil { logging.SetLevel(lvl) From d79b931557e4cc596cc7001975cc600fae0fe8e7 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sat, 9 Dec 2023 22:46:35 +0000 Subject: [PATCH 05/10] change panic to fatal, because of more useale --- cmd/dmsgcurl/commands/dmsgcurl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index 6152a1df8..587f14971 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -92,7 +92,7 @@ var RootCmd = &cobra.Command{ dmsgcurlLog = logging.MustGetLogger("dmsgcurl") } if stdout { - logLvl = "panic" + logLvl = "fatal" } if logLvl != "" { if lvl, err := logging.LevelFromString(logLvl); err == nil { From daf6c520fca234f2803adbe7c2163d98870c1fed Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sat, 9 Dec 2023 23:12:04 +0000 Subject: [PATCH 06/10] improve dmsgcurl get logic, so never use file for stdout --- cmd/dmsgcurl/commands/dmsgcurl.go | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index 587f14971..d38210541 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -143,8 +143,10 @@ var RootCmd = &cobra.Command{ } fmt.Println(string(respBody)) } else { - - file, err := parseOutputFile(dmsgcurlOutput, u.URL.Path, fullpath) + file := os.Stdout + if !stdout { + file, err = parseOutputFile(dmsgcurlOutput, u.URL.Path, fullpath) + } if err != nil { return fmt.Errorf("failed to prepare output file: %w", err) } @@ -170,21 +172,9 @@ var RootCmd = &cobra.Command{ for i := 0; i < dmsgcurlTries; i++ { if !stdout { dmsgcurlLog.Debugf("Download attempt %d/%d ...", i, dmsgcurlTries) - } - - if _, err := file.Seek(0, 0); err != nil { - return fmt.Errorf("failed to reset file: %w", err) - } - if stdout { - if fErr := file.Close(); fErr != nil { - dmsgcurlLog.WithError(fErr).Warn("Failed to close output file.") - } - if err != nil { - if rErr := os.RemoveAll(file.Name()); rErr != nil { - dmsgcurlLog.WithError(rErr).Warn("Failed to remove output file.") - } + if _, err := file.Seek(0, 0); err != nil { + return fmt.Errorf("failed to reset file: %w", err) } - file = os.Stdout } if err := Download(ctx, dmsgcurlLog, &httpC, file, u.URL.String(), 0); err != nil { dmsgcurlLog.WithError(err).Error() From b7407b3415b9e302c03d2fb0d2090dcafde3505a Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sat, 9 Dec 2023 23:53:48 +0000 Subject: [PATCH 07/10] initial commit for changes dmsgcurl logic on get stdout as default --- cmd/dmsgcurl/commands/dmsgcurl.go | 35 +++++++++++-------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index d38210541..de49bca34 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -11,7 +11,6 @@ import ( "net/http" "net/url" "os" - "path/filepath" "strings" "sync/atomic" "time" @@ -42,19 +41,15 @@ var ( dmsgcurlTries int dmsgcurlWait int dmsgcurlOutput string - stdout bool - fullpath bool ) func init() { RootCmd.Flags().StringVarP(&dmsgDisc, "dmsg-disc", "c", "", "dmsg discovery url default:\n"+skyenv.DmsgDiscAddr) RootCmd.Flags().IntVarP(&dmsgSessions, "sess", "e", 1, "number of dmsg servers to connect to") - RootCmd.Flags().StringVarP(&logLvl, "loglvl", "l", "", "[ debug | warn | error | fatal | panic | trace | info ]\033[0m") + RootCmd.Flags().StringVarP(&logLvl, "loglvl", "l", "fatal", "[ debug | warn | error | fatal | panic | trace | info ]\033[0m") RootCmd.Flags().StringVarP(&dmsgcurlData, "data", "d", "", "dmsghttp POST data") // RootCmd.Flags().StringVarP(&dmsgcurlHeader, "header", "H", "", "Pass custom header(s) to server") - RootCmd.Flags().StringVarP(&dmsgcurlOutput, "out", "o", ".", "output filepath") - RootCmd.Flags().BoolVar(&fullpath, "fullpath", false, "download in fullpath or file name only") - RootCmd.Flags().BoolVarP(&stdout, "stdout", "n", false, "output to STDOUT") + RootCmd.Flags().StringVarP(&dmsgcurlOutput, "out", "o", "", "output filepath") RootCmd.Flags().IntVarP(&dmsgcurlTries, "try", "t", 1, "download attempts (0 unlimits)") RootCmd.Flags().IntVarP(&dmsgcurlWait, "wait", "w", 0, "time to wait between fetches") RootCmd.Flags().StringVarP(&dmsgcurlAgent, "agent", "a", "dmsgcurl/"+buildinfo.Version(), "identify as `AGENT`") @@ -91,9 +86,6 @@ var RootCmd = &cobra.Command{ if dmsgcurlLog == nil { dmsgcurlLog = logging.MustGetLogger("dmsgcurl") } - if stdout { - logLvl = "fatal" - } if logLvl != "" { if lvl, err := logging.LevelFromString(logLvl); err == nil { logging.SetLevel(lvl) @@ -144,8 +136,8 @@ var RootCmd = &cobra.Command{ fmt.Println(string(respBody)) } else { file := os.Stdout - if !stdout { - file, err = parseOutputFile(dmsgcurlOutput, u.URL.Path, fullpath) + if dmsgcurlOutput != "" { + file, err = parseOutputFile(dmsgcurlOutput) } if err != nil { return fmt.Errorf("failed to prepare output file: %w", err) @@ -170,7 +162,7 @@ var RootCmd = &cobra.Command{ httpC := http.Client{Transport: dmsghttp.MakeHTTPTransport(ctx, dmsgC)} for i := 0; i < dmsgcurlTries; i++ { - if !stdout { + if dmsgcurlOutput != "" { dmsgcurlLog.Debugf("Download attempt %d/%d ...", i, dmsgcurlTries) if _, err := file.Seek(0, 0); err != nil { return fmt.Errorf("failed to reset file: %w", err) @@ -239,11 +231,11 @@ func parseURL(args []string) (*URL, error) { return &out, nil } -func parseOutputFile(name string, urlPath string, fullpath bool) (*os.File, error) { - stat, statErr := os.Stat(name) +func parseOutputFile(output string) (*os.File, error) { + stat, statErr := os.Stat(output) if statErr != nil { if os.IsNotExist(statErr) { - f, err := os.Create(name) //nolint + f, err := os.Create(output) //nolint if err != nil { return nil, err } @@ -252,15 +244,12 @@ func parseOutputFile(name string, urlPath string, fullpath bool) (*os.File, erro return nil, statErr } - urlSlice := strings.Split(urlPath, "/") + urlSlice := strings.Split(output, "/") fileName := urlSlice[len(urlSlice)-1] if stat.IsDir() { - if fullpath { - os.Mkdir(strings.Replace(urlPath, fileName, "", 1)[1:], fs.ModePerm) //nolint - fileName = urlPath - } - f, err := os.Create(filepath.Join(name, fileName)) //nolint + os.Mkdir(strings.Replace(output, fileName, "", 1)[1:], fs.ModePerm) //nolint + f, err := os.Create(output) //nolint if err != nil { return nil, err } @@ -360,7 +349,7 @@ func (pw *ProgressWriter) Write(p []byte) (int, error) { current := atomic.AddInt64(&pw.Current, int64(n)) total := atomic.LoadInt64(&pw.Total) pc := fmt.Sprintf("%d%%", current*100/total) - if !stdout { + if dmsgcurlOutput != "" { fmt.Printf("Downloading: %d/%dB (%s)", current, total, pc) if current != total { fmt.Print("\r") From e2adde37b182aabfb4f815b441a565153d5a3aa9 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sun, 10 Dec 2023 03:55:13 +0330 Subject: [PATCH 08/10] improve download file logic --- cmd/dmsgcurl/commands/dmsgcurl.go | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/cmd/dmsgcurl/commands/dmsgcurl.go b/cmd/dmsgcurl/commands/dmsgcurl.go index de49bca34..e9ddafff3 100644 --- a/cmd/dmsgcurl/commands/dmsgcurl.go +++ b/cmd/dmsgcurl/commands/dmsgcurl.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "os" + "path/filepath" "strings" "sync/atomic" "time" @@ -41,6 +42,7 @@ var ( dmsgcurlTries int dmsgcurlWait int dmsgcurlOutput string + replace bool ) func init() { @@ -50,6 +52,7 @@ func init() { RootCmd.Flags().StringVarP(&dmsgcurlData, "data", "d", "", "dmsghttp POST data") // RootCmd.Flags().StringVarP(&dmsgcurlHeader, "header", "H", "", "Pass custom header(s) to server") RootCmd.Flags().StringVarP(&dmsgcurlOutput, "out", "o", "", "output filepath") + RootCmd.Flags().BoolVarP(&replace, "replace", "r", false, "replace exist file with new downloaded") RootCmd.Flags().IntVarP(&dmsgcurlTries, "try", "t", 1, "download attempts (0 unlimits)") RootCmd.Flags().IntVarP(&dmsgcurlWait, "wait", "w", 0, "time to wait between fetches") RootCmd.Flags().StringVarP(&dmsgcurlAgent, "agent", "a", "dmsgcurl/"+buildinfo.Version(), "identify as `AGENT`") @@ -137,7 +140,7 @@ var RootCmd = &cobra.Command{ } else { file := os.Stdout if dmsgcurlOutput != "" { - file, err = parseOutputFile(dmsgcurlOutput) + file, err = parseOutputFile(dmsgcurlOutput, replace) } if err != nil { return fmt.Errorf("failed to prepare output file: %w", err) @@ -231,10 +234,13 @@ func parseURL(args []string) (*URL, error) { return &out, nil } -func parseOutputFile(output string) (*os.File, error) { - stat, statErr := os.Stat(output) +func parseOutputFile(output string, replace bool) (*os.File, error) { + _, statErr := os.Stat(output) if statErr != nil { if os.IsNotExist(statErr) { + if err := os.MkdirAll(filepath.Dir(output), fs.ModePerm); err != nil { + return nil, err + } f, err := os.Create(output) //nolint if err != nil { return nil, err @@ -243,19 +249,9 @@ func parseOutputFile(output string) (*os.File, error) { } return nil, statErr } - - urlSlice := strings.Split(output, "/") - fileName := urlSlice[len(urlSlice)-1] - - if stat.IsDir() { - os.Mkdir(strings.Replace(output, fileName, "", 1)[1:], fs.ModePerm) //nolint - f, err := os.Create(output) //nolint - if err != nil { - return nil, err - } - return f, nil + if replace { + return os.OpenFile(filepath.Clean(output), os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.ModePerm) } - return nil, os.ErrExist } From e05e89838a8452d649bfe787675285ff0788ccef Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sun, 10 Dec 2023 03:59:44 +0330 Subject: [PATCH 09/10] update dmsgcurl docs --- docs/dmsgcurl.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/dmsgcurl.md b/docs/dmsgcurl.md index 186d0f186..93351eb0f 100644 --- a/docs/dmsgcurl.md +++ b/docs/dmsgcurl.md @@ -59,14 +59,13 @@ Now we can use `dmsgcurl` to download the hosted file. Open a new terminal and r ```shell script # Replace '038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851' with the generated PK. -$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/hello.txt -$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt --fullpath -$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/hello.txt # Output be here as stdout +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/hello.txt -o downloadedFile/hello.txt +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt # Output be here as stdout +$ dmsgcurl dmsg://038dde2d050803db59e2ad19e5a6db0f58f8419709fc65041c48b0cb209bb7a851:80/inner/inner-hello.txt -o inner-hello.txt # Check downloaded file. -$ cat hello.txt -# Hello World! -$ cat inner/inner-hello.txt +$ cat downloadedFile/hello.txt # Hello World!, Inner! $ cat inner-hello.txt # Hello World!, Inner! From d70f1e3b5be070b1f44ad46526a10fb37b0342e4 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Sun, 10 Dec 2023 04:00:56 +0330 Subject: [PATCH 10/10] update dmsgcurl docs 2 --- docs/dmsgcurl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dmsgcurl.md b/docs/dmsgcurl.md index 93351eb0f..099273b09 100644 --- a/docs/dmsgcurl.md +++ b/docs/dmsgcurl.md @@ -17,11 +17,11 @@ $ dmsgcurl --help -c, --dmsg-disc string dmsg discovery url default: http://dmsgd.skywire.skycoin.com -l, --loglvl string [ debug | warn | error | fatal | panic | trace | info ] - -o, --out string output filepath (default ".") + -o, --out string output filepath + -r, --replace bool if be true then downloaded exist file will replace by new downloaded -e, --sess int number of dmsg servers to connect to (default 1) -s, --sk cipher.SecKey a random key is generated if unspecified (default 0000000000000000000000000000000000000000000000000000000000000000) - -n, --stdout output to STDOUT -t, --try int download attempts (0 unlimits) (default 1) -v, --version version for dmsgcurl -w, --wait int time to wait between fetches