Download timeout; better argv handling
This commit is contained in:
parent
0e0bb2ed91
commit
08d5a73f89
78
src/App.cpp
78
src/App.cpp
|
@ -15,7 +15,6 @@
|
|||
#include "Entry.h"
|
||||
#include "Feed.h"
|
||||
#include "FeedController.h"
|
||||
#include "Invocation.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Mimetypes.h"
|
||||
#include "RssFeed.h"
|
||||
|
@ -26,17 +25,12 @@ int
|
|||
main(int argc, char** argv)
|
||||
{
|
||||
App* app = new App();
|
||||
usageMsg.ReplaceAll("%app%", "Pogger");
|
||||
feedMimeType();
|
||||
|
||||
app->cfg = new Config;
|
||||
app->cfg->Load();
|
||||
|
||||
if (argc == 1)
|
||||
app->Run();
|
||||
else
|
||||
cliStart(argc, argv);
|
||||
|
||||
|
||||
if ( app->cfg->will_save == true )
|
||||
app->cfg->Save();
|
||||
|
@ -45,23 +39,6 @@ main(int argc, char** argv)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
cliStart(int argc, char** argv)
|
||||
{
|
||||
invocation(argc, argv);
|
||||
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")
|
||||
{
|
||||
fMainWindow = new MainWindow();
|
||||
|
@ -101,43 +78,20 @@ App::MessageReceived(BMessage* msg)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
App::ArgvReceived(int32 argc, char** argv)
|
||||
{
|
||||
for (int i = 1; i < argc; i++) {
|
||||
Feed* newFeed = new Feed(argv[i]);
|
||||
|
||||
BMessage* enqueue = new BMessage(kEnqueueFeed);
|
||||
enqueue->AddData("feeds", B_RAW_TYPE, (void*)newFeed, sizeof(Feed));
|
||||
|
||||
MessageReceived(enqueue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* configPath = "/boot/home/config/settings/Pogger/";
|
||||
BString usageMsg =
|
||||
"Usage: %app% [-hvDus] [-tT datetime] [-cCO path] \n"
|
||||
" %app% [-hvs] [-tTcCO] ( <text/xml file> | <META:url file> | <url> )\n"
|
||||
"\n"
|
||||
"%app%, a RSS and Atom feed parser/daemon.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help - Print this usage info.\n"
|
||||
" -v, --verbose - Print verbose (debug) info.\n"
|
||||
" -O, --output - Output dir for item files. (Default: ~/feeds/)\n"
|
||||
" -t, --before - Only return items published before this datetime.\n"
|
||||
" -T, --after - Only return items published after this datetime.\n"
|
||||
" -c, --config - Path to config dir. (Default: ~/config/settings/Pogger/)\n"
|
||||
" -C, --cache - Path to cache. (Default: ~/config/cache/Pogger/)\n"
|
||||
" -s, --save - Save the args of `-m`, `-C`, and `-O` to config.\n"
|
||||
" -u, --update - Update all feeds, but don't start daemon.\n"
|
||||
" -D, --foreground - Run in the foreground, do not daemonize.\n"
|
||||
" `-u` and `-D` only apply when running without file/url arg.\n"
|
||||
"\n"
|
||||
"When invoked without a file or URL, will search for any new feed items\n"
|
||||
"published since last check by by any 'feed file' placed in the config\n"
|
||||
"directory (default: ~/config/settings/Rifen/feeds/) and create their\n"
|
||||
"corresponding files.\n"
|
||||
"\n"
|
||||
"When invoked with a file or URL, will create files from items contained\n"
|
||||
"within the given file or URL.\n"
|
||||
"\n"
|
||||
"'Feed files' are files with a 'META:url' attribute containing the\n"
|
||||
"corresponding URL to the feed's XML.\n"
|
||||
"\n"
|
||||
"Both -t and -T use the ISO 8601 format for specifying datetimes:\n"
|
||||
" YYYY-MM-DDTHH:MM:SS - 2020-01-01T07:07:07\n"
|
||||
"\n"
|
||||
"NOTE: This message doesn't reflect reality. This is more of a spec of\n"
|
||||
" what I hope this program will be. As of now, running %app%\n"
|
||||
" without a file/url free-argument is invalid, as the daemon\n"
|
||||
" isn't implemented at all. As such, -D -u and -C are non-functional.\n"
|
||||
" But it sure can turn an XML feed into files! Lol.\n"
|
||||
;
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ class App : public BApplication
|
|||
public:
|
||||
App(void);
|
||||
void MessageReceived(BMessage* msg);
|
||||
void ArgvReceived(int32 argc, char** argv);
|
||||
|
||||
|
||||
Config* cfg;
|
||||
MainWindow* fMainWindow;
|
||||
|
@ -29,14 +31,9 @@ private:
|
|||
FeedController* fFeedController;
|
||||
};
|
||||
|
||||
|
||||
int main ( int, char** );
|
||||
void cliStart ( int, char** );
|
||||
|
||||
|
||||
|
||||
extern const char* configPath;
|
||||
extern BString usageMsg;
|
||||
|
||||
|
||||
#endif // APP_H
|
||||
|
|
17
src/Feed.cpp
17
src/Feed.cpp
|
@ -66,22 +66,23 @@ Feed::FetchRemoteFeed()
|
|||
BUrl givenUrl = BUrl(inputPath);
|
||||
time_t tt_lastDate = 0;
|
||||
BDateTime* lastDate = new BDateTime();
|
||||
BString* newHash = new BString();
|
||||
char oldHash[41];
|
||||
BString newHash;
|
||||
BString oldHash;
|
||||
|
||||
BFile* cacheFile = new BFile(GetCachePath(), B_READ_WRITE | B_CREATE_FILE);
|
||||
|
||||
cacheFile->ReadAttr("LastHash", B_STRING_TYPE, 0, oldHash, 41);
|
||||
// cacheFile->ReadAttr("LastHash", B_STRING_TYPE, 0, oldHash, 41);
|
||||
cacheFile->ReadAttrString("LastHash", &oldHash);
|
||||
|
||||
if (((App*)be_app)->cfg->verbose)
|
||||
printf("Saving %s...\n", inputPath.String());
|
||||
|
||||
webFetch(BUrl(inputPath), cacheFile, newHash);
|
||||
fetch(BUrl(inputPath), cacheFile, &newHash, 30);
|
||||
cacheFile->WriteAttrString("LastHash", &newHash);
|
||||
// cacheFile->WriteAttr("LastHash", B_STRING_TYPE, 0,
|
||||
// newHash.String(), newHash.CountChars());
|
||||
|
||||
cacheFile->WriteAttr("LastHash", B_STRING_TYPE, 0,
|
||||
newHash->String(), newHash->CountChars());
|
||||
|
||||
if (*(newHash) == BString(oldHash))
|
||||
if (newHash == oldHash)
|
||||
updated = false;
|
||||
|
||||
fetched = true;
|
||||
|
|
|
@ -88,12 +88,12 @@ FeedController::_DownloadLoop(void* ignored)
|
|||
Feed* feedBuffer = new Feed();
|
||||
|
||||
while (receive_data(&sender, (void*)feedBuffer, sizeof(Feed)) != 0) {
|
||||
printf( "%s\n\n", feedBuffer->GetCachePath().String());
|
||||
feedBuffer->FetchRemoteFeed();
|
||||
|
||||
BMessage* downloaded = new BMessage(kDownloadComplete);
|
||||
downloaded->AddData("feeds", B_RAW_TYPE, feedBuffer, sizeof(Feed));
|
||||
|
||||
|
||||
((App*)be_app)->MessageReceived(downloaded);
|
||||
}
|
||||
|
||||
|
@ -133,3 +133,5 @@ FeedController::_ParseLoop(void* ignored)
|
|||
delete (feedBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include "Invocation.h"
|
||||
|
||||
#include <StorageKit.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "App.h"
|
||||
#include "AtomFeed.h"
|
||||
#include "Config.h"
|
||||
#include "Entry.h"
|
||||
#include "Feed.h"
|
||||
#include "Mimetypes.h"
|
||||
#include "RssFeed.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
int
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "%s", usageMsg.String());
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
invocation(int argc, char** argv)
|
||||
{
|
||||
Config* cfg = ((App*)be_app)->cfg;
|
||||
BDateTime maxDate;
|
||||
BDateTime minDate;
|
||||
|
||||
static struct option sLongOptions[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "config", required_argument, 0, 'c' },
|
||||
{ "cache", required_argument, 0, 'C' },
|
||||
{ "before", required_argument, 0, 't' },
|
||||
{ "after", required_argument, 0, 'T' },
|
||||
{ "output", required_argument, 0, 'O' },
|
||||
{ "foreground", no_argument, 0, 'D' },
|
||||
{ "update", no_argument, 0, 'u' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
while (true) {
|
||||
opterr = 0;
|
||||
int c = getopt_long(argc, argv, "+hsuvDm:O:T:t:c:C:", sLongOptions, NULL);
|
||||
|
||||
switch (c) {
|
||||
case -1:
|
||||
freeargInvocation(argc, argv, optind);
|
||||
return 0;
|
||||
case 'h':
|
||||
return usage();
|
||||
case 'c':
|
||||
cfg->configDir = BString(optarg);
|
||||
break;
|
||||
case 'C':
|
||||
cfg->cacheDir = BString(optarg);
|
||||
break;
|
||||
case 's':
|
||||
cfg->will_save = true;
|
||||
case 't':
|
||||
minDate = dateRfc3339ToBDate(optarg);
|
||||
if (minDate != NULL)
|
||||
cfg->minDate = minDate;
|
||||
else {
|
||||
fprintf(stderr, "Invalid date format for `-%c'.\n", optopt);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
maxDate = dateRfc3339ToBDate(optarg);
|
||||
if (maxDate != NULL)
|
||||
cfg->maxDate = maxDate;
|
||||
else {
|
||||
fprintf(stderr, "Invalid date format for `-%c'.\n", optopt);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
cfg->outDir = BString(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
cfg->updateFeeds = true;
|
||||
break;
|
||||
case 'v':
|
||||
cfg->verbose = true;
|
||||
break;
|
||||
case 'D':
|
||||
cfg->daemon = false;
|
||||
break;
|
||||
case '?':
|
||||
if (optopt == 'O' || optopt == 'm')
|
||||
fprintf(stderr, "Option `-%c` requires an argument.\n",
|
||||
optopt);
|
||||
else
|
||||
fprintf(stderr, "Unknown option `-%c`.\n", optopt);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
freeargInvocation(int argc, char** argv, int optind)
|
||||
{
|
||||
Config* cfg = ((App*)be_app)->cfg;
|
||||
if (optind < argc) {
|
||||
int freeargc = argc - optind;
|
||||
cfg->targetFeeds = BList(freeargc);
|
||||
|
||||
for (int i = 0; i < freeargc; i++) {
|
||||
BString* newFeed = new BString(argv[optind + i]);
|
||||
cfg->targetFeeds.AddItem(newFeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef INVOCATION_H
|
||||
#define INVOCATION_H
|
||||
|
||||
|
||||
int usage ( );
|
||||
int invocation ( int, char** );
|
||||
void freeargInvocation ( int, char**, int );
|
||||
bool processItem ( void* );
|
||||
bool processFeed ( void* );
|
||||
|
||||
|
||||
#endif
|
||||
|
22
src/Util.cpp
22
src/Util.cpp
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "Util.h"
|
||||
|
||||
#include <OS.h>
|
||||
#include <Url.h>
|
||||
#include <UrlProtocolRoster.h>
|
||||
#include <UrlRequest.h>
|
||||
|
@ -95,15 +96,7 @@ isRemotePath(BString path) {
|
|||
|
||||
|
||||
int32
|
||||
webFetch(BUrl url, BDataIO* reply)
|
||||
{
|
||||
BString* ignored = new BString();
|
||||
return webFetch(url, reply, ignored);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
webFetch(BUrl url, BDataIO* reply, BString* hash)
|
||||
fetch(BUrl url, BDataIO* reply, BString* hash, int timeout)
|
||||
{
|
||||
ProtocolListener listener(true);
|
||||
boost::uuids::detail::sha1 sha1;
|
||||
|
@ -113,13 +106,18 @@ webFetch(BUrl url, BDataIO* reply, BString* hash)
|
|||
listener.SetDownloadIO(reply);
|
||||
listener.SetSha1(&sha1);
|
||||
|
||||
time_t startTime = time(0);
|
||||
thread_id thread = request->Run();
|
||||
wait_for_thread(thread, NULL);
|
||||
thread_info t_info;
|
||||
|
||||
while (time(0) - startTime < timeout
|
||||
&& get_thread_info(thread, &t_info) == B_OK)
|
||||
snooze(100000);
|
||||
|
||||
kill_thread(thread);
|
||||
|
||||
*(hash) = listener.GetHash();
|
||||
|
||||
return request->Status();
|
||||
return 200;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@ bool withinDateRange(BDateTime, BDateTime, BDateTime);
|
|||
|
||||
bool isRemotePath(BString);
|
||||
|
||||
int32 webFetch(BUrl, BDataIO*, BString*);
|
||||
int32 webFetch(BUrl, BDataIO*);
|
||||
int32 fetch(BUrl url, BDataIO* reply, BString* hash, int timeout);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Ŝarĝante…
Reference in New Issue