-
Notifications
You must be signed in to change notification settings - Fork 0
/
steady.go
133 lines (114 loc) · 2.77 KB
/
steady.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
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)
type RemoteFiles struct {
Files []RemoteFile `json:"files"`
}
type RemoteFile struct {
Url string `json:"url"`
Type string `json:"type"`
}
const (
outputDir = "public"
steadyFilesPath = "/steady-files"
numWorkers = 5
)
func main() {
// Get base URL
if len(os.Args) < 2 {
log.Fatal(errors.New("`steady` must be called passing the base URL of the site to convert"))
}
baseUrl := os.Args[1]
// Load steady files
resp, err := http.Get(baseUrl + steadyFilesPath)
if err != nil {
log.Fatal(err)
}
steadyFileBytes, err := ioutil.ReadAll(resp.Body)
// Unmarshal Files
var remoteFiles RemoteFiles
err = json.Unmarshal(steadyFileBytes, &remoteFiles)
if err != nil {
log.Fatal(err)
}
// Download the files
err = downloadFiles(&remoteFiles, baseUrl)
if err != nil {
log.Fatal(err)
}
}
// downloadFiles downloads all remote files from the specified remote
func downloadFiles(remoteFiles *RemoteFiles, baseUrl string) error {
// Create channels
numJobs := len(remoteFiles.Files)
jobs := make(chan RemoteFile, numJobs)
results := make(chan error, numJobs)
// Spin up some workers
for workerId := 0; workerId < numWorkers; workerId++ {
go downloadFilesWorker(baseUrl, jobs, results)
}
// Create the jobs
for _, remoteFile := range remoteFiles.Files {
jobs <- remoteFile
}
close(jobs)
// Block until we get all results
for result := 0; result < numJobs; result++ {
err := <-results
if err != nil {
return err
}
}
// OK
return nil
}
// downloadFilesWorker is a single worker that will call downloadFile on a job
func downloadFilesWorker(baseUrl string, jobs <-chan RemoteFile, results chan<- error) {
for remoteFile := range jobs {
results <- downloadFile(&remoteFile, baseUrl)
}
}
// downloadFile downloads a single remote file
func downloadFile(remoteFile *RemoteFile, baseUrl string) error {
// Download
downloadUrl := baseUrl + remoteFile.Url
fmt.Println("======> Downloading " + downloadUrl)
resp, err := http.Get(downloadUrl)
if err != nil {
return err
}
// Get local file URL
localFileUrl := remoteFile.Url
if remoteFile.Type != "" {
localFileUrl += "." + remoteFile.Type
}
localFileUrl = outputDir + localFileUrl
// Ensure all directories are made
fileSegmentArray := strings.Split(localFileUrl, "/")
dirPath := ""
for _, segment := range fileSegmentArray[0 : len(fileSegmentArray)-1] {
dirPath += segment + string(filepath.Separator)
}
err = os.MkdirAll(dirPath, 0755)
if err != nil {
return err
}
// Create local file
localFile, err := os.Create(localFileUrl)
if err != nil {
return err
}
// Write the response body to the file
_, err = io.Copy(localFile, resp.Body)
return err
}