-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathmain.go
139 lines (123 loc) · 2.9 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"flag"
"os"
"os/signal"
"path/filepath"
"runtime"
"syscall"
)
var displayProgress = true
func main() {
var err error
conn := flag.Int("n", runtime.NumCPU(), "connection")
skiptls := flag.Bool("skip-tls", true, "skip verify certificate for https")
flag.Parse()
args := flag.Args()
if len(args) < 1 {
Errorln("url is required")
usage()
os.Exit(1)
}
command := args[0]
if command == "tasks" {
if err = TaskPrint(); err != nil {
Errorf("%v\n", err)
}
return
} else if command == "resume" {
if len(args) < 2 {
Errorln("downloading task name is required")
usage()
os.Exit(1)
}
var task string
if IsUrl(args[1]) {
task = TaskFromUrl(args[1])
} else {
task = args[1]
}
state, err := Resume(task)
FatalCheck(err)
Execute(state.Url, state, *conn, *skiptls)
return
} else {
if ExistDir(FolderOf(command)) {
Warnf("Downloading task already exist, remove first \n")
err := os.RemoveAll(FolderOf(command))
FatalCheck(err)
}
Execute(command, nil, *conn, *skiptls)
}
}
func Execute(url string, state *State, conn int, skiptls bool) {
//otherwise is hget <URL> command
var err error
signal_chan := make(chan os.Signal, 1)
signal.Notify(signal_chan,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
//set up parallel
var files = make([]string, 0)
var parts = make([]Part, 0)
var isInterrupted = false
doneChan := make(chan bool, conn)
fileChan := make(chan string, conn)
errorChan := make(chan error, 1)
stateChan := make(chan Part, 1)
interruptChan := make(chan bool, conn)
var downloader *HttpDownloader
if state == nil {
downloader = NewHttpDownloader(url, conn, skiptls)
} else {
downloader = &HttpDownloader{url: state.Url, file: filepath.Base(state.Url), par: int64(len(state.Parts)), parts: state.Parts, resumable: true}
}
go downloader.Do(doneChan, fileChan, errorChan, interruptChan, stateChan)
for {
select {
case <-signal_chan:
//send par number of interrupt for each routine
isInterrupted = true
for i := 0; i < conn; i++ {
interruptChan <- true
}
case file := <-fileChan:
files = append(files, file)
case err := <-errorChan:
Errorf("%v", err)
panic(err) //maybe need better style
case part := <-stateChan:
parts = append(parts, part)
case <-doneChan:
if isInterrupted {
if downloader.resumable {
Printf("Interrupted, saving state ... \n")
s := &State{Url: url, Parts: parts}
err := s.Save()
if err != nil {
Errorf("%v\n", err)
}
return
} else {
Warnf("Interrupted, but downloading url is not resumable, silently die")
return
}
} else {
err = JoinFile(files, filepath.Base(url))
FatalCheck(err)
err = os.RemoveAll(FolderOf(url))
FatalCheck(err)
return
}
}
}
}
func usage() {
Printf(`Usage:
hget [URL] [-n connection] [-skip-tls true]
hget tasks
hget resume [TaskName]
`)
}