-
Notifications
You must be signed in to change notification settings - Fork 0
/
stations.go
152 lines (124 loc) · 3.3 KB
/
stations.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
145
146
147
148
149
150
151
152
package cptec
import (
"crypto/md5"
"encoding/json"
"fmt"
"log"
"regexp"
)
// These are the constants that can be use
const (
// pathStations link to get the list of stations.
pathStations = "/PCD/SITE/novo/site/historico/index.php"
// pathFullStations link to get full information of stations.
pathFullStations = "/PCD/SITE/novo/site/historico/passo2.php"
)
// These are the constants that can be use
var (
rgStations = `<option value=(?P<ID>\d+)>\d+-(?P<UF>[A-Z]{2})-(?P<Locality>.*?)</option>`
rgFullStations = `Latitude:\s+(?P<Latitude>.*?),\s+?Longitude:\s+(?P<Longitude>.*?),`
)
// StationService ...
type StationService struct {
client *CPTEC
}
// Station structure representing the CPTEC/INPE weather station.
//
// Information such as location and identification is part of this
// structure.
type Station struct {
ID string `json:"id"`
UF string `json:"uf"`
Locality string `json:"locality"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
}
// Stations array ...
type Stations []*Station
// ToBytes convert station to byte
func (s *Station) ToBytes() []byte {
jsonBytes, _ := json.Marshal(s)
return jsonBytes
}
// Hash return md5 of station
func (s *Station) Hash() string {
stationBytes := s.ToBytes()
stationHash := fmt.Sprintf("%x", md5.Sum(stationBytes))
return stationHash
}
func (s *Station) String() string {
return fmt.Sprintf("ID: %s UF: %s Locality: %s Latitude: %s Longitude: %s", s.ID, s.UF, s.Locality, s.Latitude, s.Longitude)
}
// GetAll ...
func (s *StationService) GetAll() ([]*Station, error) {
var stations []*Station
req, err := s.client.NewRequest("GET", pathStations, nil, nil)
if err != nil {
return nil, err
}
html, err := s.client.do(req)
if err != nil {
return nil, err
}
re := regexp.MustCompile(rgStations)
for _, match := range re.FindAllStringSubmatch(string(html), -1) {
station := &Station{
ID: match[1],
UF: match[2],
Locality: match[3],
}
stations = append(stations, station)
}
return stations, err
}
// Get coleta todos
func (s *StationService) Get(station *Station) error {
form := make(map[string]string)
form["id"] = station.ID
req, err := s.client.NewRequest("POST", pathFullStations, form, nil)
if err != nil {
return err
}
html, err := s.client.do(req)
if err != nil {
return err
}
re := regexp.MustCompile(rgFullStations)
for _, match := range re.FindAllStringSubmatch(string(html), -1) {
station.Latitude = match[1]
station.Longitude = match[2]
}
return nil
}
func worker(s *StationService, id int, jobs <-chan *Station, results chan<- *Station) {
for j := range jobs {
s.Get(j)
results <- j
}
}
// GetFull ...
func (s *StationService) GetFull() ([]*Station, error) {
stations, err := s.GetAll()
var stationsFuture []*Station
if err != nil {
return nil, err
}
fmt.Println("Número de Estações: ", len(stations))
jobs := make(chan *Station, len(stations))
results := make(chan *Station, len(stations))
for w := 1; w <= 5; w++ {
go worker(s, w, jobs, results)
}
for _, station := range stations {
jobs <- station
}
close(jobs)
for range stations {
station := <-results
stationsFuture = append(stationsFuture, station)
}
if err := Save("./data/stations.json", stationsFuture); err != nil {
log.Fatalln(err)
}
return stationsFuture, nil
}