Finish code

This commit is contained in:
Arne Maier 2024-11-12 21:21:23 +01:00
parent 82790e260d
commit 27bed5a2b7
6 changed files with 67 additions and 71 deletions

38
main.go
View File

@ -5,32 +5,36 @@ import (
"fmt" "fmt"
"github.com/kordondev/meeting/throttling" "github.com/kordondev/meeting/throttling"
"net/http" "net/http"
"sync"
"time" "time"
) )
const burstLimit = 2 const burstLimit = 3
const rateLimit = time.Second * 3
const correctResult = "12"
func main() { func main() {
ctx := context.Background() ctx := context.Background()
throttles := make(map[string]context.Context) // use sync map var throttles sync.Map
http.HandleFunc("/", serveIndexFile) http.HandleFunc("/", serveIndexFile)
http.HandleFunc("/input.txt", serveInputFile) http.HandleFunc("/input.txt", serveInputFile)
http.HandleFunc("/result", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/result", func(w http.ResponseWriter, r *http.Request) {
cctxV, ok := throttles[r.RemoteAddr] cctxV, ok := getThrottleContext(&throttles, r.RemoteAddr)
if !ok { if !ok {
cctx, cancel := context.WithCancel(ctx) cctx, cancel := context.WithCancel(ctx)
throttle := throttling.CreateThrottle(cctx, burstLimit) throttle := throttling.CreateThrottle(cctx, burstLimit, rateLimit)
a := throttleWithCancel{ a := throttleWithCancel{
throttle: throttle, throttle: throttle,
cancel: cancel, cancel: cancel,
} }
cctxV = context.WithValue(ctx, "throttle", a) cctxV = context.WithValue(ctx, "throttle", a)
throttles[r.RemoteAddr] = cctxV throttles.Store(r.RemoteAddr, cctxV)
go func() { go func() {
time.Sleep(time.Minute * 20) time.Sleep(time.Minute * 20)
delete(throttles, r.RemoteAddr) throttles.Delete(r.RemoteAddr)
cancel() cancel()
}() }()
} }
@ -50,18 +54,18 @@ type throttleWithCancel struct {
} }
func serveIndexFile(w http.ResponseWriter, r *http.Request) { func serveIndexFile(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index-with-text.html") http.ServeFile(w, r, "static/index.html")
} }
func serveInputFile(w http.ResponseWriter, r *http.Request) { func serveInputFile(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.RemoteAddr) fmt.Println(time.Now(), "Load input file", r.RemoteAddr)
http.ServeFile(w, r, "static/input.txt") http.ServeFile(w, r, "static/input.txt")
} }
func tryResult(ctx context.Context, w http.ResponseWriter, r *http.Request) { func tryResult(ctx context.Context, w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
clientResult := r.URL.Query().Get("result") clientResult := r.URL.Query().Get("result")
fmt.Println(clientIP, "called with:", clientResult) name := r.URL.Query().Get("name")
fmt.Println(time.Now(), "Submit result", clientResult, r.RemoteAddr, name)
throttle := ctx.Value("throttle").(throttleWithCancel).throttle throttle := ctx.Value("throttle").(throttleWithCancel).throttle
payload := throttling.Payload{ payload := throttling.Payload{
R: r, R: r,
@ -79,9 +83,19 @@ func (*CheckResult) Call(payload *throttling.Payload) {
w := payload.W w := payload.W
r := payload.R r := payload.R
fmt.Println("Serve now") fmt.Println(time.Now(), "Serve now for", r.RemoteAddr)
if payload.ClientResult == "12" { if payload.ClientResult == correctResult {
http.ServeFile(w, r, "static/success.html") http.ServeFile(w, r, "static/success.html")
return
} }
http.ServeFile(w, r, "static/fail.html") 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
}

View File

@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nicht so schnell</title> <title>Nicht so schnell</title>
</head> </head>
<body> <body style="color: white; background: #0f0f23; font-family: 'Source Code Pro', monospace;">
<img alt="" src="https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExaGk0cGNyanVvbmlxd3dmdDc1NmxyMnBoNGQwbWI1ZWhhb3ppeHd2OCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vyTnNTrs3wqQ0UIvwE/giphy.webp"/> <img alt="advent-of-code 22, day 2" src="https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExaGk0cGNyanVvbmlxd3dmdDc1NmxyMnBoNGQwbWI1ZWhhb3ppeHd2OCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vyTnNTrs3wqQ0UIvwE/giphy.webp"/>
<p>Leider nicht die richtige Antwort. Versuch es erneut.</p> <p>Leider nicht die richtige Antwort. Versuch es erneut.</p>
</body> </body>
</html> </html>

View File

@ -1,43 +0,0 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Informatikertreffen</title>
</head>
<body>
<h1>Das Turnier der Türsteher</h1>
<p>Die Türsteher veranstallten ein Schere-Stein-Papier-Turnier zwischen den Wartenden. Nur die Besten dürfen zu dem Treffen.</p>
<p>Schere-Stein-Papier ist ein Spiel zwischen zwei Spielern. Jedes Spiel besteht aus mehreren Runden; in jeder Runde wählen die Spieler gleichzeitig eine der Optionen Stein, Papier oder Schere durch eine Handgeste. Dann wird ein Gewinner für die Runde bestimmt: Stein schlägt Schere, Schere schlägt Papier und Papier schlägt Stein. Wählen beide Spieler die gleiche Form, endet die Runde unentschieden.</p>
<p>Plötzlich bekommst du von einer unbekannten Nummer: Einen verschlüsselten Strategie-Leitfaden (deine Puzzle-Eingabe), von dem gesagt wird, dass er dir sicher helfen wird zu gewinnen. „Die erste Spalte zeigt, was dein Gegner spielen wird: A steht für Stein, B für Papier und C für Schere. Die zweite Spalte—“ Plötzlich ein Funkloch und der Rest der Nachricht fehlt.</p>
<p>Du folgerst, dass die zweite Spalte das zeigt, was du als Reaktion spielen solltest: A für Stein, B für Papier und C für Schere. Immer zu gewinnen wäre verdächtig, also müssen die Antworten sorgfältig gewählt worden sein.</p>
<p>Der Gewinner des gesamten Turniers ist der Spieler mit der höchsten Punktzahl. Deine Gesamtpunktzahl ist die Summe deiner Punkte für jede Runde. Die Punktzahl für eine einzelne Runde setzt sich zusammen aus der Punktzahl für die gewählte Form (1 für Stein, 2 für Papier und 3 für Schere) plus der Punktzahl für das Ergebnis der Runde (0, wenn du verloren hast, 3, wenn die Runde unentschieden endete, und 6, wenn du gewonnen hast).</p>
<p>Da du dir nicht sicher sein kannst, ob dir die unbekannte Person wirklich helfen will oder dich täuschen möchte, solltest du die Punktzahl berechnen, die du erreichen würdest, wenn du den Strategie-Leitfaden befolgst.</p>
<p>Zum Beispiel, nehmen wir an, du bekommst den folgenden Strategie-Leitfaden:</p>
<pre>
A B
B A
C C
</pre>
<p>Dieser Strategie-Leitfaden sagt Folgendes voraus und empfiehlt:</p>
<ul>
<li>In der ersten Runde wird dein Gegner Stein (A) wählen, und du solltest Papier (B) wählen. Dies führt zu einem Sieg für dich mit einer Punktzahl von 8 (2 Punkte, weil du Papier gewählt hast + 6 Punkte für den Sieg).</li>
<li>In der zweiten Runde wird dein Gegner Papier (B) wählen, und du solltest Stein (A) wählen. Dies führt zu einer Niederlage für dich mit einer Punktzahl von 1 (1 Punkt + 0 Punkte).</li>
<li>Die dritte Runde ist ein Unentschieden, da beide Spieler Schere wählen, was dir eine Punktzahl von 6 gibt (3 Punkte für die Wahl von Schere + 3 Punkte für das Unentschieden).</li>
</ul>
<p>In diesem Beispiel würdest du, wenn du dem Strategie-Leitfaden folgst, eine Gesamtpunktzahl von 15 erreichen (8 + 1 + 6).</p>
<p>Was wäre deine Gesamtpunktzahl, wenn alles genau nach dem Strategie-Leitfaden verläuft?</p>
<form action="/result">
<label for="result">Antwort:</label>
<input type="text" id="result" name="result">
<button type="submit">Submit</button>
</form>
<p>Ich hoffe, diese Übersetzung hilft dir weiter!</p>
</body>
</html>

View File

@ -5,15 +5,38 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Informatikertreffen</title> <title>Informatikertreffen</title>
</head> </head>
<body> <body style="color: white; background: #0f0f23; font-family: 'Source Code Pro', monospace;">
<h1>Das Turnier der Türsteher</h1>
<p>Die Türsteher veranstallten ein Schere-Stein-Papier-Turnier zwischen den Wartenden. Nur die Besten dürfen zu dem Treffen.</p>
<p>Schere-Stein-Papier ist ein Spiel zwischen zwei Spielern. Jedes Spiel besteht aus mehreren Runden; in jeder Runde wählen die Spieler gleichzeitig eine der Optionen Stein, Papier oder Schere durch eine Handgeste. Dann wird ein Gewinner für die Runde bestimmt: Stein schlägt Schere, Schere schlägt Papier und Papier schlägt Stein. Wählen beide Spieler die gleiche Form, endet die Runde unentschieden.</p>
<p>Plötzlich bekommst du von einer unbekannten Nummer: Einen verschlüsselten Strategie-Leitfaden (deine Puzzle-Eingabe), von dem gesagt wird, dass er dir sicher helfen wird zu gewinnen. „Die erste Spalte zeigt, was dein Gegner spielen wird: A steht für Stein, B für Papier und C für Schere. Die zweite Spalte—“ Plötzlich ein Funkloch und der Rest der Nachricht fehlt.</p>
<p>Du folgerst, dass die zweite Spalte das zeigt, was du als Reaktion spielen solltest: A für Stein, B für Papier und C für Schere. Immer zu gewinnen wäre verdächtig, also müssen die Antworten sorgfältig gewählt worden sein.</p>
<p>Der Gewinner des gesamten Turniers ist der Spieler mit der höchsten Punktzahl. Deine Gesamtpunktzahl ist die Summe deiner Punkte für jede Runde. Die Punktzahl für eine einzelne Runde setzt sich zusammen aus der Punktzahl für die gewählte Form (1 für Stein, 2 für Papier und 3 für Schere) plus der Punktzahl für das Ergebnis der Runde (0, wenn du verloren hast, 3, wenn die Runde unentschieden endete, und 6, wenn du gewonnen hast).</p>
<p>Da du dir nicht sicher sein kannst, ob dir die unbekannte Person wirklich helfen will oder dich täuschen möchte, solltest du die Punktzahl berechnen, die du erreichen würdest, wenn du den Strategie-Leitfaden befolgst.</p>
<p>Zum Beispiel, nehmen wir an, du bekommst den folgenden Strategie-Leitfaden:</p>
<pre>
A B
B A
C C
</pre>
<p>Dieser Strategie-Leitfaden sagt Folgendes voraus und empfiehlt:</p>
<ul>
<li>In der ersten Runde wird dein Gegner Stein (A) wählen, und du solltest Papier (B) wählen. Dies führt zu einem Sieg für dich mit einer Punktzahl von 8 (2 Punkte, weil du Papier gewählt hast + 6 Punkte für den Sieg).</li>
<li>In der zweiten Runde wird dein Gegner Papier (B) wählen, und du solltest Stein (A) wählen. Dies führt zu einer Niederlage für dich mit einer Punktzahl von 1 (1 Punkt + 0 Punkte).</li>
<li>Die dritte Runde ist ein Unentschieden, da beide Spieler Schere wählen, was dir eine Punktzahl von 6 gibt (3 Punkte für die Wahl von Schere + 3 Punkte für das Unentschieden).</li>
</ul>
<p>In diesem Beispiel würdest du, wenn du dem Strategie-Leitfaden folgst, eine Gesamtpunktzahl von 15 erreichen (8 + 1 + 6).</p>
<p>Was wäre deine Gesamtpunktzahl, wenn alles genau nach dem Strategie-Leitfaden verläuft?</p>
<form action="/result"> <form action="/result">
<label for="result">Name:</label> <label for="name">Name:</label>
<input type="text" id="result" name="result"> <input required type="text" id="name" name="name">
<br> <label for="result">Antwort:</label>
<button type="submit">Abgeben</button> <input required type="text" id="result" name="result">
<button type="submit">Submit</button>
</form> </form>
</body> </body>
</html> </html>

View File

@ -5,10 +5,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Willkommen</title> <title>Willkommen</title>
</head> </head>
<body> <body style="color: white; background: #0f0f23; font-family: 'Source Code Pro', monospace;">
<img alt="" src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExbzl2b2NrZGxjdjl2cTFtMnY2N2tqOTVsZmE5Y2d2ejI0dDF3Y2ZiaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Ae7SI3LoPYj8Q/giphy.webp"/>
<h1>Herzlich Willkommen</h1> <h1>Herzlich Willkommen</h1>
* Wann <p>Schön, dass du es geschafft hast. Ich hoffe, du hattest etwas Spaß und hast nicht allzu lange gebraucht. Aber es hat sich gelohnt.</p>
* Wo <p><a style="color: yellow" href="https://forms.gle/Dx5fPXtd5J9fuir66 ">Hier</a> kannst du dich zurückmelden. Bitte bis zum 24.12. ausfüllen.</p>
* Rückmeldung <p>
Viele Grüße </br>
Daniel & Arne
</p>
<p>PS: Am 3.1. gibt es keine Türsteher mehr.</p>
</body> </body>
</html> </html>

View File

@ -7,8 +7,6 @@ import (
"time" "time"
) )
const rateLimit = time.Second * 3 // a call each 3 second
// Client is an interface that calls something with a payload. // Client is an interface that calls something with a payload.
type Client interface { type Client interface {
Call(*Payload) Call(*Payload)
@ -28,7 +26,7 @@ func CallFunction(ctx context.Context, client Client, payload *Payload, throttle
client.Call(payload) client.Call(payload)
} }
func CreateThrottle(ctx context.Context, burstLimit int) <-chan time.Time { func CreateThrottle(ctx context.Context, burstLimit int, rateLimit time.Duration) <-chan time.Time {
throttle := make(chan time.Time, burstLimit) throttle := make(chan time.Time, burstLimit)
for i := 0; i < burstLimit; i++ { for i := 0; i < burstLimit; i++ {
throttle <- time.Now() throttle <- time.Now()
@ -50,7 +48,6 @@ func CreateThrottle(ctx context.Context, burstLimit int) <-chan time.Time {
} }
default: default:
{ {
fmt.Println("Dropping bucket")
} }
} }
} }