-
Notifications
You must be signed in to change notification settings - Fork 0
/
dekanat.go
166 lines (130 loc) · 4.62 KB
/
dekanat.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
package main
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/kneu-messenger-pigeon/fileStorage"
"regexp"
"strings"
"time"
)
const FirebirdTimeFormat = "2006-01-02T15:04:05"
const StorageTimeFormat = time.RFC3339
const GetLastDatetimeQuery = "SELECT FIRST 1 CON_DATA FROM TSESS_LOG ORDER BY ID DESC"
const GetFirstLessonRegDateQuery = "SELECT FIRST 1 REGDATE FROM T_PRJURN ORDER BY REGDATE ASC"
func makeDbState(secondaryDekanatDb *sql.DB) (state dbState, err error) {
state.ActualDatetime, err = getDbStateDatetime(secondaryDekanatDb)
if err != nil {
return state, errors.New("Failed to get last datetime from DB: " + err.Error())
}
state.EducationYear, err = getCurrentYear(secondaryDekanatDb)
if err != nil {
return state, errors.New("failed to detect current education year: " + err.Error())
}
return state, nil
}
func checkDekanatDb(secondaryDekanatDb *sql.DB, storage fileStorage.Interface, eventbus MetaEventbusInterface) error {
currentState, err := makeDbState(secondaryDekanatDb)
if err != nil {
return errors.New("Failed to get DB state: " + err.Error())
}
var previousState dbState
previousStateSerialized, err := storage.Get()
if err == nil && previousStateSerialized != nil && len(previousStateSerialized) > 10 {
err = json.Unmarshal(previousStateSerialized, &previousState)
}
if err != nil {
return errors.New("Failed to get previous DB state from Storage: " + err.Error())
}
if previousState.isEqual(currentState) {
return nil
}
// skip if current db state is less than 3 hours from previous
if currentState.ActualDatetime.Sub(previousState.ActualDatetime) < time.Hour*3 {
return nil
}
currentStateSerialized, _ := json.Marshal(currentState)
err = storage.Set(currentStateSerialized)
if err != nil {
return err
}
if currentState.EducationYear != previousState.EducationYear {
err = eventbus.sendCurrentYearEvent(currentState.EducationYear)
if err != nil {
_ = storage.Set(previousStateSerialized)
return errors.New("Failed to send Current year event to Kafka: " + err.Error())
}
}
err = eventbus.sendSecondaryDbLoadedEvent(
currentState.ActualDatetime, previousState.ActualDatetime,
currentState.EducationYear,
)
if err != nil {
_ = storage.Set(previousStateSerialized)
return errors.New("Failed to send Secondary DB loaded Event to Kafka: " + err.Error())
}
return nil
}
// drop "+02:00" , "+03:00" etc in the end
var removeTimeZone = regexp.MustCompile(`\+[0-9]{2}:[0-9]{2}$`)
var removeMilliseconds = regexp.MustCompile(`\.[0-9]{3}`)
func getDbStateDatetime(secondaryDekanatDb *sql.DB) (time.Time, error) {
err := secondaryDekanatDb.Ping()
if err != nil {
return time.Time{}, err
}
var lastDatetimeString string
rows := secondaryDekanatDb.QueryRow(GetLastDatetimeQuery)
if rows.Err() != nil {
return time.Time{}, rows.Err()
}
err = rows.Scan(&lastDatetimeString)
if lastDatetimeString == "" || err != nil {
return time.Time{}, errors.New(fmt.Sprintf("empty last date from DB: %s", err))
}
lastDatetimeString = strings.Replace(lastDatetimeString, "Z", "", 1)
lastDatetimeString = removeTimeZone.ReplaceAllString(lastDatetimeString, "")
lastDatetimeString = removeMilliseconds.ReplaceAllString(lastDatetimeString, "")
return time.ParseInLocation(FirebirdTimeFormat, lastDatetimeString, time.Local)
}
func getCurrentYear(secondaryDekanatDb *sql.DB) (int, error) {
var firstLessonRegDateString string
rows := secondaryDekanatDb.QueryRow(GetFirstLessonRegDateQuery)
if rows.Err() != nil {
return 0, rows.Err()
}
err := rows.Scan(&firstLessonRegDateString)
if err != nil {
return 0, errors.New(fmt.Sprintf("empty last date from DB: %s", err))
}
// git first 10 chars of string, like "2024-09-02"
firstLessonRegDateString = firstLessonRegDateString[:10]
firstLessonRegDate, err := time.ParseInLocation("2006-01-02", firstLessonRegDateString, time.Local)
if err != nil {
return 0, errors.New(fmt.Sprintf("failed to parse first lesson registration date: %s", err))
}
year := firstLessonRegDate.Year()
// if first half of year - definitely it is education year start year ago
if firstLessonRegDate.Month() < 8 {
year--
}
if year < 2022 {
return 0, errors.New(fmt.Sprintf("wrong education (should be 2022 or later): %d", year))
}
return year, nil
}
func extractEducationYear(dbStateDatetime time.Time) (int, error) {
if dbStateDatetime.IsZero() {
return 0, errors.New("zero datetime for parse education year")
}
year := dbStateDatetime.Year()
month := dbStateDatetime.Month()
if month < 9 {
year--
}
if year < 2022 {
return 0, errors.New(fmt.Sprintf("wrong education (should be 2022 or later): %d", year))
}
return year, nil
}