interview/render-2023-10-11/cmd/cache-service/server.go

69 lines
1.6 KiB
Go

package main
import (
"encoding/json"
"log"
"net/http"
"render231011/internal/thestore"
"strconv"
"strings"
"time"
)
type Server struct {
store *thestore.Store
oplog *Oplog
}
func NewServer() Server {
return Server{
store: thestore.NewStore(),
oplog: NewOplog(),
}
}
func (server Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// todo middleware: rate limit
// todo middleware: timeout requests
// todo: replace with an actual router
if strings.HasPrefix(r.URL.Path, "/event") && r.Method == http.MethodPost {
server.servePostEvent(w, r)
} else if r.URL.Path == "/events" && r.Method == http.MethodGet {
server.serveGetEvents(w, r)
}
}
func (server Server) servePostEvent(w http.ResponseWriter, r *http.Request) {
var newEvent thestore.Event
if err := json.NewDecoder(r.Body).Decode(&newEvent); err != nil {
w.WriteHeader(http.StatusBadRequest)
// todo error msg pls
return
}
// todo check if action==updated service-id already exists
server.store.Push(newEvent)
log.Printf("ingested event %+v", newEvent)
// todo store the op log
server.oplog.Push(newEvent)
}
func (server Server) serveGetEvents(w http.ResponseWriter, r *http.Request) {
// todo my circular queue magic
sinceString := r.URL.Query().Get("since")
sinceInt, err := strconv.ParseInt(sinceString, 10, 64)
if err != nil {
// todo emit helpful err message
w.WriteHeader(http.StatusBadRequest)
return
}
since := time.Unix(sinceInt, 0)
result, ok := server.oplog.Since(since)
if !ok {
result = server.store.Dump()
}
json.NewEncoder(w).Encode(result)
}