Skip to content

Commit 1b442ff

Browse files
committed
ratelimit assignment
1 parent e0be1be commit 1b442ff

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

test-server/main.go

+5
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,16 @@ func main() {
207207
tokenSecret: getRandomSecret(),
208208
}
209209

210+
rl := &RateLimit{
211+
hits: make(map[string]uint64),
212+
}
213+
210214
mux := http.NewServeMux()
211215

212216
mux.Handle("/words", wh.authMiddleware(wh.wordsHandler))
213217
mux.Handle("/occurrence", wh.authMiddleware(wh.occurrenceHandler))
214218
mux.HandleFunc("/assignment1", wh.assignment1)
219+
mux.HandleFunc("/ratelimit", rl.ratelimit)
215220
mux.HandleFunc("/", wh.indexHandler)
216221
mux.HandleFunc("/login", wh.login)
217222
fmt.Printf("Starting server on port %v...\n", port)

test-server/ratelimit.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"sync"
7+
"time"
8+
)
9+
10+
const DATE_FORMAT = "2006-01-02T15:04:05"
11+
12+
type RateLimit struct {
13+
mu sync.Mutex
14+
hits map[string]uint64
15+
limitExceeded bool
16+
limitLifted time.Time
17+
}
18+
19+
func (rl *RateLimit) ratelimit(w http.ResponseWriter, r *http.Request) {
20+
if rl.limitExceeded && time.Now().Before(rl.limitLifted) {
21+
w.WriteHeader(429)
22+
w.Write([]byte("Rate Limited"))
23+
return
24+
}
25+
if rl.limitExceeded && time.Now().After(rl.limitLifted) {
26+
rl.limitExceeded = false
27+
}
28+
rl.mu.Lock()
29+
timestamp := time.Now()
30+
strTimestamp := timestamp.Format(DATE_FORMAT)
31+
if val, ok := rl.hits[strTimestamp]; ok {
32+
if val == 5 {
33+
rl.limitExceeded = true
34+
rl.limitLifted = time.Now().Add(time.Second * 10)
35+
} else {
36+
rl.hits[strTimestamp] = val + 1
37+
}
38+
} else {
39+
rl.hits[strTimestamp] = 1
40+
}
41+
rl.mu.Unlock()
42+
timestampOneSecondEarlier := time.Now().Add(time.Duration(-1) * time.Second)
43+
if rl.hits[timestampOneSecondEarlier.Format(DATE_FORMAT)] == 5 {
44+
w.Write([]byte(fmt.Sprintf("DONE! You did it! Hitting API at %d requests in a given second\n", rl.hits[timestampOneSecondEarlier.Format(DATE_FORMAT)])))
45+
} else {
46+
w.Write([]byte(fmt.Sprintf("Hitting API at %d requests in a given second\n", rl.hits[timestampOneSecondEarlier.Format(DATE_FORMAT)])))
47+
}
48+
if len(rl.hits) > 100000 {
49+
rl.mu.Lock()
50+
fmt.Printf("Map is getting big, resetting...\n")
51+
oldVal := rl.hits[strTimestamp]
52+
rl.hits = make(map[string]uint64)
53+
rl.hits[strTimestamp] = oldVal
54+
time.Sleep(1 * time.Second)
55+
rl.mu.Unlock()
56+
}
57+
}

0 commit comments

Comments
 (0)