From 0e0bb2ed91706ade673022020f7445608ed57658 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Sat, 9 Jan 2021 16:53:39 -0600 Subject: [PATCH] Multi-threaded parsing/downloading --- Makefile | 1 + src/App.cpp | 49 +++++++++++++-- src/App.h | 16 ++++- src/Feed.cpp | 18 +++++- src/Feed.h | 5 +- src/FeedController.cpp | 135 +++++++++++++++++++++++++++++++++++++++++ src/FeedController.h | 39 ++++++++++++ src/Invocation.cpp | 38 ------------ 8 files changed, 253 insertions(+), 48 deletions(-) create mode 100644 src/FeedController.cpp create mode 100644 src/FeedController.h diff --git a/Makefile b/Makefile index 6c431c0..8104134 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ SRCS = \ src/Entry.cpp, \ src/EntriesView.cpp, \ src/Feed.cpp, \ + src/FeedController.cpp \ src/FeedsView.cpp, \ src/Invocation.cpp \ src/MainWindow.cpp, \ diff --git a/src/App.cpp b/src/App.cpp index 72a7c33..dff069a 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -14,6 +14,7 @@ #include "Config.h" #include "Entry.h" #include "Feed.h" +#include "FeedController.h" #include "Invocation.h" #include "MainWindow.h" #include "Mimetypes.h" @@ -31,7 +32,6 @@ main(int argc, char** argv) app->cfg = new Config; app->cfg->Load(); - if (argc == 1) app->Run(); else @@ -49,14 +49,55 @@ void cliStart(int argc, char** argv) { invocation(argc, argv); - ((App*)be_app)->cfg->targetFeeds.DoForEach(&processFeed); + BList targetFeeds = ((App*)be_app)->cfg->targetFeeds; + + for (int i = 0; i < targetFeeds.CountItems(); i++) { + Feed* newFeed = new Feed(((BString*)targetFeeds.ItemAt(i))->String()); + BMessage* enqueue = new BMessage(kEnqueueFeed); + + enqueue->AddData("feeds", B_RAW_TYPE, newFeed, sizeof(Feed)); + + ((App*)be_app)->MessageReceived(enqueue); + } } App::App() : BApplication("application/x-vnd.Pogger") { - MainWindow* mainWin = new MainWindow(); - mainWin->Show(); + fMainWindow = new MainWindow(); + fFeedController = new FeedController(); + fMainWindow->Show(); +} + + +void +App::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case kEnqueueFeed: + { + fFeedController->MessageReceived(msg); + break; + } + case kClearQueue: + { + break; + } + case kQueueProgress: + { + fMainWindow->MessageReceived(msg); + } + case kDownloadComplete: + { + fFeedController->MessageReceived(msg); + } + default: + { +// BApplication::MessageReceived(msg); + break; + } + } } diff --git a/src/App.h b/src/App.h index b3b9dd6..eacb2cf 100644 --- a/src/App.h +++ b/src/App.h @@ -10,14 +10,23 @@ #include +class BMessage; class Config; +class FeedController; +class MainWindow; class App : public BApplication { public: - App(void); - Config* cfg; + App(void); + void MessageReceived(BMessage* msg); + + Config* cfg; + MainWindow* fMainWindow; + +private: + FeedController* fFeedController; }; @@ -25,9 +34,10 @@ int main ( int, char** ); void cliStart ( int, char** ); + extern const char* configPath; extern BString usageMsg; -#endif +#endif // APP_H diff --git a/src/Feed.cpp b/src/Feed.cpp index 3add031..e3de764 100644 --- a/src/Feed.cpp +++ b/src/Feed.cpp @@ -26,6 +26,13 @@ Feed::Feed(BString path) } +Feed::Feed(Feed* feed) + : Feed() +{ + SetCachePath(feed->GetCachePath()); +} + + Feed::Feed() { title = BString(""); @@ -171,7 +178,7 @@ Feed::SetCachePath (BString givenPath) } -// count the amount of siblings to an element of given type name +// Count the amount of siblings to an element of given type name int Feed::xmlCountSiblings (tinyxml2::XMLElement* xsibling, const char* sibling_name) { @@ -184,7 +191,7 @@ Feed::xmlCountSiblings (tinyxml2::XMLElement* xsibling, const char* sibling_name } -// add the given entry to the feed, if appropriate +// Add the given entry to the feed, if appropriate bool Feed::AddEntry (Entry* newEntry) { @@ -286,6 +293,13 @@ Feed::GetHomeUrl() } +BString +Feed::GetXmlUrl() +{ + return xmlUrl; +} + + // set the update time for a feed bool Feed::SetDate(const char* dateCStr) diff --git a/src/Feed.h b/src/Feed.h index 7186cf3..8d287e6 100644 --- a/src/Feed.h +++ b/src/Feed.h @@ -20,6 +20,7 @@ class BUrl; class Feed { public: Feed(BString); + Feed(Feed*); Feed(); virtual void Parse(); @@ -29,6 +30,8 @@ public: bool IsRss(); bool IsAtom(); + BString FetchRemoteFeed(); + bool AddEntry(Entry*); BList GetEntries(); bool SetTitle(const char*); @@ -40,6 +43,7 @@ public: bool SetHomeUrl(const char*); bool SetHomeUrl(tinyxml2::XMLElement*); BString GetHomeUrl(); + BString GetXmlUrl(); bool SetDate(const char*); bool SetDate(tinyxml2::XMLElement*); BDateTime GetDate(); @@ -49,7 +53,6 @@ public: protected: void EnsureCached(); - BString FetchRemoteFeed(); int xmlCountSiblings(tinyxml2::XMLElement*, const char*); BString title; diff --git a/src/FeedController.cpp b/src/FeedController.cpp new file mode 100644 index 0000000..b9c4d29 --- /dev/null +++ b/src/FeedController.cpp @@ -0,0 +1,135 @@ +/* + * Copyright 2020, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "FeedController.h" + +#include + +#include + +#include "App.h" +#include "AtomFeed.h" +#include "Entry.h" +#include "RssFeed.h" + + +FeedController::FeedController() + : + fDownloadThread(0), + fParseThread(0) +{ + fDownloadThread = spawn_thread(_DownloadLoop, "here, eat this", + B_NORMAL_PRIORITY, NULL); + fParseThread = spawn_thread(_ParseLoop, "oki tnx nomnomnom", + B_NORMAL_PRIORITY, NULL); + resume_thread(fDownloadThread); + resume_thread(fParseThread); +} + + +FeedController::~FeedController() +{ + kill_thread(fDownloadThread); + kill_thread(fParseThread); +} + + +void +FeedController::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case kEnqueueFeed: + { + int i = 0; + const void* data; + ssize_t size = sizeof(Feed); + + while (msg->HasData("feeds", B_RAW_TYPE, i)) { + msg->FindData("feeds", B_RAW_TYPE, i, &data, &size); + send_data(fDownloadThread, msg->what, data, size); + i++; + } + break; + } + case kClearQueue: + { + break; + } + case kDownloadComplete: + { + int i = 0; + const void* data; + ssize_t size = sizeof(Feed); + + while (msg->HasData("feeds", B_RAW_TYPE, i)) { + msg->FindData("feeds", B_RAW_TYPE, i, &data, &size); + if (((Feed*)data)->IsUpdated() == true) + send_data(fParseThread, msg->what, data, size); + i++; + } + break; + } + default: + { +// BWindow::MessageReceived(msg); + break; + } + } +} + + +int32 +FeedController::_DownloadLoop(void* ignored) +{ + thread_id sender; + Feed* feedBuffer = new Feed(); + + while (receive_data(&sender, (void*)feedBuffer, sizeof(Feed)) != 0) { + feedBuffer->FetchRemoteFeed(); + + BMessage* downloaded = new BMessage(kDownloadComplete); + downloaded->AddData("feeds", B_RAW_TYPE, feedBuffer, sizeof(Feed)); + + + ((App*)be_app)->MessageReceived(downloaded); + } + + delete(feedBuffer); + return 0; +} + + +int32 +FeedController::_ParseLoop(void* ignored) +{ + thread_id sender; + Feed* feedBuffer = new Feed(); + + while (receive_data(&sender, (void*)feedBuffer, sizeof(Feed)) != 0) { + BList entries; + + if (feedBuffer->IsAtom()) { + AtomFeed* feed = (AtomFeed*)malloc(sizeof(AtomFeed)); + feed = new AtomFeed(feedBuffer); + feed->Parse(); + entries = feed->GetEntries(); + delete(feed); + } + if (feedBuffer->IsRss()) { + RssFeed* feed = (RssFeed*)malloc(sizeof(RssFeed)); + feed = new RssFeed(feedBuffer); + feed->Parse(); + entries = feed->GetEntries(); + delete(feed); + } + + for (int i = 0; i < entries.CountItems(); i++) + ((Entry*)entries.ItemAt(i))->Filetize(true); + } + + delete (feedBuffer); + return 0; +} diff --git a/src/FeedController.h b/src/FeedController.h new file mode 100644 index 0000000..24e5877 --- /dev/null +++ b/src/FeedController.h @@ -0,0 +1,39 @@ +/* + * Copyright 2020, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef FEEDCONTROLLER_H +#define FEEDCONTROLLER_H + +#include +#include + +class BMessage; + + +enum +{ + kEnqueueFeed = 'fenq', + kClearQueue = 'frmq', + kDownloadComplete = 'fdpr', + kQueueProgress = 'fqpr' +}; + + +class FeedController{ +public: + FeedController(); + ~FeedController(); + void MessageReceived(BMessage* msg); + +private: + static int32 _DownloadLoop(void* ignored); + static int32 _ParseLoop(void* ignored); + + thread_id fDownloadThread; + thread_id fParseThread; +}; + + +#endif // FEEDCONTROLLER_H + diff --git a/src/Invocation.cpp b/src/Invocation.cpp index 5136aa1..a287286 100644 --- a/src/Invocation.cpp +++ b/src/Invocation.cpp @@ -124,41 +124,3 @@ freeargInvocation(int argc, char** argv, int optind) } -bool -processEntry(void* entry) -{ - Entry* entryPtr = (Entry*)entry; - entryPtr->Filetize(false); - return false; -} - - -bool -processFeed(void* feedArg) -{ - BString* feedStr = (BString*)feedArg; - Feed* testFeed = new Feed(*(feedStr)); - BList entries; - - if (testFeed->IsUpdated() == false - && ((App*)be_app)->cfg->updateFeeds == true) - return false; - - if (testFeed->IsAtom()) { - AtomFeed* feed = (AtomFeed*)malloc(sizeof(AtomFeed)); - feed = new AtomFeed(testFeed); - feed->Parse(); - entries = feed->GetEntries(); - } - if (testFeed->IsRss()) { - RssFeed* feed = (RssFeed*)malloc(sizeof(RssFeed)); - feed = new RssFeed(testFeed); - feed->Parse(); - entries = feed->GetEntries(); - } - - entries.DoForEach(&processEntry); - return false; -} - -