webrss/main.go

349 lines
7.0 KiB
Go

package main
import (
"database/sql"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
_ "github.com/mattn/go-sqlite3"
librss "github.com/mmcdole/gofeed"
"log"
"net/http"
"os"
"strconv"
"time"
)
type FeedManager struct {
DBPath string
}
func (f *FeedManager) createDB() (bool, error) {
db, err := sql.Open("sqlite3", "./database.db")
if err != nil {
return false, err
}
defer db.Close()
createStmts := [2]string{`
create table feeds (
Id INTEGER PRIMARY KEY,
Title TEXT,
Description TEXT,
Link TEXT,
FeedLink TEXT,
Updated TEXT,
UpdatedParsed TEXT,
Published TEXT,
PublishedParsed TEXT,
Author TEXT,
Language TEXT,
Image TEXT,
Copyright TEXT,
Generator TEXT,
Categories TEXT,
DublinCoreExt TEXT,
ITunesExt TEXT,
Extensions TEXT,
Custom TEXT,
Items TEXT,
FeedType TEXT,
FeedVersion TEXT
);`,
`
create table items (
GUID TEXT PRIMARY KEY,
Feed INTEGER NOT NULL,
Title TEXT,
Description TEXT,
Content TEXT,
Link TEXT,
Updated TEXT,
UpdatedParsed TEXT,
Published TEXT,
PublishedParsed TEXT,
Author TEXT,
Image TEXT,
Categories TEXT,
Enclosures TEXT,
DublinCoreExt TEXT,
ITunesExt TEXT,
Extensions TEXT,
Custom TEXT,
FOREIGN KEY(Feed) REFERENCES feeds(Id)
)
`}
for _, stmt := range createStmts {
_, err = db.Exec(stmt)
if err != nil {
return false, err
}
}
return true, nil
}
func (f *FeedManager) ExecDB(query string, parameters ...interface{}) (*sql.Result, error) {
db, err := sql.Open("sqlite3", f.DBPath)
if err != nil {
return nil, err
}
defer db.Close()
stmt, err := db.Prepare(query)
if err != nil {
return nil, err
}
result, err := stmt.Exec(parameters...)
if err != nil {
return nil, err
}
return &result, nil
}
func (f *FeedManager) QueryDB(query string, parameters ...interface{}) (*sql.Rows, error) {
db, err := sql.Open("sqlite3", f.DBPath)
if err != nil {
return nil, err
}
defer db.Close()
stmt, err := db.Prepare(query)
if err != nil {
return nil, err
}
result, err := stmt.Query(parameters...)
if err != nil {
return nil, err
}
return result, nil
}
func (f *FeedManager) AddFeed(url string) (*sql.Result, error) {
feed, err := f.DownloadFeed(url)
if err != nil {
return nil, err
}
query := `insert into feeds (title, description, link, feedLink, updated, updatedParsed,
published, publishedParsed) values(?, ?, ?, ?, ?, ?, ?, ?);`
return f.ExecDB(query, feed.Title, feed.Description, feed.Link, feed.FeedLink, feed.Updated, feed.UpdatedParsed,
feed.Published, feed.PublishedParsed)
}
func (f *FeedManager) RemoveFeed(url string) (*sql.Result, error) {
query := "delete from feeds where link = ?;"
return f.ExecDB(query, url)
}
func (f *FeedManager) DownloadFeed(url string) (*librss.Feed, error) {
fp := librss.NewParser()
feed, err := fp.ParseURL(url)
if err != nil {
return nil, err
}
return feed, nil
}
func (f *FeedManager) GetFeeds() (map[int]librss.Feed, error) {
feeds := make(map[int]librss.Feed)
rows, err := f.QueryDB("select id, title, feedlink, link from feeds;")
if err != nil {
return feeds, err
}
defer rows.Close()
for rows.Next() {
var link, title, feedLink string
var id int
err = rows.Scan(&id, &title, &feedLink, &link)
if err != nil {
return feeds, err
}
feeds[id] = librss.Feed{Link: link, FeedLink: feedLink, Title: title}
}
return feeds, nil
}
func (f *FeedManager) Sync() error {
feeds, err := f.GetFeeds()
if err != nil {
return err
}
for id, feed := range feeds {
res, err := f.DownloadFeed(feed.Link)
if err != nil {
return err
}
for _, item := range res.Items {
_, err := f.ExecDB("insert into items (feed, Title, Description, Content, Link, Author, GUID) values (?, ?, ?, ?, ?, ?, ?)",
id, item.Title, item.Description, item.Content, item.Link, item.Author, item.GUID)
if err != nil {
return err
}
}
}
return nil
}
func HomeHandler(w http.ResponseWriter, r *http.Request) {
//fmt.Fprintf(w, "hello")
http.ServeFile(w, r, "./ui/index.html")
}
func GetFeedsHandler(w http.ResponseWriter, r *http.Request) {
defaultDBPath := "./database.db"
feedManager := FeedManager{DBPath: defaultDBPath}
feeds, err := feedManager.GetFeeds()
if err != nil {
return
}
feedList := make([]librss.Feed, 0)
for _, feed := range feeds {
feedList = append(feedList, feed)
}
json, err := json.Marshal(feedList)
fmt.Fprintf(w, string(json))
}
func PostFeed(w http.ResponseWriter, r *http.Request) {
defaultDBPath := "./database.db"
feedManager := FeedManager{DBPath: defaultDBPath}
new_feed_url := r.FormValue("new_feed_url")
if new_feed_url == "" {
w.WriteHeader(500)
}
feeds, err := feedManager.GetFeeds()
if err != nil {
log.Print(err)
w.WriteHeader(500)
return
}
for _, feed := range feeds {
if feed.FeedLink == new_feed_url {
log.Print("Not adding feed ", new_feed_url, " because it already exists")
w.WriteHeader(500)
return
}
}
log.Print("Adding new feed : ", new_feed_url)
_, err = feedManager.AddFeed(r.FormValue("new_feed_url"))
if err != nil {
fmt.Fprintf(w, "ERROR")
}
fmt.Fprintf(w, "OK")
}
func (f *FeedManager) GetItems(feedId int) ([]librss.Item, error) {
rows, err := f.QueryDB("select title, description from items where feed=?;", feedId)
if err != nil {
log.Print(err)
return nil, err
}
defer rows.Close()
items := make([]librss.Item, 0)
for rows.Next() {
var title, description string
err = rows.Scan(&title, &description)
if err != nil {
return nil, err
}
items = append(items, librss.Item{Title: title, Description: description})
}
return items, nil
}
func GetItemsHandler(w http.ResponseWriter, r *http.Request) {
defaultDBPath := "./database.db"
feedManager := FeedManager{DBPath: defaultDBPath}
vars := mux.Vars(r)
feedId, err := strconv.Atoi(vars["feedId"])
if err != nil {
log.Print(err)
return
}
items, err := feedManager.GetItems(feedId)
if err != nil {
log.Print(err)
return
}
json, err := json.Marshal(items)
fmt.Fprintf(w, string(json))
}
func main() {
defaultDBPath := "./database.db"
feedManager := FeedManager{DBPath: defaultDBPath}
if _, err := os.Stat(defaultDBPath); os.IsNotExist(err) {
feedManager.createDB()
_, err := feedManager.AddFeed("https://me.wavrant.xyz/feed/1/")
if err != nil {
panic(err)
}
_, err = feedManager.AddFeed("https://www.lemonde.fr/rss/une.xml")
if err != nil {
panic(err)
}
err = feedManager.Sync()
if err != nil {
panic(err)
}
} else if err != nil {
panic(err)
}
router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)
router.PathPrefix("/static/").Handler(
http.StripPrefix(
"/static/", http.FileServer(http.Dir("./ui/static"))))
router.HandleFunc("/api/feeds/", GetFeedsHandler)
router.HandleFunc("/api/feeds/{feedId:[0-9]+}/items", GetItemsHandler)
router.HandleFunc("/api/feeds/new/", PostFeed).Methods("POST")
http.Handle("/", router)
server := &http.Server{
Handler: router,
Addr: "127.0.0.1:8000",
WriteTimeout: 10 * time.Second,
ReadTimeout: 10 * time.Second,
}
log.Print("Listening on 127.0.0.1:8000")
log.Fatal(server.ListenAndServe())
}