diff --git a/exchange/exchange.go b/exchange/exchange.go new file mode 100644 index 0000000..a19f5f9 --- /dev/null +++ b/exchange/exchange.go @@ -0,0 +1,191 @@ +package exchange + +import ( + "errors" + "local1/logger" + "local3/rssmon2/monitor" + "local3/rssmon2/rss" + "local3/rssmon2/server" + "local3/rssmon2/store" + "strings" + "time" +) + +const nsForFeeds = "FEEDS" + +type Exchange struct { + Mon *monitor.Monitor + SClient store.Client + Srv *server.Server + allFeeds map[string]*rss.Feed +} + +func New(mon *monitor.Monitor, sclient store.Client, srv *server.Server) *Exchange { + return &Exchange{ + Mon: mon, + SClient: sclient, + Srv: srv, + allFeeds: make(map[string]*rss.Feed), + } +} + +func (ex *Exchange) LoadDB() error { + oldFeeds, err := ex.SClient.List(nsForFeeds, "", true, -1) + if err != nil { + return err + } + for _, feedID := range oldFeeds { + b, err := ex.SClient.Get(nsForFeeds, feedID) + if err != nil { + return err + } + feed, err := rss.Deserialize(b) + if err != nil { + return err + } + ex.allFeeds[feed.Link] = feed + if err := ex.Mon.Submit(feed.Link, feed.Interval); err != nil { + return err + } + } + return nil +} + +func (ex *Exchange) NewFeed(url, itemFilter, contentFilter string, tags []string, interval time.Duration) { + feed, err := rss.New(url, itemFilter, contentFilter, tags, interval) + if err != nil { + logger.Logf("can't create new RSS %q: %v", url, err) + return + } + ex.allFeeds[url] = feed + if err := ex.Mon.Submit(url, feed.Interval); err != nil { + logger.Logf("Cannot accept new feed %q: %v", url, err) + } +} + +func (ex *Exchange) GetFeedRSS(url string, n int) (string, error) { + feed, ok := ex.allFeeds[url] + if !ok { + return "", errors.New("unknown feed " + url) + } + itemKeys, err := ex.SClient.List(feed.ID(), "", false, n) + if err != nil { + return "", err + } + items := make([]*rss.Item, len(itemKeys)) + for i := range itemKeys { + b, err := ex.SClient.Get(feed.ID(), itemKeys[i]) + if err != nil { + return "", errors.New("cannot get feed item " + itemKeys[i]) + } + items[i], err = rss.DeserializeItem(b) + if err != nil { + return "", errors.New("cannot deserialize feed item" + itemKeys[i]) + } + } + return rss.ToRSS(feed, items) +} + +func (ex *Exchange) GetFeedItem(ID string) (string, error) { + b, err := ex.SClient.Get(strings.Split(ID, ".")[0], strings.Join(strings.Split(ID, ".")[1:], ".")) + if err != nil { + return "", errors.New("cannot get feed item " + ID) + } + item, err := rss.DeserializeItem(b) + if err != nil { + return "", errors.New("cannot deserialize feed item" + ID) + } + return item.Content, nil +} + +func (ex *Exchange) GetFeedTagRSS(tag string) (string, error) { + feedNames, err := ex.SClient.List(nsForFeeds, "", false, -1) + if err != nil { + return "", err + } + combinedItems := []*rss.Item{} + for _, feedName := range feedNames { + b, err := ex.SClient.Get(nsForFeeds, feedName) + if err != nil { + return "", err + } + feed, err := rss.Deserialize(b) + if err != nil { + return "", err + } + + for i := range feed.Tags { + if feed.Tags[i] == tag { + itemKeys, err := ex.SClient.List(feed.ID(), "", false, 20) // TODO variable, or pick most recent n or something + if err != nil { + return "", err + } + for i := range itemKeys { + b, err := ex.SClient.Get(feed.ID(), itemKeys[i]) + if err != nil { + return "", errors.New("cannot get feed item " + itemKeys[i]) + } + item, err := rss.DeserializeItem(b) + if err != nil { + return "", errors.New("cannot deserialize feed item" + itemKeys[i]) + } + combinedItems = append(combinedItems, item) + } + break + } + } + } + combinedFeed, err := rss.New(tag, "", "", nil, time.Minute) + if err != nil { + return "", err + } + return rss.ToRSS(combinedFeed, combinedItems) +} + +func (ex *Exchange) UpdateFeed(url string) { + feed, ok := ex.allFeeds[url] + if !ok { + f, err := rss.New(url, "", "", nil, time.Minute) + if err != nil { + logger.Logf("cannot identify unknown feed triggered in monitor: %q: %v", url, err) + return + } + b, err := ex.SClient.Get(nsForFeeds, f.ID()) + if err != nil { + logger.Logf("cannot get unknown feed triggered in monitor: %q: %v", url, err) + return + } + feed, err = rss.Deserialize(b) + if err != nil { + logger.Logf("cannot deserialize feed triggered in monitor: %q: %v", url, err) + return + } + } + items, err := ex.allFeeds[url].Update() + if err != nil { + logger.Logf("can't update old RSS %q: %v", url, err) + return + } + b, err := feed.Serialize() + if err != nil { + logger.Logf("can't serialize to save RSS %q: %v", url, err) + return + } + if err := ex.SClient.Set(nsForFeeds, feed.ID(), b); err != nil { + logger.Logf("can't save RSS %q.%q: %v", nsForFeeds, feed.ID(), err) + return + } + logger.Log("Saved feed", feed) + for i := range items { + b, err := items[i].Serialize() + if err != nil { + logger.Logf("can't save rss item %q.%q: %v", url, items[i].Link, err) + return + } + if err := ex.SClient.Set(feed.ID(), items[i].ID(), b); err != nil { + logger.Logf("can't save rss item %q.%q: %v", feed.ID(), items[i].ID(), err) + return + } + logger.Log("Saved feed item", feed.ID(), items[i].ID(), items[i]) + } +} diff --git a/main.go b/main.go index 8cd3739..f575529 100644 --- a/main.go +++ b/main.go @@ -1,200 +1,56 @@ package main import ( - "errors" "local1/logger" "local3/rssmon2/config" + "local3/rssmon2/exchange" "local3/rssmon2/monitor" - "local3/rssmon2/rss" "local3/rssmon2/server" "local3/rssmon2/store" - "strings" - "time" ) -const nsForFeeds = "FEEDS" - func main() { core() } func core() { + var err error + config := config.New() + ex := exchange.New(nil, nil, nil) + + var mon *monitor.Monitor + if mon, err = monitor.New(ex.UpdateFeed); err != nil { + panic(err) + } else if err = mon.Start(); err != nil { + panic(err) + } + defer mon.Stop() + ex.Mon = mon + var sclient store.Client - var err error if sclient, err = store.NewBolt(config.DBPath); err != nil { panic(err) } defer sclient.Close() + ex.SClient = sclient - allFeeds := make(map[string]*rss.Feed) - mon, err := monitor.New(func(url string) { - feed, ok := allFeeds[url] - if !ok { - f, err := rss.New(url, "", "", nil, time.Minute) - if err != nil { - logger.Logf("cannot identify unknown feed triggered in monitor: %q: %v", url, err) - return - } - b, err := sclient.Get(nsForFeeds, f.ID()) - if err != nil { - logger.Logf("cannot get unknown feed triggered in monitor: %q: %v", url, err) - return - } - feed, err = rss.Deserialize(b) - if err != nil { - logger.Logf("cannot deserialize feed triggered in monitor: %q: %v", url, err) - return - } - } - items, err := allFeeds[url].Update() - if err != nil { - logger.Logf("can't update old RSS %q: %v", url, err) - return - } - b, err := feed.Serialize() - if err != nil { - logger.Logf("can't serialize to save RSS %q: %v", url, err) - return - } - if err := sclient.Set(nsForFeeds, feed.ID(), b); err != nil { - logger.Logf("can't save RSS %q.%q: %v", nsForFeeds, feed.ID(), err) - return - } - logger.Log("Saved feed", feed) - for i := range items { - b, err := items[i].Serialize() - if err != nil { - logger.Logf("can't save rss item %q.%q: %v", url, items[i].Link, err) - return - } - if err := sclient.Set(feed.ID(), items[i].ID(), b); err != nil { - logger.Logf("can't save rss item %q.%q: %v", feed.ID(), items[i].ID(), err) - return - } - logger.Log("Saved feed item", feed.ID(), items[i].ID(), items[i]) - } - }) - if err != nil { + var server *server.Server + if server, err = server.New(config.Port, + ex.NewFeed, + ex.GetFeedRSS, + ex.GetFeedItem, + ex.GetFeedTagRSS, + ); err != nil { panic(err) } - if err := mon.Start(); err != nil { - panic(err) - } - defer mon.Stop() + ex.Srv = server - server, err := server.New(config.Port, - func(url string, itemFilter, contentFilter string, tags []string, interval time.Duration) { - feed, err := rss.New(url, itemFilter, contentFilter, tags, interval) - if err != nil { - logger.Logf("can't create new RSS %q: %v", url, err) - return - } - allFeeds[url] = feed - if err := mon.Submit(url, feed.Interval); err != nil { - logger.Logf("Cannot accept new feed %q: %v", url, err) - } - }, - func(url string, n int) (string, error) { - feed, ok := allFeeds[url] - if !ok { - return "", errors.New("unknown feed " + url) - } - itemKeys, err := sclient.List(feed.ID(), "", false, n) - if err != nil { - return "", err - } - items := make([]*rss.Item, len(itemKeys)) - for i := range itemKeys { - b, err := sclient.Get(feed.ID(), itemKeys[i]) - if err != nil { - return "", errors.New("cannot get feed item " + itemKeys[i]) - } - items[i], err = rss.DeserializeItem(b) - if err != nil { - return "", errors.New("cannot deserialize feed item" + itemKeys[i]) - } - } - return rss.ToRSS(feed, items) - }, - func(ID string) (string, error) { - b, err := sclient.Get(strings.Split(ID, ".")[0], strings.Join(strings.Split(ID, ".")[1:], ".")) - if err != nil { - return "", errors.New("cannot get feed item " + ID) - } - item, err := rss.DeserializeItem(b) - if err != nil { - return "", errors.New("cannot deserialize feed item" + ID) - } - return item.Content, nil - }, - func(tag string) (string, error) { - feedNames, err := sclient.List(nsForFeeds, "", false, -1) - if err != nil { - return "", err - } - combinedItems := []*rss.Item{} - for _, feedName := range feedNames { - b, err := sclient.Get(nsForFeeds, feedName) - if err != nil { - return "", err - } - feed, err := rss.Deserialize(b) - if err != nil { - return "", err - } - for i := range feed.Tags { - if feed.Tags[i] == tag { - itemKeys, err := sclient.List(feed.ID(), "", false, 20) // TODO variable, or pick most recent n or something - if err != nil { - return "", err - } - for i := range itemKeys { - b, err := sclient.Get(feed.ID(), itemKeys[i]) - if err != nil { - return "", errors.New("cannot get feed item " + itemKeys[i]) - } - item, err := rss.DeserializeItem(b) - if err != nil { - return "", errors.New("cannot deserialize feed item" + itemKeys[i]) - } - combinedItems = append(combinedItems, item) - } - break - } - } - } - combinedFeed, err := rss.New(tag, "", "", nil, time.Minute) - if err != nil { - return "", err - } - return rss.ToRSS(combinedFeed, combinedItems) - }, - ) - if err != nil { + if err := ex.LoadDB(); err != nil { panic(err) } - oldFeeds, err := sclient.List(nsForFeeds, "", true, -1) - if err != nil { - panic(err) - } - for _, feedID := range oldFeeds { - b, err := sclient.Get(nsForFeeds, feedID) - if err != nil { - panic(err) - } - feed, err := rss.Deserialize(b) - if err != nil { - panic(err) - } - allFeeds[feed.Link] = feed - if err := mon.Submit(feed.Link, feed.Interval); err != nil { - panic(err) - } - } - logger.Log("Starting with", config) if err := server.Serve(); err != nil { panic(err)