/
collector.go
188 lines (167 loc) Β· 5.74 KB
/
collector.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package collector
import (
"regexp"
"strconv"
"time"
"github.com/JamesClonk/iRcollector/api"
"github.com/JamesClonk/iRcollector/database"
"github.com/JamesClonk/iRcollector/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
collectorErrors = promauto.NewCounter(prometheus.CounterOpts{
Name: "ircollector_errors_total",
Help: "Total errors from iRcollector, should be a rate of 0.",
})
)
type Collector struct {
client *api.Client
db database.Database
}
func New(db database.Database) *Collector {
return &Collector{
client: api.New(),
db: db,
}
}
func (c *Collector) Database() database.Database {
return c.db
}
func (c *Collector) Run() {
seasonrx := regexp.MustCompile(`20[1-5][0-9] Season [1-4]`) // "2019 Season 2"
// update tracks
c.CollectTracks()
// update cars
c.CollectCars()
forceUpdate := false
forceUpdateCounter := 0
for {
series, err := c.db.GetActiveSeries()
if err != nil {
log.Errorln("could not read series information from database")
log.Fatalf("%v", err)
}
// update tracks and cars only once in a while
if forceUpdate {
c.CollectTracks()
c.CollectCars()
}
// fetch all current seasons and go through them
seasons, err := c.client.GetCurrentSeasons()
if err != nil {
log.Fatalf("%v", err)
}
if len(seasons) == 0 {
collectorErrors.Inc()
log.Errorf("no seasons found, couldn't get anything from iRacing!")
}
for _, series := range series {
var found bool
namerx := regexp.MustCompile(series.SeriesRegex)
for _, season := range seasons {
if namerx.MatchString(season.SeasonName) || season.SeriesID == series.APISeriesID { // does SeasonName match seriesRegex from db? or the API provided SeriesID?
log.Infof("Season: %s", season)
found = true
// does it already exists in db?
s, err := c.db.GetSeasonByID(season.SeasonID)
if err != nil {
log.Errorf("could not get season [%d] from database: %v", season.SeasonID, err)
}
if err != nil || len(s.SeasonName) == 0 || len(s.Timeslots) == 0 || s.StartDate.Before(time.Now().AddDate(-1, -1, -1)) {
year := season.Year
quarter := season.Quarter
if year < 2018 || quarter < 1 { // figure out which season we are in incase API returns nonsense
if seasonrx.MatchString(season.SeasonNameShort) {
var err error
year, err = strconv.Atoi(season.SeasonNameShort[0:4])
if err != nil {
collectorErrors.Inc()
log.Errorf("could not convert SeasonNameShort [%s] to year: %v", season.SeasonNameShort, err)
}
quarter, err = strconv.Atoi(season.SeasonNameShort[12:13])
if err != nil {
collectorErrors.Inc()
log.Errorf("could not convert SeasonNameShort [%s] to quarter: %v", season.SeasonNameShort, err)
}
}
// if we couldn't figure out the season from SeasonNameShort, then we'll try to calculate it based on 2018S1 which started on 2017-12-12
if year < 2018 || quarter < 1 {
iracingEpoch := time.Date(2017, 12, 12, 0, 0, 0, 0, time.UTC)
daysSince := int(time.Since(iracingEpoch).Hours() / 24)
weeksSince := daysSince / 7
seasonsSince := int(weeksSince / 13)
yearsSince := int(seasonsSince / 4)
year = 2018 + yearsSince
quarter = (seasonsSince % 4) + 1
}
}
// startDate := database.WeekStart(time.Now().UTC().AddDate(0, 0, -7*season.RaceWeek))
log.Infof("Current season: %dS%d, started: %s", year, quarter, season.StartDate)
// upsert current season
s.SeriesID = series.SeriesID
s.SeasonID = season.SeasonID
s.Year = year
s.Quarter = quarter
s.Category = "-" // pointless since this can change each week / for each track
s.SeasonName = season.SeasonName
s.SeasonNameShort = season.SeasonNameShort
s.BannerImage = "-" // does not exist anymore in new API
s.PanelImage = "-" // does not exist anymore in new API
s.LogoImage = "-" // does not exist anymore in new API
s.StartDate = season.StartDate
if err := c.db.UpsertSeason(s); err != nil {
collectorErrors.Inc()
log.Errorf("could not store season [%s] in database: %v", season.SeasonName, err)
}
}
// insert current raceweek
c.CollectRaceWeek(season.SeasonID, season.RaceWeek, forceUpdate)
// update previous week too
if season.RaceWeek > 0 {
c.CollectRaceWeek(season.SeasonID, season.RaceWeek-1, forceUpdate)
} else {
// find previous season
ss, err := c.db.GetSeasonsBySeriesID(series.SeriesID)
if err != nil {
log.Errorln("could not read seasons from database")
log.Fatalf("%v", err)
}
for _, s := range ss {
yearToFind := s.Year
quarterToFind := s.Quarter - 1
if s.Quarter == 1 {
yearToFind = yearToFind - 1
quarterToFind = 4
}
if s.Year == yearToFind && s.Quarter == quarterToFind { // previous season found
c.CollectRaceWeek(s.SeasonID, 11, forceUpdate)
break
}
}
}
}
}
if !found {
log.Errorf("no seasons found for series [%s], couldn't match anything to regex [%s] or API series_id [%d]!", series.SeriesName, series.SeriesRegex, series.APISeriesID)
}
}
// check if we should forcibly update the whole raceweek / do a full snapshot
if forceUpdate {
forceUpdate = false
forceUpdateCounter = 0
}
forceUpdateCounter++
if forceUpdateCounter > 33 {
forceUpdate = true
forceUpdateCounter = 0
}
time.Sleep(33 * time.Minute)
}
}
func (c *Collector) CollectSeason(seasonID int) {
log.Infof("collecting whole season [%d], all 12 weeks ...", seasonID)
for w := 0; w < 12; w++ {
c.CollectRaceWeek(seasonID, w, true)
}
}