diff --git a/store/store.go b/store/store.go new file mode 100644 index 0000000..e2362bd --- /dev/null +++ b/store/store.go @@ -0,0 +1,68 @@ +// Package store implements a synchronous in-memory K/V store +// fronted by an HTTP server. +package store + +import ( + "io" + "net/http" + "sync" +) + +type Map struct { + m sync.Map +} + +func New(from map[string]string) *Map { + var m Map + for k, v := range from { + m.Set(k, v) + } + return &m +} + +func (m *Map) Get(k string) (string, bool) { + r, ok := m.m.Load(k) + return r.(string), ok +} + +func (m *Map) Set(k, v string) { + m.m.Store(k, v) +} + +func (m *Map) Delete(k string) { + m.m.Delete(k) +} + +func (m *Map) Router() http.Handler { + r := http.NewServeMux() + r.HandleFunc("GET /{key}", m.get) + r.HandleFunc("PUT /{key}", m.set) + r.HandleFunc("POST /{key}", m.set) + r.HandleFunc("DELETE /{key}", m.delete) + return r +} + +func (m *Map) get(w http.ResponseWriter, r *http.Request) { + k := r.PathValue("key") + v, ok := m.Get(k) + if !ok { + http.Error(w, "not found", http.StatusNotFound) + } + io.WriteString(w, v) +} + +func (m *Map) set(w http.ResponseWriter, r *http.Request) { + k := r.PathValue("key") + b, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + m.Set(k, string(b)) + w.WriteHeader(http.StatusNoContent) +} + +func (m *Map) delete(w http.ResponseWriter, r *http.Request) { + k := r.PathValue("key") + m.Delete(k) + w.WriteHeader(http.StatusNoContent) +}