Files
podinfo/pkg/api/cache.go
stefanprodan 73b658d711 Add cache API
- implement cache with Redis
- add cache-server to args and config
- add Redis deployment to webapp overlays
2020-05-16 09:53:17 +03:00

94 lines
2.3 KiB
Go

package api
import (
"github.com/gomodule/redigo/redis"
"github.com/gorilla/mux"
"go.uber.org/zap"
"io/ioutil"
"net/http"
"time"
)
// Cache godoc
// @Summary Save payload in cache
// @Description writes the posted content in cache and returns the SHA1 hash of the content
// @Tags HTTP API
// @Accept json
// @Produce json
// @Router /cache [post]
// @Success 200 {object} api.MapResponse
func (s *Server) cacheWriteHandler(w http.ResponseWriter, r *http.Request) {
if s.pool == nil {
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
s.ErrorResponse(w, r, "reading the request body failed", http.StatusBadRequest)
return
}
hash := hash(string(body))
conn := s.pool.Get()
defer conn.Close()
_, err = conn.Do("SET", hash, string(body))
if err != nil {
s.logger.Warn("cache set failed", zap.Error(err))
s.ErrorResponse(w, r, "cache set failed", http.StatusInternalServerError)
return
}
s.JSONResponseCode(w, r, map[string]string{"hash": hash}, http.StatusAccepted)
}
// Cache godoc
// @Summary Get payload from cache
// @Description returns the content from cache if key exists
// @Tags HTTP API
// @Accept json
// @Produce json
// @Router /cache/{hash} [get]
// @Success 200 {string} api.MapResponse
func (s *Server) cacheReadHandler(w http.ResponseWriter, r *http.Request) {
if s.pool == nil {
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
return
}
hash := mux.Vars(r)["hash"]
conn := s.pool.Get()
defer conn.Close()
ok, err := redis.Bool(conn.Do("EXISTS", hash))
if err != nil || !ok {
s.ErrorResponse(w, r, "key not found in cache", http.StatusNotFound)
return
}
data, err := redis.String(conn.Do("GET", hash))
if err != nil {
s.logger.Warn("cache get failed", zap.Error(err))
s.ErrorResponse(w, r, "cache get failed", http.StatusInternalServerError)
return
}
s.JSONResponseCode(w, r, map[string]string{"data": data}, http.StatusAccepted)
}
func (s *Server) startCachePool() {
if s.config.CacheServer != "" {
s.pool = &redis.Pool{
MaxIdle: 3,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", s.config.CacheServer)
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
}
}