meeting/main.go

102 lines
2.3 KiB
Go

package main
import (
"context"
"fmt"
"github.com/kordondev/meeting/throttling"
"net/http"
"sync"
"time"
)
const burstLimit = 3
const rateLimit = time.Second * 3
const correctResult = "12"
func main() {
ctx := context.Background()
var throttles sync.Map
http.HandleFunc("/", serveIndexFile)
http.HandleFunc("/input.txt", serveInputFile)
http.HandleFunc("/result", func(w http.ResponseWriter, r *http.Request) {
cctxV, ok := getThrottleContext(&throttles, r.RemoteAddr)
if !ok {
cctx, cancel := context.WithCancel(ctx)
throttle := throttling.CreateThrottle(cctx, burstLimit, rateLimit)
a := throttleWithCancel{
throttle: throttle,
cancel: cancel,
}
cctxV = context.WithValue(ctx, "throttle", a)
throttles.Store(r.RemoteAddr, cctxV)
go func() {
time.Sleep(time.Minute * 20)
throttles.Delete(r.RemoteAddr)
cancel()
}()
}
tryResult(cctxV, w, r)
})
err := http.ListenAndServe(":3333", nil)
if err != nil {
fmt.Printf("http.ListenAndServe() failed with %s\n", err)
}
}
type throttleWithCancel struct {
throttle <-chan time.Time
cancel context.CancelFunc
}
func serveIndexFile(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index.html")
}
func serveInputFile(w http.ResponseWriter, r *http.Request) {
fmt.Println(time.Now(), "Load input file", r.RemoteAddr)
http.ServeFile(w, r, "static/input.txt")
}
func tryResult(ctx context.Context, w http.ResponseWriter, r *http.Request) {
clientResult := r.URL.Query().Get("result")
name := r.URL.Query().Get("name")
fmt.Println(time.Now(), "Submit result", clientResult, r.RemoteAddr, name)
throttle := ctx.Value("throttle").(throttleWithCancel).throttle
payload := throttling.Payload{
R: r,
W: w,
ClientResult: clientResult,
}
throttling.CallFunction(ctx, &CheckResult{}, &payload, throttle)
}
type CheckResult struct {
}
func (*CheckResult) Call(payload *throttling.Payload) {
w := payload.W
r := payload.R
fmt.Println(time.Now(), "Serve now for", r.RemoteAddr)
if payload.ClientResult == correctResult {
http.ServeFile(w, r, "static/success.html")
return
}
http.ServeFile(w, r, "static/fail.html")
}
func getThrottleContext(throttles *sync.Map, RemoteAddr string) (context.Context, bool) {
ctx1, ok := throttles.Load(RemoteAddr)
if !ok {
return nil, ok
}
return ctx1.(context.Context), true
}