Skip to content

Commit ac160ef

Browse files
authored
feat: suppor to download magnet files (#325)
1 parent c9ab375 commit ac160ef

File tree

11 files changed

+152
-19
lines changed

11 files changed

+152
-19
lines changed

cmd/fetch.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"github.com/linuxsuren/http-downloader/pkg"
77
"os"
8+
"strings"
9+
"time"
810

911
"github.com/linuxsuren/http-downloader/pkg/installer"
1012
"github.com/spf13/cobra"
@@ -27,15 +29,23 @@ func newFetchCmd(context.Context) (cmd *cobra.Command) {
2729
"The branch of git repository (not support currently)")
2830
flags.BoolVarP(&opt.reset, "reset", "", false,
2931
"If you want to reset the hd-config which means delete and clone it again")
32+
flags.IntVarP(&opt.retry, "retry", "", 6, "Retry times due to timeout error")
33+
flags.DurationVarP(&opt.timeout, "timeout", "", time.Second*10, "Timeout of fetching")
3034

3135
_ = cmd.RegisterFlagCompletionFunc("provider", ArrayCompletion(ProviderGitHub, ProviderGitee))
3236
return
3337
}
3438

35-
func (o *fetchOption) preRunE(c *cobra.Command, _ []string) (err error) {
39+
func (o *fetchOption) setTimeout(c *cobra.Command) {
3640
if c.Context() != nil {
37-
o.fetcher.SetContext(c.Context())
41+
var ctx context.Context
42+
ctx, o.cancel = context.WithTimeout(c.Context(), o.timeout)
43+
o.fetcher.SetContext(ctx)
3844
}
45+
}
46+
47+
func (o *fetchOption) preRunE(c *cobra.Command, _ []string) (err error) {
48+
o.setTimeout(c)
3949
if o.reset {
4050
var configDir string
4151
if configDir, err = o.fetcher.GetConfigDir(); err == nil {
@@ -48,8 +58,21 @@ func (o *fetchOption) preRunE(c *cobra.Command, _ []string) (err error) {
4858
return
4959
}
5060

51-
func (o *fetchOption) runE(cmd *cobra.Command, _ []string) (err error) {
52-
return o.fetcher.FetchLatestRepo(o.Provider, o.branch, cmd.OutOrStdout())
61+
func (o *fetchOption) runE(c *cobra.Command, _ []string) (err error) {
62+
var i int
63+
for i = 0; i < o.retry; i++ {
64+
err = o.fetcher.FetchLatestRepo(o.Provider, o.branch, c.OutOrStdout())
65+
if err == nil || (!strings.Contains(err.Error(), "context deadline exceeded") &&
66+
!strings.Contains(err.Error(), "i/o timeout")) {
67+
break
68+
}
69+
o.setTimeout(c)
70+
c.Print(".")
71+
}
72+
if i >= 1 {
73+
c.Println()
74+
}
75+
return
5376
}
5477

5578
type fetchOption struct {
@@ -58,4 +81,7 @@ type fetchOption struct {
5881
branch string
5982
reset bool
6083
fetcher installer.Fetcher
84+
cancel context.CancelFunc
85+
retry int
86+
timeout time.Duration
6187
}

cmd/get.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"github.com/linuxsuren/http-downloader/pkg/exec"
78
"net/http"
89
"net/url"
910
sysos "os"
@@ -126,7 +127,7 @@ func (o *downloadOption) fetch() (err error) {
126127
go func() {
127128
// no need to handle the error due to this is a background task
128129
if o.fetcher != nil {
129-
err = o.fetcher.FetchLatestRepo(o.Provider, installer.ConfigBranch, bytes.NewBuffer(nil))
130+
err = o.fetcher.FetchLatestRepo(o.Provider, installer.ConfigBranch, bytes.NewBuffer([]byte{}))
130131
}
131132
o.wait.Done()
132133
}()
@@ -169,7 +170,11 @@ func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error)
169170

170171
targetURL := args[0]
171172
o.Package = &installer.HDConfig{}
172-
if !strings.HasPrefix(targetURL, "http://") && !strings.HasPrefix(targetURL, "https://") {
173+
if strings.HasPrefix(targetURL, "magnet:?") {
174+
// download via external tool
175+
o.URL = targetURL
176+
return
177+
} else if !strings.HasPrefix(targetURL, "http://") && !strings.HasPrefix(targetURL, "https://") {
173178
ins := &installer.Installer{
174179
Provider: o.Provider,
175180
OS: o.OS,
@@ -188,10 +193,6 @@ func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error)
188193
}
189194
o.URL = targetURL
190195

191-
if o.ProxyGitHub != "" {
192-
o.URL = strings.Replace(o.URL, "github.com", fmt.Sprintf("%s/github.com", o.ProxyGitHub), 1)
193-
}
194-
195196
if o.Output == "" {
196197
var urlObj *url.URL
197198
if urlObj, err = url.Parse(o.URL); err == nil {
@@ -246,6 +247,11 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) {
246247
return
247248
}
248249

250+
if strings.HasPrefix(o.URL, "magnet:?") {
251+
err = downloadMagnetFile(o.ProxyGitHub, o.URL)
252+
return
253+
}
254+
249255
cmd.Printf("start to download from %s\n", o.URL)
250256
if o.Thread <= 1 {
251257
downloader := &net.ContinueDownloader{}
@@ -262,3 +268,26 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) {
262268
}
263269
return
264270
}
271+
272+
func downloadMagnetFile(proxyGitHub, target string) (err error) {
273+
targetCmd := "gotorrent"
274+
execer := exec.DefaultExecer{}
275+
is := installer.Installer{
276+
Provider: "github",
277+
Execer: execer,
278+
ProxyGitHub: proxyGitHub,
279+
}
280+
if err = is.CheckDepAndInstall(map[string]string{
281+
targetCmd: "linuxsuren/gotorrent",
282+
}); err != nil {
283+
return
284+
}
285+
286+
var targetBinary string
287+
if targetBinary, err = execer.LookPath(targetCmd); err == nil {
288+
sysCallArgs := []string{targetCmd}
289+
sysCallArgs = append(sysCallArgs, []string{"download", target}...)
290+
err = execer.SystemCall(targetBinary, sysCallArgs, sysos.Environ())
291+
}
292+
return
293+
}

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ require (
4949
github.com/nxadm/tail v1.4.8 // indirect
5050
github.com/pelletier/go-toml v1.9.4 // indirect
5151
github.com/pmezard/go-difflib v1.0.0 // indirect
52+
github.com/prometheus/client_golang v1.11.1 // indirect
5253
github.com/sergi/go-diff v1.1.0 // indirect
5354
github.com/spf13/afero v1.6.0 // indirect
5455
github.com/spf13/cast v1.4.1 // indirect
@@ -58,9 +59,9 @@ require (
5859
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
5960
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
6061
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
61-
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
62+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
6263
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
63-
golang.org/x/text v0.3.7 // indirect
64+
golang.org/x/text v0.3.8 // indirect
6465
google.golang.org/appengine v1.6.7 // indirect
6566
google.golang.org/protobuf v1.27.1 // indirect
6667
gopkg.in/ini.v1 v1.63.2 // indirect

0 commit comments

Comments
 (0)