Idea
- In-memory Cache Server to store named byte sequences
- HTTP Server to serve the cache
- Memory and load are note handled, also no content types
Example
The cache server package
package cache
import (
"net/http"
"sync"
)
// Handler provides a simple in-memory cache server. Cache is done
// via a map of string to []byte. The sync.RWMutex is used to ensure that
// the cache is thread-safe.
type Handler struct {
mu sync.RWMutex
cache map[string][]byte
}
// NewHandler creates the cache handler. It's needed to create the
// map of string to []byte.
func NewHandler() *Handler {
return &Handler{
cache: make(map[string][]byte),
}
}
// ServeHTTP implements the http.Handler interface. It only handles
// two HTTP methods: GET and POST. The work itself is done by
// private helper methods.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Map HTTP methods to individual methods.
switch r.Method {
case http.MethodGet:
h.handleGet(w, r)
case http.MethodPost:
h.handlePost(w, r)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
// handleGet handles GET requests. If the path can be found in the cache,
// its data is returned. Otherwise, the response is set to 404. Only
// read lock is needed.
func (h *Handler) handleGet(w http.ResponseWriter, r *http.Request) {
h.mu.RLock()
defer h.mu.RUnlock()
// Check if path is known.
data, ok := h.cache[r.URL.Path]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
w.WriteHeader(http.StatusOK)
w.Write(data)
}
// handlePost handles POST requests. It does not matter if the path is known,
// content will be replaced.
func (h *Handler) handlePost(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
// Simply write/update the variable.
w.WriteHeader(http.StatusOK)
h.cache[r.URL.Path] = r.Body
}
Using the cache server
package main
import (
"log"
"net/http"
"./pkg/cache"
)
// main runs the cache server.
func main() {
h := cache.NewHandler()
err := http.ListenAndServe(":8080", h)
if err != nil {
log.Fatal(err)
}
}