@@ -4,9 +4,11 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"io"
7
+ "io/ioutil"
7
8
"net/http"
8
9
"os"
9
10
"path"
11
+ "path/filepath"
10
12
11
13
"golang.org/x/sync/errgroup"
12
14
)
@@ -36,7 +38,19 @@ func Run(option Option) {
36
38
37
39
option .divide ()
38
40
39
- err = option .parallelDownload ()
41
+ tmpDir , err := ioutil .TempDir ("" , "rget" )
42
+ if err != nil {
43
+ fmt .Errorf ("%s" , err )
44
+ }
45
+ defer os .RemoveAll (tmpDir )
46
+ fmt .Println (tmpDir )
47
+
48
+ err = option .parallelDownload (tmpDir )
49
+ if err != nil {
50
+ fmt .Errorf ("%s" , err )
51
+ }
52
+
53
+ err = option .combine (tmpDir )
40
54
if err != nil {
41
55
fmt .Errorf ("%s" , err )
42
56
}
@@ -47,27 +61,19 @@ func (o *Option) contentLength() error {
47
61
//resp, err := http.Head(url)
48
62
resp , err := http .Head (o .URL )
49
63
if err != nil {
50
- fmt .Fprintln (os .Stderr , err )
51
- //return 0, err
52
64
return err
53
65
}
54
66
55
67
if resp .Header .Get ("Accept-Ranges" ) == "" {
56
68
err := fmt .Errorf ("%s URL cannot support Ranges Requests" , o .URL )
57
- // fmt.Fprintln(os.Stderr, err)
58
- //return resp.ContentLength, err
59
69
return err
60
70
}
61
71
if resp .Header ["Accept-Ranges" ][0 ] == "none" {
62
72
err := fmt .Errorf ("%s cannot support Ranges Requests" , o .URL )
63
- // fmt.Fprintln(os.Stderr, err)
64
- //return resp.ContentLength, err
65
73
return err
66
74
}
67
75
if resp .ContentLength == 0 {
68
76
err := fmt .Errorf ("%s size is %s" , o .URL , resp .Header ["Content-Length" ][0 ])
69
- // fmt.Fprintln(os.Stderr, err)
70
- //return resp.ContentLength, err
71
77
return err
72
78
}
73
79
@@ -80,10 +86,9 @@ func (o *Option) contentLength() error {
80
86
func (o * Option ) divide () {
81
87
var units []Unit
82
88
83
- //sbyte := contentLength / int64(concurrency )
89
+ //TODO: if o.ContentLength < int64(o.Concurrency )
84
90
sbyte := o .ContentLength / int64 (o .Concurrency )
85
91
86
- // for i := 0; i < concurrency; i++ {
87
92
for i := 0 ; i < o .Concurrency ; i ++ {
88
93
units = append (units , Unit {
89
94
RangeStart : int64 (i ) * sbyte ,
@@ -92,16 +97,13 @@ func (o *Option) divide() {
92
97
})
93
98
}
94
99
100
+ // TODO: should distribute the remainder to each unit
101
+ units [len (units )- 1 ].RangeEnd = o .ContentLength
102
+
95
103
o .Units = units
96
- //return units
97
104
}
98
105
99
- // func download(units Units) {
100
- // filepath.Split()
101
- // fmt.Println(units)
102
- // }
103
-
104
- func (o * Option ) parallelDownload () error {
106
+ func (o * Option ) parallelDownload (tmpDir string ) error {
105
107
fmt .Println ("parallelDownload" , o .Units )
106
108
107
109
eg , ctx := errgroup .WithContext (context .Background ())
@@ -110,19 +112,22 @@ func (o *Option) parallelDownload() error {
110
112
// https://golang.org/doc/faq#closures_and_goroutines
111
113
i := i
112
114
eg .Go (func () error {
113
- return o .downloadWithContext (ctx , i )
115
+ return o .downloadWithContext (ctx , i , tmpDir )
114
116
})
115
117
}
116
118
117
119
if err := eg .Wait (); err != nil {
118
- o .clearCache ()
119
120
return err
120
121
}
121
122
122
123
return nil
123
124
}
124
125
125
- func (o * Option ) downloadWithContext (ctx context.Context , i int ) error {
126
+ func (o * Option ) downloadWithContext (
127
+ ctx context.Context ,
128
+ i int ,
129
+ dir string ,
130
+ ) error {
126
131
ctx , cancel := context .WithCancel (ctx )
127
132
defer cancel ()
128
133
@@ -135,26 +140,26 @@ func (o *Option) downloadWithContext(ctx context.Context, i int) error {
135
140
}
136
141
137
142
// add range header
138
- fmt .Printf (fmt .Sprintf ("bytes=%d-%d" , o .Units [i ].RangeStart , o .Units [i ].RangeEnd ))
143
+ fmt .Printf (fmt .Sprintf ("bytes=%d-%d\n " , o .Units [i ].RangeStart , o .Units [i ].RangeEnd ))
139
144
req .Header .Set ("Range" , fmt .Sprintf ("bytes=%d-%d" , o .Units [i ].RangeStart , o .Units [i ].RangeEnd ))
140
145
141
- client := & http.Client {}
146
+ client := http .DefaultClient
142
147
resp , err := client .Do (req )
143
- defer resp .Body .Close ()
144
148
if err != nil {
149
+ fmt .Printf ("client err: %s" , err )
145
150
return fmt .Errorf ("Error: %v" , err )
146
151
}
152
+ defer resp .Body .Close ()
147
153
148
154
select {
149
155
case <- ctx .Done ():
150
156
fmt .Printf ("Done: %v %+v\n " , i , o .Units [i ])
151
157
return nil
152
158
default :
153
159
fmt .Println ("default:" , i , o .Units [i ])
154
- //return fmt.Errorf("Error: %v %+v", i, o.Units[i])
155
160
}
156
161
157
- w , err := os .Create (o .Units [i ].TempFileName )
162
+ w , err := os .Create (filepath . Join ( dir , o .Units [i ].TempFileName ) )
158
163
if err != nil {
159
164
return fmt .Errorf ("Error: %v" , err )
160
165
}
@@ -173,11 +178,29 @@ func (o *Option) downloadWithContext(ctx context.Context, i int) error {
173
178
return nil
174
179
}
175
180
176
- func (o * Option ) conbine () error {
177
- return nil
178
- }
181
+ func (o * Option ) combine (dir string ) error {
182
+ w , err := os .Create (path .Base (o .URL ))
183
+ if err != nil {
184
+ return fmt .Errorf ("Error: %v" , err )
185
+ }
186
+ defer func () error {
187
+ if err := w .Close (); err != nil {
188
+ return fmt .Errorf ("Error: %v" , err )
189
+ }
190
+ return nil
191
+ }()
192
+
193
+ for _ , unit := range o .Units {
194
+ r , err := os .Open (filepath .Join (dir , unit .TempFileName ))
195
+ if err != nil {
196
+ return fmt .Errorf ("Error: %v" , err )
197
+ }
198
+
199
+ _ , err = io .Copy (w , r )
200
+ if err != nil {
201
+ return fmt .Errorf ("Error: %v" , err )
202
+ }
203
+ }
179
204
180
- func (o * Option ) clearCache () error {
181
- //TODO: remove temporary files
182
205
return nil
183
206
}
0 commit comments