-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
112 lines (91 loc) · 2.65 KB
/
main.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
package main
const (
error429 = 429
noError = 0
)
// ID - идентификатор пользователя
type ID int
// Queue - самописная тупая очередь
type Queue struct {
buffer []int
}
func (q *Queue) Push(val int) {
q.buffer = append(q.buffer, val)
}
func (q *Queue) Top() (int, bool) {
if len(q.buffer) > 0 {
return q.buffer[0], false
}
return 0, true
}
func (q *Queue) Pop() (int, bool) {
if len(q.buffer) > 0 {
top := q.buffer[0]
q.buffer = q.buffer[1:]
return top, false
}
return 0, true
}
func NewQueue() Queue {
return Queue{
buffer: []int{},
}
}
type Request struct {
id ID // идентификатор пользователя
time int // время запроса
}
type Response struct {
responses map[ID][]int
}
type RatelimitData struct {
ids map[ID]struct{} // какие пользователи ограничены
timeLimit int // единица времени
maxCount int // максимальное количество запросов за единицу времени
}
type Ratelimit struct {
rateLimitData *RatelimitData
queues map[ID]*Queue // очередь времени, когда освобождает еще одно место для нового запроса, для каждого id
currentRequestCount map[ID]int // количество текущих запросов, для каждого id
}
// Check - проверяет может ли пользователь получить доступ к участку кода
func (r *Ratelimit) Check(req Request) bool {
if _, inIdsList := r.rateLimitData.ids[req.id]; !inIdsList {
return true
}
currentRequestCount, countExist := r.currentRequestCount[req.id]
if !countExist {
currentRequestCount = 0
}
currentRequestCount++
queue, queueExist := r.queues[req.id]
if !queueExist {
newQueue := NewQueue()
newQueue.Push(req.time + r.rateLimitData.timeLimit)
r.queues[req.id] = &newQueue
} else {
queue.Push(req.time + r.rateLimitData.timeLimit)
top, isEmpty := queue.Top()
for top < req.time && !isEmpty {
currentRequestCount--
queue.Pop()
top, isEmpty = queue.Top()
}
}
r.currentRequestCount[req.id] = currentRequestCount
if currentRequestCount <= r.rateLimitData.maxCount {
return true
}
return false
}
func pseudoServer(requests []Request, responses Response, rateLimit Ratelimit) {
for _, req := range requests {
if rateLimit.Check(req) {
responses.responses[req.id] = append(responses.responses[req.id], noError)
} else {
responses.responses[req.id] = append(responses.responses[req.id], error429)
}
}
}
func main() {
}