diff --git a/monitor/item.go b/monitor/item.go index b34ff31..ee0024d 100644 --- a/monitor/item.go +++ b/monitor/item.go @@ -1,8 +1,6 @@ package monitor import ( - "bytes" - "encoding/gob" "local/rssmon3/config" "log" "time" @@ -65,19 +63,16 @@ func (i *Item) getInterval() (time.Duration, error) { if err != nil { return forever, err } - buff := bytes.NewBuffer(b) - dec := gob.NewDecoder(buff) - err = dec.Decode(&t) + err = config.Decode(b, &t) return t, err } func (i *Item) setInterval(t time.Duration) error { - buff := bytes.NewBuffer(nil) - enc := gob.NewEncoder(buff) - if err := enc.Encode(t); err != nil { + b, err := config.Encode(t) + if err != nil { return err } - if err := config.Values().DB.Set(i.Key, buff.Bytes(), nsInterval); err != nil { + if err := config.Values().DB.Set(i.Key, b, nsInterval); err != nil { return err } return nil @@ -98,29 +93,21 @@ func (i *Item) Mark() { } func (i *Item) setLast(t time.Time) error { - buff := bytes.NewBuffer(nil) - enc := gob.NewEncoder(buff) - if err := enc.Encode(t); err != nil { + b, err := config.Encode(t) + if err != nil { return err } - if err := config.Values().DB.Set(i.Key, buff.Bytes(), nsLast); err != nil { - return err - } - return nil + return config.Values().DB.Set(i.Key, b, nsLast) } func (i *Item) getLast() (time.Time, error) { - t := time.Now() + t := never b, err := config.Values().DB.Get(i.Key, nsLast) if err != nil { return never, err } - buff := bytes.NewBuffer(b) - dec := gob.NewDecoder(buff) - if err := dec.Decode(&t); err != nil { - return never, err - } - return t, nil + err = config.Decode(b, &t) + return t, err } func (i *Item) Encode() ([]byte, error) { diff --git a/rss/feed.go b/rss/feed.go index b063610..e934dbd 100644 --- a/rss/feed.go +++ b/rss/feed.go @@ -23,25 +23,8 @@ type Feed struct { Tags []string } -func TaggedFeeds(tag string) ([]*Feed, error) { - db := config.Values().DB - feedNames, err := db.List([]string{nsFeeds}) - if err != nil { - return nil, err - } - results := []*Feed{} - for _, feedName := range feedNames { - f := newFeed(feedName) - if err := f.Load(); err != nil { - return nil, err - } - for i := range f.Tags { - if f.Tags[i] == tag { - results = append(results, f) - } - } - } - return results, nil +func SubmitFeed(f *Feed) error { + return f.save() } func newFeed(key string) *Feed { diff --git a/rss/feed_test.go b/rss/feed_test.go index 90544c5..ae0c6ec 100644 --- a/rss/feed_test.go +++ b/rss/feed_test.go @@ -177,29 +177,3 @@ func TestRSSFeedPull(t *testing.T) { t.Fatal(i) } } - -func TestRSSTaggedFeeds(t *testing.T) { - initRSSFeed() - - for _, k := range []string{"a", "b"} { - f := newFeed(k) - f.Tags = []string{"TAG"} - if err := f.save(); err != nil { - t.Fatal(err) - } - } - - if feeds, err := TaggedFeeds("NOTTAG"); err != nil { - t.Fatal(err) - } else if len(feeds) != 0 { - t.Fatal(len(feeds)) - } - - if feeds, err := TaggedFeeds("TAG"); err != nil { - t.Fatal(err) - } else if len(feeds) != 2 { - t.Fatal(len(feeds)) - } else { - t.Logf("%v", feeds) - } -} diff --git a/rss/serialize.go b/rss/serialize.go new file mode 100644 index 0000000..fe0323c --- /dev/null +++ b/rss/serialize.go @@ -0,0 +1,52 @@ +package rss + +import ( + "io" + "local/rssmon3/config" + + "github.com/gorilla/feeds" +) + +func TaggedFeeds(tag string) ([]*Feed, error) { + db := config.Values().DB + feedNames, err := db.List([]string{nsFeeds}) + if err != nil { + return nil, err + } + results := []*Feed{} + for _, feedName := range feedNames { + f := newFeed(feedName) + if err := f.Load(); err != nil { + return nil, err + } + for i := range f.Tags { + if f.Tags[i] == tag { + results = append(results, f) + } + } + } + return results, nil +} + +func WriteFeed(w io.Writer, tag string, items []*Item) error { + feed := &feeds.Feed{ + Title: tag, + Link: &feeds.Link{}, + Description: tag, + Items: make([]*feeds.Item, len(items)), + } + for i, item := range items { + feed.Items[i] = &feeds.Item{ + Title: item.Title, + Link: &feeds.Link{Href: item.Link}, + Description: item.Content, + Created: item.TS, + } + } + s, err := feed.ToRss() + if err != nil { + return err + } + w.Write([]byte(s)) + return nil +} diff --git a/rss/serialize_test.go b/rss/serialize_test.go new file mode 100644 index 0000000..43e7085 --- /dev/null +++ b/rss/serialize_test.go @@ -0,0 +1,71 @@ +package rss + +import ( + "bytes" + "log" + "os" + "testing" +) + +func initRSSSerialize() { + initRSSFeed() +} + +func TestRSSTaggedFeeds(t *testing.T) { + initRSSFeed() + + for _, k := range []string{"a", "b"} { + f := newFeed(k) + f.Tags = []string{"TAG"} + if err := f.save(); err != nil { + t.Fatal(err) + } + } + + if feeds, err := TaggedFeeds("NOTTAG"); err != nil { + t.Fatal(err) + } else if len(feeds) != 0 { + t.Fatal(len(feeds)) + } + + if feeds, err := TaggedFeeds("TAG"); err != nil { + t.Fatal(err) + } else if len(feeds) != 2 { + t.Fatal(len(feeds)) + } else { + t.Logf("%v", feeds) + } +} + +func TestRSSWriteFeed(t *testing.T) { + initRSSFeed() + s := mockRSS() + defer s.Close() + + f := newFeed("key") + f.TitleFilter = "5[0-9]{2}" + f.ContentFilter = "b" + f.Tags = []string{"c"} + f.URL = s.URL + + log.SetOutput(bytes.NewBuffer(nil)) + defer log.SetOutput(os.Stderr) + if err := f.pull(); err != nil { + t.Fatal(err) + } + log.SetOutput(os.Stderr) + + items, err := f.Items(5) + if err != nil { + t.Fatal(err) + } + if len(items) != 5 { + t.Fatal(len(items)) + } + + buff := bytes.NewBuffer(nil) + if err := WriteFeed(buff, "c", items); err != nil { + t.Fatal(err) + } + t.Logf("%s", buff.Bytes()) +} diff --git a/server/.routes.go.swp b/server/.routes.go.swp new file mode 100644 index 0000000..eea7618 Binary files /dev/null and b/server/.routes.go.swp differ diff --git a/server/routes.go b/server/routes.go index a5f43f4..e1e2113 100644 --- a/server/routes.go +++ b/server/routes.go @@ -1,12 +1,16 @@ package server import ( + "encoding/json" "errors" "fmt" "local/router" + "local/rssmon3/monitor" + "local/rssmon3/rss" "log" "net/http" "regexp" + "time" ) func (s *Server) Routes() error { @@ -15,6 +19,7 @@ func (s *Server) Routes() error { handler http.HandlerFunc }{ {path: fmt.Sprintf("/api/tag/%s", router.Wildcard), handler: s.tag}, + {path: fmt.Sprintf("/api/feed"), handler: s.feed}, } for _, handle := range handles { if err := s.router.Add(handle.path, handle.handler); err != nil { @@ -47,6 +52,57 @@ func (s *Server) tag(w http.ResponseWriter, r *http.Request) { return } tag := regexp.MustCompile("^.*\\/").ReplaceAllString(r.URL.Path, "") - log.Println(tag) + feeds, err := rss.TaggedFeeds(tag) + if err != nil { + s.error(w, r, err) + return + } + items := []*rss.Item{} + for _, feed := range feeds { + feedItems, err := feed.Items(20) + if err != nil { + s.error(w, r, err) + } + items = append(items, feedItems...) + } + if err := rss.WriteFeed(w, tag, items); err != nil { + s.error(w, r, err) + return + } +} + +func (s *Server) feed(w http.ResponseWriter, r *http.Request) { + if r.Method != "PUT" { + s.notFound(w, r) + return + } + var putFeed struct { + URL string `json:"url"` + Interval time.Duration `json:"refresh"` + TitleFilter string `json:"items"` + ContentFilter string `json:"content"` + Tags []string `json:"tags"` + } + if err := json.NewDecoder(r.Body).Decode(&putFeed); err != nil { + s.userError(w, r, err) + return + } + f := &rss.Feed{ + Key: putFeed.URL, + URL: putFeed.URL, + TitleFilter: putFeed.TitleFilter, + ContentFilter: putFeed.ContentFilter, + Tags: putFeed.Tags, + } + if err := rss.SubmitFeed(f); err != nil { + s.error(w, r, err) + return + } + i, err := monitor.NewItem(f.Key, putFeed.Interval) + if err != nil { + s.error(w, r, err) + return + } + log.Println(i) s.error(w, r, errors.New("not impl")) }