/
exchange_rate.go
153 lines (125 loc) · 3.73 KB
/
exchange_rate.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
package redisdb
import (
"log"
"math"
"time"
"github.com/chynkm/ratesdb/currencystore"
"github.com/chynkm/ratesdb/datastore"
"github.com/gomodule/redigo/redis"
)
const (
euro = "EUR"
rate_prefix = "rate:"
days = 30 // maximum days exchange rate to load inside Redis at startup
)
var LatestDate string
// SaveExchangeRates to Redis
// Insert data of previous days exchange rate when a day is missing
// Previous day is always present since we are fetching it from the DB
func SaveExchangeRates() {
rdb := Rdbpool.Get()
defer rdb.Close()
// Flush the Redis data before fresh data is inserted
_, err := rdb.Do("FLUSHDB")
if err != nil {
log.Fatal(err)
}
for i := days; i >= 0; i-- {
date := time.Now().AddDate(0, 0, -i).Format(currencystore.DateLayout)
if i == 0 {
LatestDate = date
}
saveExchangeRateForDate(rdb, date)
}
}
// saveExchangeRateForDate save exchange rate to Redis for a single date
func saveExchangeRateForDate(rdb redis.Conn, date string) {
dbCurrencies := datastore.GetCurrencies()
exchangeRates := datastore.GetExchangeRates(date)
dailyExchangeRates := createExchangeRateHash(
date,
dbCurrencies,
exchangeRates,
)
for key, dailyExchangeRate := range dailyExchangeRates {
redisExchangeRates := []interface{}{}
redisExchangeRates = append(redisExchangeRates, rate_prefix+key)
for code, rate := range dailyExchangeRate {
redisExchangeRates = append(redisExchangeRates, code, rate)
}
_, err := rdb.Do("HMSET", redisExchangeRates...)
if err != nil {
log.Fatal(err)
}
}
}
// createExchangeRateHash generates hash for exchange rates of different
// currencies for the given date
func createExchangeRateHash(
date string,
currencies map[string]int,
exchangeRates map[string]float64,
) map[string]map[string]float64 {
exchangeRateHash := map[string]map[string]float64{}
for currencyCode, _ := range currencies {
exchangeRateHash[date+":"+currencyCode] = calculateExchangeRate(
currencyCode,
exchangeRates,
)
}
return exchangeRateHash
}
// calculateExchangeRate for a base currency
func calculateExchangeRate(
baseCurrencyCode string,
exchangeRates map[string]float64,
) map[string]float64 {
if baseCurrencyCode == euro {
return exchangeRates
}
baseCurrencyExchangeRate := map[string]float64{}
for currencyCode, rate := range exchangeRates {
roundRate := rate / exchangeRates[baseCurrencyCode]
roundRate = math.Round(roundRate*10000) / 10000
baseCurrencyExchangeRate[currencyCode] = roundRate
}
return baseCurrencyExchangeRate
}
// GetExchangeRate retrieves the rate for the day from Redis
func GetExchangeRate(date, from, to string) (map[string]interface{}, error) {
rdb := Rdbpool.Get()
defer rdb.Close()
key := rate_prefix + date + ":" + from
exists, err := redis.Int(rdb.Do("EXISTS", key))
if err != nil {
log.Println("redis: check key exists failed in GetExchangeRate. key: ", key)
return map[string]interface{}{}, err
}
if exists == 0 {
saveExchangeRateForDate(rdb, date)
}
if to != "" {
rate, err := redis.Float64(rdb.Do("HGET", key, to))
if err != nil {
log.Println("redis: unable to retrieve HGET exchange rate for: ", date, from, to)
return map[string]interface{}{}, err
}
return map[string]interface{}{to: rate}, nil
}
redisRates, err := redis.Values(rdb.Do("HGETALL", key))
if err != nil {
log.Println("redis: unable to retrieve HGETALL exchange rate for: ", date, from)
return map[string]interface{}{}, err
}
rates := map[string]interface{}{}
for i := 0; i < len(redisRates); i += 2 {
currencyCode, _ := redis.String(redisRates[i], nil)
exchangeRate, _ := redis.Float64(redisRates[i+1], nil)
if exchangeRate == 0 {
rates[currencyCode] = nil
} else {
rates[currencyCode] = exchangeRate
}
}
return rates, err
}