igar/storage/entrymap.go

175 lines
3.5 KiB
Go

package storage
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sort"
"sync"
"time"
"github.com/gorilla/feeds"
)
type (
EntryMap struct {
Filename string
modtime time.Time
mapped map[string]*Entry
sorted []*Entry
mu sync.RWMutex
}
entryList []*Entry
)
// entryList
func (list entryList) Len() int { return len(list) }
func (list entryList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
func (list entryList) Less(i, j int) bool {
return time.Time(list[i].Date).After(time.Time(list[j].Date))
}
func (list *EntryMap) modified() (mod bool) {
info, err := os.Stat(list.Filename)
if err == nil {
mod = list.modtime.Before(info.ModTime())
list.modtime = info.ModTime()
} else {
mod = true
}
return
}
func (list *EntryMap) write() (err error) {
data, err := json.MarshalIndent(list.mapped, "", " ")
if err == nil {
err = ioutil.WriteFile(list.Filename, data, 0644)
}
return
}
func (list *EntryMap) read() (err error) {
if list.modified() {
if data, err := ioutil.ReadFile(list.Filename); err == nil {
// read map
list.mapped = make(map[string]*Entry)
err = json.Unmarshal(data, &list.mapped)
// sort list
list.sorted = make([]*Entry, 0, len(list.mapped))
for _, entry := range list.mapped {
list.sorted = append(list.sorted, entry)
}
sort.Sort(entryList(list.sorted))
// assign prev/next
for index, value := range list.sorted {
if index-1 >= 0 {
value.Next = list.sorted[index-1]
}
if index+1 < len(list.sorted) {
value.Prev = list.sorted[index+1]
}
}
}
}
return
}
func (list *EntryMap) GetEntry(uuid string) (result Entry, err error) {
list.mu.Lock()
defer list.mu.Unlock()
if err = list.read(); err == nil {
result = *list.mapped[uuid]
}
return
}
func (list *EntryMap) GetEntries() (result []Entry, err error) {
list.mu.RLock()
defer list.mu.RUnlock()
err = list.read()
if err == nil {
result = make([]Entry, len(list.sorted))
for index, elem := range list.sorted {
result[index] = *elem
}
}
return
}
func (list *EntryMap) GetFeed() (feed *feeds.Feed) {
feed = &feeds.Feed{
Title: "danoloan.es igar",
Link: &feeds.Link{Href: "https://danoloan.es/igar/"},
Description: "bitácora fotográfica de danoloan",
Author: &feeds.Author{Name: "danoloan", Email: "danolo@danoloan.es"},
}
feed.Items = make([]*feeds.Item, 0, list.Len())
elements, err := list.GetEntries()
if err != nil {
for _, elem := range elements {
item := &feeds.Item{
Title: elem.Description,
Link: &feeds.Link{Href: fmt.Sprintf("https://danoloan.es/igar/view?uuid=%s", elem.Post)},
Description: fmt.Sprintf("<p>%s</p>\n<div>\n", elem.Description),
Created: time.Time(elem.Date),
}
for _, media := range elem.Media {
if media.Type == "GraphImage" {
// TODO ruta relativa al proxy
item.Description = fmt.Sprintf("%s\n\t<img src=/igar/img/%s/%s>", item.Description, elem.Post, media.File)
}
}
item.Description = fmt.Sprintf("%s\n</div>", item.Description)
feed.Items = append(feed.Items, item)
}
}
return
}
func (list *EntryMap) Len() int { return len(list.mapped) }
func (list *EntryMap) AddEntry(entry *Entry) (err error) {
list.mu.Lock()
defer list.mu.Unlock()
list.read()
if entry != nil {
list.mapped[entry.Post] = entry
err = list.write()
}
return
}
func (list *EntryMap) RemoveEntry(uuid string) (entry *Entry) {
list.mu.Lock()
defer list.mu.Unlock()
list.read()
entry, ok := list.mapped[uuid]
if ok {
delete(list.mapped, uuid)
}
list.write()
return
}