mirror of
https://github.com/nkanaev/yarr.git
synced 2026-06-15 12:35:04 +00:00
add storage interface, fix all references
This commit is contained in:
@@ -14,7 +14,7 @@ type Middleware struct {
|
|||||||
Password string
|
Password string
|
||||||
BasePath string
|
BasePath string
|
||||||
Public []string
|
Public []string
|
||||||
DB *storage.Storage
|
DB storage.Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Middleware) Handler(c *router.Context) {
|
func (m *Middleware) Handler(c *router.Context) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/nkanaev/yarr/src/server/auth"
|
"github.com/nkanaev/yarr/src/server/auth"
|
||||||
"github.com/nkanaev/yarr/src/server/router"
|
"github.com/nkanaev/yarr/src/server/router"
|
||||||
"github.com/nkanaev/yarr/src/storage"
|
"github.com/nkanaev/yarr/src/storage"
|
||||||
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FeverGroup struct {
|
type FeverGroup struct {
|
||||||
@@ -61,7 +62,7 @@ func writeFeverJSON(c *router.Context, data map[string]any, lastRefreshed int64)
|
|||||||
c.JSON(http.StatusOK, data)
|
c.JSON(http.StatusOK, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastRefreshedOnTime(feedStates []storage.FeedState) int64 {
|
func getLastRefreshedOnTime(feedStates []model.FeedState) int64 {
|
||||||
var lastRefreshed int64
|
var lastRefreshed int64
|
||||||
for _, state := range feedStates {
|
for _, state := range feedStates {
|
||||||
if state.LastRefreshed.Unix() > lastRefreshed {
|
if state.LastRefreshed.Unix() > lastRefreshed {
|
||||||
@@ -140,7 +141,7 @@ func joinInts(values []int64) string {
|
|||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func feedGroups(db *storage.Storage) []*FeverFeedsGroup {
|
func feedGroups(db storage.Storage) []*FeverFeedsGroup {
|
||||||
feeds := db.ListFeeds()
|
feeds := db.ListFeeds()
|
||||||
|
|
||||||
groupFeeds := make(map[int64][]int64)
|
groupFeeds := make(map[int64][]int64)
|
||||||
@@ -176,7 +177,7 @@ func (s *Server) feverGroupsHandler(c *router.Context) {
|
|||||||
func (s *Server) feverFeedsHandler(c *router.Context) {
|
func (s *Server) feverFeedsHandler(c *router.Context) {
|
||||||
feeds := s.db.ListFeeds()
|
feeds := s.db.ListFeeds()
|
||||||
states, _ := s.db.ListFeedStates()
|
states, _ := s.db.ListFeedStates()
|
||||||
statesMap := make(map[int64]storage.FeedState)
|
statesMap := make(map[int64]model.FeedState)
|
||||||
for _, state := range states {
|
for _, state := range states {
|
||||||
statesMap[state.FeedID] = state
|
statesMap[state.FeedID] = state
|
||||||
}
|
}
|
||||||
@@ -230,7 +231,7 @@ func (s *Server) feverFaviconsHandler(c *router.Context) {
|
|||||||
const listLimit = 50
|
const listLimit = 50
|
||||||
|
|
||||||
func (s *Server) feverItemsHandler(c *router.Context) {
|
func (s *Server) feverItemsHandler(c *router.Context) {
|
||||||
filter := storage.ItemFilter{}
|
filter := model.ItemFilter{}
|
||||||
query := c.Req.URL.Query()
|
query := c.Req.URL.Query()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@@ -262,11 +263,11 @@ func (s *Server) feverItemsHandler(c *router.Context) {
|
|||||||
time := date.Unix()
|
time := date.Unix()
|
||||||
|
|
||||||
isSaved := 0
|
isSaved := 0
|
||||||
if item.Status == storage.STARRED {
|
if item.Status == model.STARRED {
|
||||||
isSaved = 1
|
isSaved = 1
|
||||||
}
|
}
|
||||||
isRead := 0
|
isRead := 0
|
||||||
if item.Status == storage.READ {
|
if item.Status == model.READ {
|
||||||
isRead = 1
|
isRead = 1
|
||||||
}
|
}
|
||||||
feverItems[i] = FeverItem{
|
feverItems[i] = FeverItem{
|
||||||
@@ -299,10 +300,10 @@ func (s *Server) feverLinksHandler(c *router.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) feverUnreadItemIDsHandler(c *router.Context) {
|
func (s *Server) feverUnreadItemIDsHandler(c *router.Context) {
|
||||||
status := storage.UNREAD
|
status := model.UNREAD
|
||||||
itemIds := make([]int64, 0)
|
itemIds := make([]int64, 0)
|
||||||
|
|
||||||
itemFilter := storage.ItemFilter{
|
itemFilter := model.ItemFilter{
|
||||||
Status: &status,
|
Status: &status,
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
@@ -322,10 +323,10 @@ func (s *Server) feverUnreadItemIDsHandler(c *router.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) feverSavedItemIDsHandler(c *router.Context) {
|
func (s *Server) feverSavedItemIDsHandler(c *router.Context) {
|
||||||
status := storage.STARRED
|
status := model.STARRED
|
||||||
itemIds := make([]int64, 0)
|
itemIds := make([]int64, 0)
|
||||||
|
|
||||||
itemFilter := storage.ItemFilter{
|
itemFilter := model.ItemFilter{
|
||||||
Status: &status,
|
Status: &status,
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
@@ -353,16 +354,16 @@ func (s *Server) feverMarkHandler(c *router.Context) {
|
|||||||
|
|
||||||
switch c.Req.Form.Get("mark") {
|
switch c.Req.Form.Get("mark") {
|
||||||
case "item":
|
case "item":
|
||||||
var status storage.ItemStatus
|
var status model.ItemStatus
|
||||||
switch c.Req.Form.Get("as") {
|
switch c.Req.Form.Get("as") {
|
||||||
case "read":
|
case "read":
|
||||||
status = storage.READ
|
status = model.READ
|
||||||
case "unread":
|
case "unread":
|
||||||
status = storage.UNREAD
|
status = model.UNREAD
|
||||||
case "saved":
|
case "saved":
|
||||||
status = storage.STARRED
|
status = model.STARRED
|
||||||
case "unsaved":
|
case "unsaved":
|
||||||
status = storage.READ
|
status = model.READ
|
||||||
default:
|
default:
|
||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -372,7 +373,7 @@ func (s *Server) feverMarkHandler(c *router.Context) {
|
|||||||
if c.Req.Form.Get("as") != "read" {
|
if c.Req.Form.Get("as") != "read" {
|
||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
markFilter := storage.MarkFilter{FeedID: &id}
|
markFilter := model.MarkFilter{FeedID: &id}
|
||||||
x, _ := strconv.ParseInt(c.Req.Form.Get("before"), 10, 64)
|
x, _ := strconv.ParseInt(c.Req.Form.Get("before"), 10, 64)
|
||||||
if x > 0 {
|
if x > 0 {
|
||||||
before := time.Unix(x, 0).UTC()
|
before := time.Unix(x, 0).UTC()
|
||||||
@@ -383,7 +384,7 @@ func (s *Server) feverMarkHandler(c *router.Context) {
|
|||||||
if c.Req.Form.Get("as") != "read" {
|
if c.Req.Form.Get("as") != "read" {
|
||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
markFilter := storage.MarkFilter{}
|
markFilter := model.MarkFilter{}
|
||||||
if id > 0 {
|
if id > 0 {
|
||||||
markFilter.FolderID = &id
|
markFilter.FolderID = &id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import "github.com/nkanaev/yarr/src/storage"
|
import "github.com/nkanaev/yarr/src/storage/model"
|
||||||
|
|
||||||
type ItemUpdateForm struct {
|
type ItemUpdateForm struct {
|
||||||
Status *storage.ItemStatus `json:"status,omitempty"`
|
Status *model.ItemStatus `json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FolderCreateForm struct {
|
type FolderCreateForm struct {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
"github.com/nkanaev/yarr/src/server/gzip"
|
"github.com/nkanaev/yarr/src/server/gzip"
|
||||||
"github.com/nkanaev/yarr/src/server/opml"
|
"github.com/nkanaev/yarr/src/server/opml"
|
||||||
"github.com/nkanaev/yarr/src/server/router"
|
"github.com/nkanaev/yarr/src/server/router"
|
||||||
"github.com/nkanaev/yarr/src/storage"
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
"github.com/nkanaev/yarr/src/worker"
|
"github.com/nkanaev/yarr/src/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ func (s *Server) handleFolder(c *router.Context) {
|
|||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.db.UpdateFolder(id, storage.UpdateFolderParams{
|
s.db.UpdateFolder(id, model.UpdateFolderParams{
|
||||||
Title: body.Title,
|
Title: body.Title,
|
||||||
IsExpanded: body.IsExpanded,
|
IsExpanded: body.IsExpanded,
|
||||||
})
|
})
|
||||||
@@ -248,7 +248,7 @@ func (s *Server) handleFeedList(c *router.Context) {
|
|||||||
map[string]any{"status": "multiple", "choice": result.Sources},
|
map[string]any{"status": "multiple", "choice": result.Sources},
|
||||||
)
|
)
|
||||||
case result.Feed != nil:
|
case result.Feed != nil:
|
||||||
feed := s.db.CreateFeed(storage.CreateFeedParams{
|
feed := s.db.CreateFeed(model.CreateFeedParams{
|
||||||
Title: result.Feed.Title,
|
Title: result.Feed.Title,
|
||||||
Link: result.Feed.SiteURL,
|
Link: result.Feed.SiteURL,
|
||||||
FeedLink: result.FeedLink,
|
FeedLink: result.FeedLink,
|
||||||
@@ -288,7 +288,7 @@ func (s *Server) handleFeed(c *router.Context) {
|
|||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
params := storage.UpdateFeedParams{}
|
params := model.UpdateFeedParams{}
|
||||||
if title, ok := body["title"]; ok {
|
if title, ok := body["title"]; ok {
|
||||||
if reflect.TypeOf(title).Kind() == reflect.String {
|
if reflect.TypeOf(title).Kind() == reflect.String {
|
||||||
t := title.(string)
|
t := title.(string)
|
||||||
@@ -297,10 +297,10 @@ func (s *Server) handleFeed(c *router.Context) {
|
|||||||
}
|
}
|
||||||
if f_id, ok := body["folder_id"]; ok {
|
if f_id, ok := body["folder_id"]; ok {
|
||||||
if f_id == nil {
|
if f_id == nil {
|
||||||
params.FolderID = storage.SetNullable[int64](nil)
|
params.FolderID = model.SetNullable[int64](nil)
|
||||||
} else if reflect.TypeOf(f_id).Kind() == reflect.Float64 {
|
} else if reflect.TypeOf(f_id).Kind() == reflect.Float64 {
|
||||||
folderId := int64(f_id.(float64))
|
folderId := int64(f_id.(float64))
|
||||||
params.FolderID = storage.SetNullable(&folderId)
|
params.FolderID = model.SetNullable(&folderId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if link, ok := body["feed_link"]; ok {
|
if link, ok := body["feed_link"]; ok {
|
||||||
@@ -366,7 +366,7 @@ func (s *Server) handleItemList(c *router.Context) {
|
|||||||
perPage := 20
|
perPage := 20
|
||||||
query := c.Req.URL.Query()
|
query := c.Req.URL.Query()
|
||||||
|
|
||||||
filter := storage.ItemFilter{}
|
filter := model.ItemFilter{}
|
||||||
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
||||||
filter.FolderID = &folderID
|
filter.FolderID = &folderID
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ func (s *Server) handleItemList(c *router.Context) {
|
|||||||
filter.After = &after
|
filter.After = &after
|
||||||
}
|
}
|
||||||
if status := query.Get("status"); len(status) != 0 {
|
if status := query.Get("status"); len(status) != 0 {
|
||||||
statusValue := storage.StatusValues[status]
|
statusValue := model.StatusValues[status]
|
||||||
filter.Status = &statusValue
|
filter.Status = &statusValue
|
||||||
}
|
}
|
||||||
if search := query.Get("search"); len(search) != 0 {
|
if search := query.Get("search"); len(search) != 0 {
|
||||||
@@ -403,7 +403,7 @@ func (s *Server) handleItemList(c *router.Context) {
|
|||||||
"has_more": hasMore,
|
"has_more": hasMore,
|
||||||
})
|
})
|
||||||
} else if c.Req.Method == "PUT" {
|
} else if c.Req.Method == "PUT" {
|
||||||
filter := storage.MarkFilter{}
|
filter := model.MarkFilter{}
|
||||||
|
|
||||||
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
||||||
filter.FolderID = &folderID
|
filter.FolderID = &folderID
|
||||||
@@ -422,7 +422,7 @@ func (s *Server) handleSettings(c *router.Context) {
|
|||||||
if c.Req.Method == "GET" {
|
if c.Req.Method == "GET" {
|
||||||
c.JSON(http.StatusOK, s.db.GetSettings())
|
c.JSON(http.StatusOK, s.db.GetSettings())
|
||||||
} else if c.Req.Method == "PUT" {
|
} else if c.Req.Method == "PUT" {
|
||||||
var params storage.UpdateSettingsParams
|
var params model.UpdateSettingsParams
|
||||||
if err := json.NewDecoder(c.Req.Body).Decode(¶ms); err != nil {
|
if err := json.NewDecoder(c.Req.Body).Decode(¶ms); err != nil {
|
||||||
c.Out.WriteHeader(http.StatusBadRequest)
|
c.Out.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -452,7 +452,7 @@ func (s *Server) handleOPMLImport(c *router.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, f := range doc.Feeds {
|
for _, f := range doc.Feeds {
|
||||||
s.db.CreateFeed(storage.CreateFeedParams{
|
s.db.CreateFeed(model.CreateFeedParams{
|
||||||
Title: f.Title,
|
Title: f.Title,
|
||||||
Link: f.SiteUrl,
|
Link: f.SiteUrl,
|
||||||
FeedLink: f.FeedUrl,
|
FeedLink: f.FeedUrl,
|
||||||
@@ -461,7 +461,7 @@ func (s *Server) handleOPMLImport(c *router.Context) {
|
|||||||
for _, f := range doc.Folders {
|
for _, f := range doc.Folders {
|
||||||
folder := s.db.CreateFolder(f.Title)
|
folder := s.db.CreateFolder(f.Title)
|
||||||
for _, ff := range f.AllFeeds() {
|
for _, ff := range f.AllFeeds() {
|
||||||
s.db.CreateFeed(storage.CreateFeedParams{
|
s.db.CreateFeed(model.CreateFeedParams{
|
||||||
Title: ff.Title,
|
Title: ff.Title,
|
||||||
Link: ff.SiteUrl,
|
Link: ff.SiteUrl,
|
||||||
FeedLink: ff.FeedUrl,
|
FeedLink: ff.FeedUrl,
|
||||||
@@ -485,7 +485,7 @@ func (s *Server) handleOPMLExport(c *router.Context) {
|
|||||||
|
|
||||||
doc := opml.Folder{}
|
doc := opml.Folder{}
|
||||||
|
|
||||||
feedsByFolderID := make(map[int64][]*storage.Feed)
|
feedsByFolderID := make(map[int64][]*model.Feed)
|
||||||
for _, feed := range s.db.ListFeeds() {
|
for _, feed := range s.db.ListFeeds() {
|
||||||
if feed.FolderId == nil {
|
if feed.FolderId == nil {
|
||||||
doc.Feeds = append(doc.Feeds, opml.Feed{
|
doc.Feeds = append(doc.Feeds, opml.Feed{
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nkanaev/yarr/src/storage"
|
"github.com/nkanaev/yarr/src/storage"
|
||||||
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStatic(t *testing.T) {
|
func TestStatic(t *testing.T) {
|
||||||
@@ -79,8 +80,8 @@ func TestFeedIcons(t *testing.T) {
|
|||||||
log.SetOutput(io.Discard)
|
log.SetOutput(io.Discard)
|
||||||
db, _ := storage.New(":memory:")
|
db, _ := storage.New(":memory:")
|
||||||
icon := []byte("test")
|
icon := []byte("test")
|
||||||
feed := db.CreateFeed(storage.CreateFeedParams{})
|
feed := db.CreateFeed(model.CreateFeedParams{})
|
||||||
db.UpdateFeed(feed.Id, storage.UpdateFeedParams{Icon: storage.SetNullable(&icon)})
|
db.UpdateFeed(feed.Id, model.UpdateFeedParams{Icon: model.SetNullable(&icon)})
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Addr string
|
Addr string
|
||||||
db *storage.Storage
|
db storage.Storage
|
||||||
worker *worker.Worker
|
worker *worker.Worker
|
||||||
cache map[string]any
|
cache map[string]any
|
||||||
cache_mutex *sync.Mutex
|
cache_mutex *sync.Mutex
|
||||||
@@ -29,7 +29,7 @@ type Server struct {
|
|||||||
KeyFile string
|
KeyFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(db *storage.Storage, addr string) *Server {
|
func NewServer(db storage.Storage, addr string) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
db: db,
|
db: db,
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package factory
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nkanaev/yarr/src/storage/model"
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
|
"github.com/nkanaev/yarr/src/storage/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
Close() error
|
Close() error
|
||||||
Migrate() error
|
|
||||||
CountItems() int
|
CountItems() int
|
||||||
CreateFeed(params model.CreateFeedParams) *model.Feed
|
CreateFeed(params model.CreateFeedParams) *model.Feed
|
||||||
CreateFolder(title string) *model.Folder
|
CreateFolder(title string) *model.Folder
|
||||||
@@ -30,3 +30,7 @@ type Storage interface {
|
|||||||
UpdateItemStatus(item_id int64, status model.ItemStatus) bool
|
UpdateItemStatus(item_id int64, status model.ItemStatus) bool
|
||||||
UpdateSettings(params model.UpdateSettingsParams) bool
|
UpdateSettings(params model.UpdateSettingsParams) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func New(path string) (Storage, error) {
|
||||||
|
return sqlite.New(path)
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/nkanaev/yarr/src/content/scraper"
|
"github.com/nkanaev/yarr/src/content/scraper"
|
||||||
"github.com/nkanaev/yarr/src/parser"
|
"github.com/nkanaev/yarr/src/parser"
|
||||||
"github.com/nkanaev/yarr/src/storage"
|
"github.com/nkanaev/yarr/src/storage"
|
||||||
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
"golang.org/x/net/html/charset"
|
"golang.org/x/net/html/charset"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -139,28 +140,28 @@ func findFavicon(siteUrl, feedUrl string) (*[]byte, error) {
|
|||||||
return &emptyIcon, nil
|
return &emptyIcon, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertItems(items []parser.Item, feed storage.Feed) []storage.Item {
|
func ConvertItems(items []parser.Item, feed model.Feed) []model.Item {
|
||||||
result := make([]storage.Item, len(items))
|
result := make([]model.Item, len(items))
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
mediaLinks := make(storage.MediaLinks, 0)
|
mediaLinks := make(model.MediaLinks, 0)
|
||||||
for _, link := range item.MediaLinks {
|
for _, link := range item.MediaLinks {
|
||||||
mediaLinks = append(mediaLinks, storage.MediaLink(link))
|
mediaLinks = append(mediaLinks, model.MediaLink(link))
|
||||||
}
|
}
|
||||||
result[i] = storage.Item{
|
result[i] = model.Item{
|
||||||
GUID: item.GUID,
|
GUID: item.GUID,
|
||||||
FeedId: feed.Id,
|
FeedId: feed.Id,
|
||||||
Title: item.Title,
|
Title: item.Title,
|
||||||
Link: item.URL,
|
Link: item.URL,
|
||||||
Content: item.Content,
|
Content: item.Content,
|
||||||
Date: item.Date,
|
Date: item.Date,
|
||||||
Status: storage.UNREAD,
|
Status: model.UNREAD,
|
||||||
MediaLinks: mediaLinks,
|
MediaLinks: mediaLinks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func listItems(f storage.Feed, db *storage.Storage) ([]storage.Item, error) {
|
func listItems(f model.Feed, db storage.Storage) ([]model.Item, error) {
|
||||||
lmod := ""
|
lmod := ""
|
||||||
etag := ""
|
etag := ""
|
||||||
if state, _ := db.GetFeedState(f.Id); state != nil {
|
if state, _ := db.GetFeedState(f.Id); state != nil {
|
||||||
@@ -193,7 +194,7 @@ func listItems(f storage.Feed, db *storage.Storage) ([]storage.Item, error) {
|
|||||||
etag = res.Header.Get("Etag")
|
etag = res.Header.Get("Etag")
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
if lmod != "" || etag != "" {
|
if lmod != "" || etag != "" {
|
||||||
db.UpdateFeedState(f.Id, storage.UpdateFeedStateParams{
|
db.UpdateFeedState(f.Id, model.UpdateFeedStateParams{
|
||||||
HTTPLastModified: &lmod,
|
HTTPLastModified: &lmod,
|
||||||
HTTPEtag: &etag,
|
HTTPEtag: &etag,
|
||||||
LastRefreshed: &now,
|
LastRefreshed: &now,
|
||||||
|
|||||||
@@ -7,19 +7,20 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nkanaev/yarr/src/storage"
|
"github.com/nkanaev/yarr/src/storage"
|
||||||
|
"github.com/nkanaev/yarr/src/storage/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const NUM_WORKERS = 4
|
const NUM_WORKERS = 4
|
||||||
|
|
||||||
type Worker struct {
|
type Worker struct {
|
||||||
db *storage.Storage
|
db storage.Storage
|
||||||
pending *int32
|
pending *int32
|
||||||
refresh *time.Ticker
|
refresh *time.Ticker
|
||||||
reflock sync.Mutex
|
reflock sync.Mutex
|
||||||
stopper chan bool
|
stopper chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorker(db *storage.Storage) *Worker {
|
func NewWorker(db storage.Storage) *Worker {
|
||||||
pending := int32(0)
|
pending := int32(0)
|
||||||
return &Worker{db: db, pending: &pending}
|
return &Worker{db: db, pending: &pending}
|
||||||
}
|
}
|
||||||
@@ -39,13 +40,13 @@ func (w *Worker) StartFeedCleaner() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) FindFeedFavicon(feed storage.Feed) {
|
func (w *Worker) FindFeedFavicon(feed model.Feed) {
|
||||||
icon, err := findFavicon(feed.Link, feed.FeedLink)
|
icon, err := findFavicon(feed.Link, feed.FeedLink)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to find favicon for %s (%s): %s", feed.FeedLink, feed.Link, err)
|
log.Printf("Failed to find favicon for %s (%s): %s", feed.FeedLink, feed.Link, err)
|
||||||
}
|
}
|
||||||
if icon != nil {
|
if icon != nil {
|
||||||
w.db.UpdateFeed(feed.Id, storage.UpdateFeedParams{Icon: storage.SetNullable(icon)})
|
w.db.UpdateFeed(feed.Id, model.UpdateFeedParams{Icon: model.SetNullable(icon)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +100,11 @@ func (w *Worker) RefreshFeeds() {
|
|||||||
go w.refresher(feeds)
|
go w.refresher(feeds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) refresher(feeds []storage.Feed) {
|
func (w *Worker) refresher(feeds []model.Feed) {
|
||||||
// w.db.ResetFeedErrors()
|
// w.db.ResetFeedErrors()
|
||||||
|
|
||||||
srcqueue := make(chan storage.Feed, len(feeds))
|
srcqueue := make(chan model.Feed, len(feeds))
|
||||||
dstqueue := make(chan []storage.Item)
|
dstqueue := make(chan []model.Item)
|
||||||
|
|
||||||
for range NUM_WORKERS {
|
for range NUM_WORKERS {
|
||||||
go w.worker(srcqueue, dstqueue)
|
go w.worker(srcqueue, dstqueue)
|
||||||
@@ -125,15 +126,15 @@ func (w *Worker) refresher(feeds []storage.Feed) {
|
|||||||
log.Printf("Finished refreshing %d feeds", len(feeds))
|
log.Printf("Finished refreshing %d feeds", len(feeds))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) worker(srcqueue <-chan storage.Feed, dstqueue chan<- []storage.Item) {
|
func (w *Worker) worker(srcqueue <-chan model.Feed, dstqueue chan<- []model.Item) {
|
||||||
for feed := range srcqueue {
|
for feed := range srcqueue {
|
||||||
empty := ""
|
empty := ""
|
||||||
w.db.UpdateFeedState(feed.Id, storage.UpdateFeedStateParams{LastError: &empty})
|
w.db.UpdateFeedState(feed.Id, model.UpdateFeedStateParams{LastError: &empty})
|
||||||
|
|
||||||
items, err := listItems(feed, w.db)
|
items, err := listItems(feed, w.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg := err.Error()
|
errMsg := err.Error()
|
||||||
w.db.UpdateFeedState(feed.Id, storage.UpdateFeedStateParams{LastError: &errMsg})
|
w.db.UpdateFeedState(feed.Id, model.UpdateFeedStateParams{LastError: &errMsg})
|
||||||
}
|
}
|
||||||
if len(items) > 0 && !feed.HasIcon {
|
if len(items) > 0 && !feed.HasIcon {
|
||||||
w.FindFeedFavicon(feed)
|
w.FindFeedFavicon(feed)
|
||||||
|
|||||||
Reference in New Issue
Block a user