diff --git a/gecho.go b/gecho.go new file mode 100644 index 0000000..c9ca388 --- /dev/null +++ b/gecho.go @@ -0,0 +1,62 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +// handler generates the echo server response +func handler(l int) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + defer C.Add() + if !serve(l) { + w.WriteHeader(http.StatusInternalServerError) + return + } + if r.Header.Get("Content-Type") == "application/json" { + v := make(map[string]interface{}) + err := json.NewDecoder(r.Body).Decode(&v) + if err != nil { + http.Error(w, "why did you do that?", http.StatusInternalServerError) + return + } + fmt.Fprintf(w, "%s", v) + return + } + v, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Error reading body", http.StatusBadRequest) + } + if r.Header.Get("Reverse") == "true" { + v = reverse(v) + } + fmt.Fprintf(w, "%s", v) + } +} + +// httpHealth is a bad implementation of a health check +func httpHealth(l int) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !serve(l) { + http.Error(w, fmt.Sprintf(`{"status":"FAIL","requests":"%v"}`, C.Get()), http.StatusInternalServerError) + return + } + fmt.Fprintf(w, `{"status":"ok","requests":"%v"}`, C.Get()) + } +} + +// reset resets the request counter +func reset(rt string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + t := r.FormValue("TOKEN") + if len(t) == 0 || t != rt { + http.Error(w, "Bad request, invalid token", http.StatusBadRequest) + return + } + C.Reset() + fmt.Fprintf(w, `{"status":"ok","requests":"%v"}`, C.Get()) + } +} diff --git a/main.go b/main.go index cada741..9d5bcd2 100644 --- a/main.go +++ b/main.go @@ -1,139 +1,14 @@ package main import ( - "encoding/json" - "fmt" - "io" "log" "net/http" "os" - "strconv" - "sync" "github.com/gorilla/handlers" "github.com/gorilla/mux" ) -// Counter mutex for counter -type counter struct { - mu sync.Mutex - n int -} - -// Global counter -var C counter - -// Add value to counter -func (c *counter) Add() { - c.mu.Lock() - c.n++ - c.mu.Unlock() -} - -// Get value from counter -func (c *counter) Get() int { - c.mu.Lock() - n := c.n - c.mu.Unlock() - return n -} - -// Reset counter -func (c *counter) Reset() { - c.mu.Lock() - c.n = 0 - c.mu.Unlock() -} - -// getenv reads an environment variable named k and returns it as type D -func getenv[D ~string | int](k string, d D) D { - v := os.Getenv(k) - if len(v) == 0 { - return d - } - var r any - switch any(d).(type) { - case string: - r = v - case int: - i, err := strconv.Atoi(v) - if err != nil { - log.Fatalf("Invalid Value, %s not a valid integer", k) - } - r = i - default: - log.Fatalf("Invalid Value, %T not valid", k) - } - return r.(D) -} - -// serve evaluates if the limit of requests is reached -func serve(l int) bool { - return C.Get() < l -} - -// reverse returns a reversed byte array of c -func reverse[C ~[]E, E any](c C) C { - for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 { - c[i], c[j] = c[j], c[i] - } - return c -} - -// handler generates the echo server response -func handler(l int) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - defer C.Add() - if !serve(l) { - w.WriteHeader(http.StatusInternalServerError) - return - } - if r.Header.Get("Content-Type") == "application/json" { - v := make(map[string]interface{}) - err := json.NewDecoder(r.Body).Decode(&v) - if err != nil { - http.Error(w, "why did you do that?", http.StatusInternalServerError) - return - } - fmt.Fprintf(w, "%s", v) - return - } - v, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, "Error reading body", http.StatusBadRequest) - } - if r.Header.Get("Reverse") == "true" { - v = reverse(v) - } - fmt.Fprintf(w, "%s", v) - } -} - -// httpHealth is a bad implementation of a health check -func httpHealth(l int) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - if !serve(l) { - http.Error(w, fmt.Sprintf(`{"status":"FAIL","requests":"%v"}`, C.Get()), http.StatusInternalServerError) - return - } - fmt.Fprintf(w, `{"status":"ok","requests":"%v"}`, C.Get()) - } -} - -// reset resets the request counter -func reset(rt string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - t := r.FormValue("TOKEN") - if len(t) == 0 || t != rt { - http.Error(w, "Bad request, invalid token", http.StatusBadRequest) - return - } - C.Reset() - fmt.Fprintf(w, `{"status":"ok","requests":"%v"}`, C.Get()) - } -} - func main() { l := getenv("MAX_REQUESTS", 500) t := getenv("TOKEN", "token") diff --git a/tools.go b/tools.go new file mode 100644 index 0000000..52d8420 --- /dev/null +++ b/tools.go @@ -0,0 +1,74 @@ +package main + +import ( + "log" + "os" + "strconv" + "sync" +) + +// Counter mutex for counter +type counter struct { + mu sync.Mutex + n int +} + +// Global counter +var C counter + +// Add value to counter +func (c *counter) Add() { + c.mu.Lock() + c.n++ + c.mu.Unlock() +} + +// Get value from counter +func (c *counter) Get() int { + c.mu.Lock() + n := c.n + c.mu.Unlock() + return n +} + +// Reset counter +func (c *counter) Reset() { + c.mu.Lock() + c.n = 0 + c.mu.Unlock() +} + +// serve evaluates if the limit of requests is reached +func serve(l int) bool { + return C.Get() < l +} + +// reverse returns a reversed byte array of c +func reverse[C ~[]E, E any](c C) C { + for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 { + c[i], c[j] = c[j], c[i] + } + return c +} + +// getenv reads an environment variable named k and returns it as type D +func getenv[D ~string | int](k string, d D) D { + v := os.Getenv(k) + if len(v) == 0 { + return d + } + var r any + switch any(d).(type) { + case string: + r = v + case int: + i, err := strconv.Atoi(v) + if err != nil { + log.Fatalf("Invalid Value, %s not a valid integer", k) + } + r = i + default: + log.Fatalf("Invalid Value, %T not valid", k) + } + return r.(D) +}