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("

%s

\n
\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", item.Description, elem.Post, media.File) } } item.Description = fmt.Sprintf("%s\n
", 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 }