-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
144 lines (127 loc) · 3.63 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
140
141
142
143
144
package main
import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/dadosjusbr/storage"
"github.com/kelseyhightower/envconfig"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
mgoConnTimeout = 60 * time.Second
)
// O tipo decInt é necessário pois a biblioteca converte usando ParseInt passando
// zero na base. Ou seja, meses como 08 passam a ser inválidos pois são tratados
// como números octais.
type decInt int
func (i *decInt) Decode(value string) error {
v, err := strconv.Atoi(value)
*i = decInt(v)
return err
}
type config struct {
Month decInt `envconfig:"MONTH"`
Year decInt `envconfig:"YEAR"`
AID string `envconfig:"AID"`
// Backup URL store
MongoURI string `envconfig:"MONGODB_URI" required:"true"`
MongoDBName string `envconfig:"MONGODB_DBNAME" required:"true"`
MongoBackupColl string `envconfig:"MONGODB_BCOLL" required:"true"`
OutDir string `envconfig:"OUTPUT_FOLDER" required:"true"`
}
func main() {
// parsing environment variables.
var conf config
if err := envconfig.Process("", &conf); err != nil {
log.Fatalf("Error loading config values from .env: %v", err)
}
conf.AID = strings.ToLower(conf.AID)
// configuring mongodb and cloud backup clients.
db, err := connect(conf.MongoURI)
if err != nil {
log.Fatalf("Error connecting to mongo: %v", err)
}
defer disconnect(db)
dbColl := db.Database(conf.MongoDBName).Collection(conf.MongoBackupColl)
if err := os.MkdirAll(conf.OutDir, os.ModePerm); err != nil && !os.IsExist(err) {
log.Fatalf("Error creating output folder(%s): %q", conf.OutDir, err)
}
// we are only interested in one field.
var item struct {
Backups []storage.Backup `json:"backups,omitempty" bson:"backups,omitempty"`
}
err = dbColl.FindOne(
context.TODO(),
bson.D{
{Key: "aid", Value: conf.AID},
{Key: "year", Value: conf.Year},
{Key: "month", Value: conf.Month},
}).Decode(&item)
if err != nil {
log.Fatalf("Error searching for agency id \"%s\":%q", conf.AID, err)
}
downloads, err := savePackage(item.Backups, conf.OutDir)
if err != nil {
log.Fatalf("Error saving backups (%v): %q", item.Backups, err)
}
fmt.Println(strings.Join(downloads, "\n"))
}
func connect(url string) (*mongo.Client, error) {
c, err := mongo.NewClient(options.Client().ApplyURI(url))
if err != nil {
return nil, fmt.Errorf("error creating mongo client(%s):%w", url, err)
}
ctx, cancel := context.WithTimeout(context.Background(), mgoConnTimeout)
defer cancel()
if err := c.Connect(ctx); err != nil {
return nil, fmt.Errorf("error connecting to mongo(%s):%w", url, err)
}
return c, nil
}
func disconnect(c *mongo.Client) error {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if err := c.Disconnect(ctx); err != nil {
return fmt.Errorf("error disconnecting from mongo:%w", err)
}
return nil
}
func savePackage(backups []storage.Backup, outDir string) ([]string, error) {
var files []string
for _, file := range backups {
fpath := filepath.Join(outDir, path.Base(file.URL))
if err := download(fpath, file.URL); err != nil {
return nil, fmt.Errorf("error while dowloading file %s: %q", file, err)
}
files = append(files, fpath)
}
return files, nil
}
func download(fp string, url string) error {
os.MkdirAll(filepath.Dir(fp), 0700)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
out, err := os.Create(fp)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}