mirror of
https://github.com/nkanaev/yarr.git
synced 2025-05-24 00:33:14 +00:00
cache feed icons
This commit is contained in:
parent
214c7aacfc
commit
f38dcfba3b
@ -1,12 +1,15 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/assets"
|
||||
@ -143,20 +146,51 @@ func (s *Server) handleFeedErrors(c *router.Context) {
|
||||
c.JSON(http.StatusOK, errors)
|
||||
}
|
||||
|
||||
type feedicon struct {
|
||||
ctype string
|
||||
bytes []byte
|
||||
etag string
|
||||
}
|
||||
|
||||
func (s *Server) handleFeedIcon(c *router.Context) {
|
||||
// TODO: caching
|
||||
id, err := c.VarInt64("id")
|
||||
if err != nil {
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
feed := s.db.GetFeed(id)
|
||||
if feed != nil && feed.Icon != nil {
|
||||
c.Out.Header().Set("Content-Type", http.DetectContentType(*feed.Icon))
|
||||
c.Out.Write(*feed.Icon)
|
||||
} else {
|
||||
c.Out.WriteHeader(http.StatusNotFound)
|
||||
|
||||
cachekey := "icon:" + strconv.FormatInt(id, 10)
|
||||
cachedat := s.cache[cachekey]
|
||||
if cachedat == nil {
|
||||
feed := s.db.GetFeed(id)
|
||||
if feed == nil || feed.Icon == nil {
|
||||
c.Out.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
hash := md5.New()
|
||||
hash.Write(*feed.Icon)
|
||||
|
||||
etag := fmt.Sprintf("%x", hash.Sum(nil))[:16]
|
||||
|
||||
cachedat = feedicon{
|
||||
ctype: http.DetectContentType(*feed.Icon),
|
||||
bytes: *(*feed).Icon,
|
||||
etag: etag,
|
||||
}
|
||||
s.cache[cachekey] = cachedat
|
||||
}
|
||||
|
||||
icon := cachedat.(feedicon)
|
||||
|
||||
if c.Req.Header.Get("If-None-Match") == icon.etag {
|
||||
c.Out.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
|
||||
c.Out.Header().Set("Content-Type", icon.ctype)
|
||||
c.Out.Header().Set("Etag", icon.etag)
|
||||
c.Out.Write(icon.bytes)
|
||||
}
|
||||
|
||||
func (s *Server) handleFeedList(c *router.Context) {
|
||||
@ -191,7 +225,7 @@ func (s *Server) handleFeedList(c *router.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"status": "success",
|
||||
"feed": feed,
|
||||
"feed": feed,
|
||||
})
|
||||
default:
|
||||
c.JSON(http.StatusOK, map[string]string{"status": "notfound"})
|
||||
|
@ -1,10 +1,13 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/nkanaev/yarr/src/storage"
|
||||
@ -71,3 +74,41 @@ func TestIndexGzipped(t *testing.T) {
|
||||
t.Errorf("invalid content-type header: %#v", response.Header.Get("content-type"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFeedIcons(t *testing.T) {
|
||||
log.SetOutput(io.Discard)
|
||||
db, _ := storage.New(":memory:")
|
||||
icon := []byte("test")
|
||||
feed := db.CreateFeed("", "", "", "", nil)
|
||||
db.UpdateFeedIcon(feed.Id, &icon)
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
url := fmt.Sprintf("/api/feeds/%d/icon", feed.Id)
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
|
||||
handler := NewServer(db, "127.0.0.1:8000").handler()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
response := recorder.Result()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
t.Fatal()
|
||||
}
|
||||
body, _ := io.ReadAll(response.Body)
|
||||
if !reflect.DeepEqual(body, icon) {
|
||||
t.Fatal()
|
||||
}
|
||||
if response.Header.Get("Etag") == "" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
recorder2 := httptest.NewRecorder()
|
||||
request2 := httptest.NewRequest("GET", url, nil)
|
||||
request2.Header.Set("If-None-Match", response.Header.Get("Etag"))
|
||||
handler.ServeHTTP(recorder2, request2)
|
||||
response2 := recorder2.Result()
|
||||
|
||||
if response2.StatusCode != http.StatusNotModified {
|
||||
t.Fatal("got", response2.StatusCode)
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ type Server struct {
|
||||
Addr string
|
||||
db *storage.Storage
|
||||
worker *worker.Worker
|
||||
cache map[string]interface{}
|
||||
|
||||
BasePath string
|
||||
|
||||
@ -28,6 +29,7 @@ func NewServer(db *storage.Storage, addr string) *Server {
|
||||
db: db,
|
||||
Addr: addr,
|
||||
worker: worker.NewWorker(db),
|
||||
cache: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user