package main import ( "fmt" "plugin" "time" ) type FeedSource struct { Feeds []*Feed // Plugin Functions getSourceName func() string refreshFeedList func() []map[string]string getFeedUrl func(string, time.Time) (string, error) getFeedDesc func(string, time.Time) (string, error) } func LoadFeedPlugin(p *plugin.Plugin) (*FeedSource, error) { ret := new(FeedSource) feedSourceSymbol, err := p.Lookup("GetSourceName") if err != nil { return nil, err } ret.getSourceName = feedSourceSymbol.(func() string) feedListSymbol, err := p.Lookup("GetFeedList") if err != nil { return nil, err } ret.refreshFeedList = feedListSymbol.(func() []map[string]string) feeds := ret.refreshFeedList() // `feeds` is a []map, each map should contain keys: `slug`, `name`, `author`, `source` for _, f := range feeds { var slug, name, author, source string var ok bool if slug, ok = f["slug"]; !ok { continue } if name, ok = f["name"]; !ok { continue } if author, ok = f["author"]; !ok { continue } if source, ok = f["source"]; !ok { continue } ret.Feeds = append(ret.Feeds, NewFeed(slug, name, author, source)) } feedUrlSymbol, err := p.Lookup("GetFeedUrl") if err != nil { return nil, err } ret.getFeedUrl = feedUrlSymbol.(func(string, time.Time) (string, error)) feedDescSymbol, err := p.Lookup("GetFeedDesc") if err != nil { return nil, err } ret.getFeedDesc = feedDescSymbol.(func(string, time.Time) (string, error)) return ret, nil } func (f *FeedSource) getFeed(slug string) *Feed { for i := range f.Feeds { if f.Feeds[i].Slug == slug { return f.Feeds[i] } } return nil } type Feed struct { Name string Author string Slug string Source string Desc string LastUpdate time.Time } func NewFeed(s, n, a, source string) *Feed { return &Feed{ Name: n, Author: a, Slug: s, Source: source, } } func (f *Feed) GetBucket() []string { return []string{"feeds", f.Source, f.Slug} } func (f *Feed) Update() error { /* dt := time.Now() desc, err := getFeedDesc(f.Source, f.Slug, dt) if err != nil { return err } if desc == f.Desc { return errors.New("Feed didn't change") } f.Desc = desc f.LastUpdate = dt */ return nil } func (f *Feed) GetUrl(dt time.Time) string { var v string /* var e error if v, e = getFeedUrl(f.Source, f.Slug, dt); e != nil { return "" } */ return v } func (f *Feed) GetDesc(dt time.Time) string { var v string /* var e error if v, e = getFeedDesc(f.Source, f.Slug, dt); e != nil { return "" } */ return v } func (f *Feed) GetRssItem() string { var v string /* var e error if v, e = getRssItem(f.Source, f.Slug); e != nil { return "" } */ return v } // DB Function to save a feed func (m *model) SaveFeed(f *Feed) error { var err error if err = m.openDB(); err != nil { return err } defer m.closeDB() bkt := f.GetBucket() if err = m.bolt.MkBucketPath(bkt); err != nil { return err } if err = m.bolt.SetValue(bkt, "name", f.Name); err != nil { return err } if err = m.bolt.SetValue(bkt, "author", f.Author); err != nil { return err } if err = m.bolt.SetValue(bkt, "desc", f.Desc); err != nil { return err } if err = m.bolt.SetTimestamp(bkt, "lastupdate", f.LastUpdate); err != nil { return err } // Add it to the cached list for i, v := range m.Feeds { if v.Source == f.Source && v.Slug == f.Slug { m.Feeds[i] = *f return nil } } m.Feeds = append(m.Feeds, *f) return nil } // DB Function to get a feed func (m *model) GetFeed(source, slug string) (*Feed, error) { var err error if err = m.openDB(); err != nil { return nil, err } defer m.closeDB() ret := new(Feed) ret.Source = source ret.Slug = slug bkt := ret.GetBucket() if ret.Name, err = m.bolt.GetValue(bkt, "name"); err != nil { return nil, err } if ret.Author, err = m.bolt.GetValue(bkt, "author"); err != nil { return nil, err } if ret.Desc, err = m.bolt.GetValue(bkt, "desc"); err != nil { return nil, err } if ret.LastUpdate, err = m.bolt.GetTimestamp(bkt, "lastupdate"); err != nil { return nil, err } return ret, nil } // Load all feeds into the model func (m *model) LoadFeeds() error { m.Feeds = m.GetAllFeeds() return nil } // Save all feeds to the DB func (m *model) SaveAllFeeds(feedSources []FeedSource) { var err error if err = m.openDB(); err != nil { return } defer m.closeDB() for _, v := range feedSources { for j := range v.Feeds { fmt.Printf("Saving Feed to DB (%s;%s)\n", v.Feeds[j].Source, v.Feeds[j].Slug) m.SaveFeed(v.Feeds[j]) } } } // Get all feeds from the db func (m *model) GetAllFeeds() []Feed { var ret []Feed var err error if err = m.openDB(); err != nil { return ret } defer m.closeDB() var srcs []string bkt := []string{"feeds"} if srcs, err = m.bolt.GetBucketList(bkt); err != nil { return ret } for _, src := range srcs { srcBkt := append(bkt, src) var slugs []string if slugs, err = m.bolt.GetBucketList(srcBkt); err != nil { return ret } for _, slg := range slugs { c, err := m.GetFeed(src, slg) if err == nil { ret = append(ret, *c) } } } return ret } // Delete a feed from the DB func (m *model) DeleteFeed(slug string) error { var err error if err = m.openDB(); err != nil { return err } defer m.closeDB() return m.bolt.DeleteBucket([]string{"feeds"}, slug) } func (m *model) RemoveMissingFeeds(feeds []Feed) { for _, c := range m.Feeds { var fnd bool for _, nc := range feeds { if nc.Slug == c.Slug { fnd = true break } } if !fnd { m.DeleteFeed(c.Slug) } } }