-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstorage.go
146 lines (125 loc) · 3.11 KB
/
storage.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
package main
import (
"crypto/rand"
"encoding/base64"
math_rand "math/rand"
"regexp"
"strconv"
"strings"
"time"
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/number"
)
var safeStringRegex = regexp.MustCompile(`[^a-zA-Z0-9]`)
var zeroStringRegex = regexp.MustCompile(`[0]{1}`)
func newStorage(active bool) *storage {
storage := storage{}
storage.active = active
storage.values = make(map[string]uint64)
storage.expire = make(map[string]int64)
return &storage
}
func (s *storage) count() int {
return len(s.values)
}
func (s *storage) newItem(level int, lang string, ttl int64) *storageItem {
if s.active {
s.mu.Lock()
defer s.mu.Unlock()
}
id := generateID()
value := generateProblem(level)
intlValue := convertUInt64ToString(value)
if lang == "fa" {
intlValue = message.NewPrinter(language.Persian).Sprintf("%v", number.Decimal(value, number.NoSeparator()))
} else if lang == "ar" {
intlValue = message.NewPrinter(language.Arabic).Sprintf("%v", number.Decimal(value, number.NoSeparator()))
}
item := storageItem{id: id, value: value, language: lang, intlValue: intlValue, level: level}
if s.active {
expireTime := time.Now()
expireTime = expireTime.Add(time.Second * time.Duration(ttl))
item.expire = expireTime
s.expire[id] = expireTime.Unix()
s.values[id] = value
}
return &item
}
func (s *storage) validate(id string, value uint64) bool {
s.mu.Lock()
defer s.mu.Unlock()
if exp, ok := s.expire[id]; ok {
if exp >= time.Now().Unix() && s.values[id] == value {
delete(s.expire, id)
delete(s.values, id)
prometheusValidTotal.Inc()
return true
}
}
prometheusInValidTotal.Inc()
return false
}
func (s *storage) cleanUp() {
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now().Unix()
for id, exp := range s.expire {
if exp <= now {
delete(s.expire, id)
delete(s.values, id)
}
}
}
func generateID() string {
b1 := make([]byte, 16)
_, err := rand.Read(b1)
if err != nil {
panic(err.Error())
}
return safeStringRegex.ReplaceAllString(base64.StdEncoding.EncodeToString(b1), "")[0:12]
}
func generateProblem(level int) uint64 {
var num int
var min int
var max int
if level == levelEasy {
min = 10000
max = 99999
} else if level == levelHard {
min = 1000000
max = 9999999
} else { // medium is default
min = 100000
max = 999999
}
num = getRandomNumber(min, max)
numberString := strconv.Itoa(num)
numberString = zeroStringRegex.ReplaceAllStringFunc(numberString, func(m string) string {
return strconv.Itoa(getRandomNumber(1, 9))
})
return convertStringToUInt64(numberString)
}
func getRandomNumber(min int, max int) int {
math_rand.Seed(time.Now().UnixNano())
return math_rand.Intn(max-min) + min
}
func convertStringToUInt64(str string) uint64 {
value, e := strconv.ParseInt(str, 10, 64)
if e != nil {
return 0
}
return uint64(value)
}
func convertUInt64ToString(in uint64) string {
return strconv.FormatUint(in, 10)
}
func getLevel(str string) int {
if str == "1" || strings.ToUpper(str) == "EASY" {
return levelEasy
}
if str == "2" || strings.ToUpper(str) == "HARD" {
return levelHard
}
return levelMedium
}