-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
100 lines (89 loc) · 1.83 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
package main
import (
"bufio"
"compress/gzip"
"encoding/csv"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
)
func main() {
dst := flag.String("destination", "torbulkexitlist.json", "the destination file path")
src := flag.String("source", "https://check.torproject.org/torbulkexitlist", "the source URL")
flag.Parse()
err := run(*dst, *src)
if err != nil {
log.Fatalln(err)
}
}
func run(dst, src string) error {
ips, err := readIPs(src)
if err != nil {
return err
}
f, err := os.Create(dst)
if err != nil {
return err
}
defer f.Close()
return writeFile(f, dst, ips)
}
func readIPs(src string) ([]string, error) {
res, err := http.Get(src)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode/100 != 2 {
return nil, fmt.Errorf("unexpected status code: %d %s", res.StatusCode, res.Status)
}
var ips []string
scanner := bufio.NewScanner(res.Body)
for scanner.Scan() {
ip := strings.TrimSpace(scanner.Text())
if ip == "" {
continue
}
ips = append(ips, ip)
}
sort.Strings(ips)
return ips, nil
}
func writeFile(w io.Writer, name string, ips []string) error {
switch ext := filepath.Ext(name); ext {
case ".gz":
zw, err := gzip.NewWriterLevel(w, gzip.BestCompression)
if err != nil {
return err
}
err = writeFile(zw, name[:len(name)-len(ext)], ips)
if err != nil {
_ = zw.Close()
return err
}
return zw.Close()
case ".csv":
cw := csv.NewWriter(w)
cw.Write([]string{"id"})
for _, ip := range ips {
cw.Write([]string{ip})
}
cw.Flush()
return cw.Error()
case ".json":
var records []interface{}
for _, ip := range ips {
records = append(records, map[string]interface{}{"id": ip})
}
return json.NewEncoder(w).Encode(records)
default:
return fmt.Errorf("unsupported file extension: %s", ext)
}
}