Prepared for in-memory-caching (not yet functional).

This commit is contained in:
Martin Dosch 2019-06-01 10:59:19 +02:00
parent 1bdf8c048f
commit fb21d01556
2 changed files with 106 additions and 95 deletions

View file

@ -17,104 +17,110 @@ import (
"jaytaylor.com/html2text" "jaytaylor.com/html2text"
) )
// ToDo: If caching == false create a global variable to save timestamp in memory.
// Get new articles for specified feed. // Get new articles for specified feed.
func getArticles(feedURL string, max int, noExcerpt bool, filter []string) (string, error) { func getArticles(feedURL string, max int, noExcerpt bool, filter []string, caching bool) (string, error) {
type feedCache struct { type feedCache struct {
LastChange string LastChange string
} }
var output, cachePath string var output, cachePath, cacheFile string
var last time.Time var last time.Time
var lastUpdate feedCache var lastUpdate feedCache
var file *os.File var file *os.File
var updateTime time.Time var updateTime time.Time
// Get systems user cache path. if caching == true {
osCacheDir := os.Getenv("$XDG_CACHE_HOME") // Get systems user cache path.
if osCacheDir != "" { osCacheDir := os.Getenv("$XDG_CACHE_HOME")
// Create configPath if not yet existing. if osCacheDir != "" {
cachePath = osCacheDir + "/feed-to-muc/" // Create configPath if not yet existing.
cachePath = osCacheDir + "/feed-to-muc/"
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
err = os.MkdirAll(cachePath, 0700)
if err != nil {
log.Fatal("Error: Can't create cache path:", err)
}
}
} else { // Get the current user.
curUser, err := user.Current()
if err != nil {
log.Fatal("Error: Can't get current user:", err)
return "", err
}
// Get home directory.
home := curUser.HomeDir
if home == "" {
log.Fatal("Error: No home directory available.")
return "", err
}
// Create cachePath if not yet existing.
cachePath = home + "/.cache/feed-to-muc/"
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
err = os.MkdirAll(cachePath, 0700)
if err != nil {
log.Fatal("Error: Can't create cache path:", err)
}
}
}
// Create a hash as identifier for the feed.
// The identifier will be used as filename for caching the update time.
h := fnv.New32a()
h.Write([]byte(feedURL))
if _, err := os.Stat(cachePath); os.IsNotExist(err) { if _, err := os.Stat(cachePath); os.IsNotExist(err) {
err = os.MkdirAll(cachePath, 0700) err = os.MkdirAll(cachePath, 0700)
if err != nil { if err != nil {
log.Fatal("Error: Can't create cache path:", err) log.Fatal("Error: Can't create hash identifier for cache file:", err)
} }
} }
} else { // Get the current user. cacheFile = cachePath + strconv.Itoa(int(h.Sum32()))
curUser, err := user.Current()
if err != nil {
log.Fatal("Error: Can't get current user:", err)
return "", err
}
// Get home directory.
home := curUser.HomeDir
if home == "" { if _, err := os.Stat(cacheFile); os.IsNotExist(err) {
log.Fatal("Error: No home directory available.") file, err = os.Create(cacheFile)
return "", err
}
// Create cachePath if not yet existing.
cachePath = home + "/.cache/feed-to-muc/"
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
err = os.MkdirAll(cachePath, 0700)
if err != nil { if err != nil {
log.Fatal("Error: Can't create cache path:", err) log.Fatal("Error: Can't create cache file:", err)
}
defer file.Close()
last = time.Now()
lastUpdate.LastChange = last.Format(time.RFC3339)
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
_, err = file.Write(lastUpdateJSON)
if err != nil {
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
}
} else {
file, err = os.OpenFile(cacheFile, os.O_RDWR, 0600)
if err != nil {
log.Fatal("Error: Can't open cache file:", err)
}
defer file.Close()
decoder := json.NewDecoder(file)
lastUpdate := feedCache{}
if err := decoder.Decode(&lastUpdate); err != nil {
log.Fatal("Error: Can't decode laste updates time stamp:", err)
}
last, err = time.Parse(time.RFC3339, string(lastUpdate.LastChange))
if err != nil {
log.Fatal("Error: Can't parse last updates time stamp:", err)
} }
} }
}
// Create a hash as identifier for the feed.
// The identifier will be used as filename for caching the update time.
h := fnv.New32a()
h.Write([]byte(feedURL))
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
err = os.MkdirAll(cachePath, 0700)
if err != nil {
log.Fatal("Error: Can't create hash identifier for cache file:", err)
}
}
cacheFile := cachePath + strconv.Itoa(int(h.Sum32()))
if _, err := os.Stat(cacheFile); os.IsNotExist(err) {
file, err = os.Create(cacheFile)
if err != nil {
log.Fatal("Error: Can't create cache file:", err)
}
defer file.Close()
last = time.Now()
lastUpdate.LastChange = last.Format(time.RFC3339)
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
_, err = file.Write(lastUpdateJSON)
if err != nil {
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
}
} else { } else {
last = time.Now()
file, err = os.OpenFile(cacheFile, os.O_RDWR, 0600)
if err != nil {
log.Fatal("Error: Can't open cache file:", err)
}
defer file.Close()
decoder := json.NewDecoder(file)
lastUpdate := feedCache{}
if err := decoder.Decode(&lastUpdate); err != nil {
log.Fatal("Error: Can't decode laste updates time stamp:", err)
}
last, err = time.Parse(time.RFC3339, string(lastUpdate.LastChange))
if err != nil {
log.Fatal("Error: Can't parse last updates time stamp:", err)
}
} }
fp := gofeed.NewParser() fp := gofeed.NewParser()
@ -174,24 +180,26 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string) (stri
last = updateTime last = updateTime
lastUpdate.LastChange = updateTime.Format(time.RFC3339) lastUpdate.LastChange = updateTime.Format(time.RFC3339)
// Remove file with cached timestamp and create it if caching == true {
// again with updated timestamp. // Remove file with cached timestamp and create it
// ToDo: Replace timestamp without deleting. // again with updated timestamp.
err = os.Remove(cacheFile) // ToDo: Replace timestamp without deleting.
if err != nil { err = os.Remove(cacheFile)
log.Fatal("Error: Can't delete cache file:", err) if err != nil {
} log.Fatal("Error: Can't delete cache file:", err)
}
file, err = os.Create(cacheFile) file, err = os.Create(cacheFile)
if err != nil { if err != nil {
log.Fatal("Error: Can't create cache file:", err) log.Fatal("Error: Can't create cache file:", err)
} }
defer file.Close() defer file.Close()
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ") lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
_, err = file.Write(lastUpdateJSON) _, err = file.Write(lastUpdateJSON)
if err != nil { if err != nil {
log.Fatal("Error: Can't write last update time stamp to cache file:", err) log.Fatal("Error: Can't write last update time stamp to cache file:", err)
}
} }
// Remove redirects and tracking parameters from URL. // Remove redirects and tracking parameters from URL.

View file

@ -17,11 +17,12 @@ type configuration struct {
Password string Password string
Muc string Muc string
MucNick string MucNick string
Contact string
MaxArticles int MaxArticles int
RefreshTime time.Duration RefreshTime time.Duration
NoExcerpt bool NoExcerpt bool
Quiet bool Quiet bool
Contact string Caching bool
Filter []string Filter []string
Feeds []string Feeds []string
} }
@ -72,7 +73,8 @@ func main() {
go pingMUC(client, config.BotJid, config.Muc, config.MucNick) go pingMUC(client, config.BotJid, config.Muc, config.MucNick)
// Starting goroutine to process received stanzas. // Starting goroutine to process received stanzas.
go processStanzas(client, config.Muc, config.MucNick, config.Feeds, config.Quiet, config.Contact) go processStanzas(client, config.Muc, config.MucNick, config.Feeds, config.Quiet,
config.Contact)
// Set RefreshTime to 30 seconds if not defined. // Set RefreshTime to 30 seconds if not defined.
if config.RefreshTime == 0 { if config.RefreshTime == 0 {
@ -83,7 +85,8 @@ func main() {
// Check all configured feeds for new articles and send // Check all configured feeds for new articles and send
// new articles to configured MUC. // new articles to configured MUC.
for i := 0; i < len(config.Feeds); i++ { for i := 0; i < len(config.Feeds); i++ {
output, err := getArticles(config.Feeds[i], config.MaxArticles, config.NoExcerpt, config.Filter) output, err := getArticles(config.Feeds[i], config.MaxArticles, config.NoExcerpt,
config.Filter, config.Caching)
if err != nil { if err != nil {
// Exit if an error occurs checking the feeds. // Exit if an error occurs checking the feeds.
log.Fatal("Error: Can't check feeds for new articles: ", err) log.Fatal("Error: Can't check feeds for new articles: ", err)