From a1d2ce27ac2f42dd323c6e620f04d82b35663c92 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 29 Nov 2020 06:47:35 +0200 Subject: Feeds: Worker saves feeds in the background No need to wait until quitting the app to write the feeds state to disk. --- res/about/version.gmi | 4 ++- src/feeds.c | 94 +++++++++++++++++++++++++-------------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/res/about/version.gmi b/res/about/version.gmi index a5830726..d209d376 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi @@ -6,8 +6,10 @@ ``` # Release notes +## 0.12 + ## 0.11 -* Added feed subscriptions. A subscription is any bookmark with the "subscribed" tag. Subscriptions are refreshed in the background while Lagrange is running. +* Added feed subscriptions. A subscription is any bookmark with the "subscribed" tag. Subscribed feeds are refreshed in the background while Lagrange is running. * Added a new sidebar tab for feeds. * Added "about:feeds" to show entries from all subscriptions on one page. * Added icons for special bookmark tags, and context menu items for toggling "homepage" and "subscribed". diff --git a/src/feeds.c b/src/feeds.c index dc82fe0d..d8a2f24d 100644 --- a/src/feeds.c +++ b/src/feeds.c @@ -111,6 +111,15 @@ static void submit_FeedJob_(iFeedJob *d) { submit_GmRequest(d->request); } +static iBool isSubscribed_(void *context, const iBookmark *bm) { + iUnused(context); + return indexOfCStr_String(&bm->tags, "subscribed") != iInvalidPos; /* TODO: RegExp with \b */ +} + +static const iPtrArray *listSubscriptions_(void) { + return list_Bookmarks(bookmarks_App(), NULL, isSubscribed_, NULL); +} + static iFeedJob *startNextJob_Feeds_(iFeeds *d) { if (isEmpty_PtrArray(&d->jobs)) { return NULL; @@ -177,6 +186,43 @@ static void parseResult_FeedJob_(iFeedJob *d) { } } +static void save_Feeds_(iFeeds *d) { + iFile *f = new_File(collect_String(concatCStr_Path(&d->saveDir, feedsFilename_Feeds_))); + if (open_File(f, write_FileMode | text_FileMode)) { + lock_Mutex(d->mtx); + iString *str = new_String(); + format_String(str, "%llu\n# Feeds\n", integralSeconds_Time(&d->lastRefreshedAt)); + write_File(f, utf8_String(str)); + /* Index of feeds for IDs. */ { + iConstForEach(PtrArray, i, listSubscriptions_()) { + const iBookmark *bm = i.ptr; + format_String(str, "%08x %s\n", id_Bookmark(bm), cstr_String(&bm->url)); + write_File(f, utf8_String(str)); + } + } + writeData_File(f, "# Entries\n", 10); + iTime now; + initCurrent_Time(&now); + iConstForEach(Array, i, &d->entries.values) { + const iFeedEntry *entry = *(const iFeedEntry **) i.value; + if (secondsSince_Time(&now, &entry->discovered) > maxAge_Visited) { + continue; /* Forget entries discovered long ago. */ + } + format_String(str, "%x\n%llu\n%llu\n%s\n%s\n", + entry->bookmarkId, + integralSeconds_Time(&entry->posted), + integralSeconds_Time(&entry->discovered), + cstr_String(&entry->url), + cstr_String(&entry->title)); + write_File(f, utf8_String(str)); + } + delete_String(str); + close_File(f); + unlock_Mutex(d->mtx); + } + iRelease(f); +} + static iBool updateEntries_Feeds_(iFeeds *d, iPtrArray *incoming) { iBool gotNew = iFalse; lock_Mutex(d->mtx); @@ -252,20 +298,12 @@ static iThreadResult fetch_Feeds_(iThread *thread) { break; } } + save_Feeds_(d); postCommandf_App("feeds.update.finished arg:%d", gotNew ? 1 : 0); initCurrent_Time(&d->lastRefreshedAt); return 0; } -static iBool isSubscribed_(void *context, const iBookmark *bm) { - iUnused(context); - return indexOfCStr_String(&bm->tags, "subscribed") != iInvalidPos; /* TODO: RegExp with \b */ -} - -static const iPtrArray *listSubscriptions_(void) { - return list_Bookmarks(bookmarks_App(), NULL, isSubscribed_, NULL); -} - static iBool startWorker_Feeds_(iFeeds *d) { if (d->worker) { return iFalse; /* Refresh is already ongoing. */ @@ -308,43 +346,6 @@ static int cmp_FeedEntryPtr_(const void *a, const void *b) { return cmpString_String(&(*elem[0])->url, &(*elem[1])->url); } -static void save_Feeds_(iFeeds *d) { - iFile *f = new_File(collect_String(concatCStr_Path(&d->saveDir, feedsFilename_Feeds_))); - if (open_File(f, write_FileMode | text_FileMode)) { - lock_Mutex(d->mtx); - iString *str = new_String(); - format_String(str, "%llu\n# Feeds\n", integralSeconds_Time(&d->lastRefreshedAt)); - write_File(f, utf8_String(str)); - /* Index of feeds for IDs. */ { - iConstForEach(PtrArray, i, listSubscriptions_()) { - const iBookmark *bm = i.ptr; - format_String(str, "%08x %s\n", id_Bookmark(bm), cstr_String(&bm->url)); - write_File(f, utf8_String(str)); - } - } - writeData_File(f, "# Entries\n", 10); - iTime now; - initCurrent_Time(&now); - iConstForEach(Array, i, &d->entries.values) { - const iFeedEntry *entry = *(const iFeedEntry **) i.value; - if (secondsSince_Time(&now, &entry->discovered) > maxAge_Visited) { - continue; /* Forget entries discovered long ago. */ - } - format_String(str, "%x\n%llu\n%llu\n%s\n%s\n", - entry->bookmarkId, - integralSeconds_Time(&entry->posted), - integralSeconds_Time(&entry->discovered), - cstr_String(&entry->url), - cstr_String(&entry->title)); - write_File(f, utf8_String(str)); - } - delete_String(str); - close_File(f); - unlock_Mutex(d->mtx); - } - iRelease(f); -} - iDeclareType(FeedHashNode) struct Impl_FeedHashNode { @@ -474,7 +475,6 @@ void deinit_Feeds(void) { stopWorker_Feeds_(d); iAssert(isEmpty_PtrArray(&d->jobs)); deinit_PtrArray(&d->jobs); - save_Feeds_(d); deinit_String(&d->saveDir); delete_Mutex(d->mtx); iForEach(Array, i, &d->entries.values) { -- cgit v1.2.3