Files
pay/modules/social-feed/FeedDataProvider.cpp

173 lines
4.8 KiB
C++

/*
* This file is part of the Flowee project
* Copyright (C) 2025 Tom Zander <tom@flowee.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "FeedDataProvider.h"
#include <utils/Logger.h>
#include <FloweePay.h>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QTimer>
#include <QUrl>
#include <QCoreApplication>
constexpr const char *FEED = "/v/index.json";
constexpr const char *FLOWEE_JSON = "social-feed-flowee.json";
FeedDataProvider::FeedDataProvider(QObject *parent)
: QObject(parent)
{
QFileInfo info(FLOWEE_JSON);
bool useOld = info.exists();
if (useOld) {
m_lastCheck = info.lastModified();
readFeed();
}
if (m_lastCheck.isNull()
|| m_lastCheck.msecsTo(QDateTime::currentDateTime()) > 4 * 60 * 60 * 1000) {
QTimer::singleShot(10, this, SLOT(start()));
}
}
void FeedDataProvider::start()
{
if (m_httpClient)
return;
// Prepare the HTTP request
boost::beast::http::request<boost::beast::http::vector_body<char>> request;
request.version(11);
if (m_lastCheck.isNull())
request.method(boost::beast::http::verb::get);
else
request.method(boost::beast::http::verb::head);
request.target(FEED);
request.set(boost::beast::http::field::host, "flowee.org");
auto *fp = FloweePay::instance();
m_httpClient = SimpleHttpClient::create(fp->ioContext(), fp->sslContext(), request);
connect(m_httpClient.get(), SIGNAL(finished()), this, SLOT(downloadFinished()));
connect(m_httpClient.get(), SIGNAL(errored(SimpleHttpClient::ErrorType)),
this, SLOT(errored(SimpleHttpClient::ErrorType)));
}
void FeedDataProvider::downloadFinished()
{
if (m_httpClient->request().method() == boost::beast::http::verb::head) {
const auto lastModified = m_httpClient->headerDate(boost::beast::http::field::last_modified);
m_httpClient.reset();
// check if the server has a newer one.
if (lastModified > m_lastCheck) {
m_lastCheck = QDateTime();
assert(m_lastCheck.isNull());
start(); // this will now do a download of the actual data.
}
return;
}
if (m_httpClient->httpErrorCode() == 200) {
auto data = m_httpClient->responseBody();
QFile feed(FLOWEE_JSON);
if (feed.open(QIODevice::WriteOnly)) {
feed.write(data.begin(), data.size());
feed.close();
}
readFeed();
}
m_httpClient.reset();
}
void FeedDataProvider::readFeed()
{
QFile feed(FLOWEE_JSON);
if (!feed.open(QIODevice::ReadOnly))
return;
auto data = feed.readAll();
feed.close();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (doc.isNull()) {
logWarning(10052) << "Parsing error of social json";
return;
}
m_listItems.clear();
QJsonArray list = doc.array();
for (auto i = list.begin(); i != list.end(); ++i) {
auto obj = i->toObject();
auto text = obj["text"];
if (!text.isString()) {
logWarning(10052) << "Skipping item in JSON, missing text attribute";
continue;
}
auto *item = new ListItem(this);
item->m_text = text.toString();
item->m_url = obj["url"].toString();
item->m_videoLength = obj["length"].toString();
item->m_title = obj["title"].toString();
auto date = obj["date"].toString();
item->m_date = QDate::fromString(date, Qt::ISODate);
m_listItems.append(item);
}
emit listItemsChanged();
}
QList<ListItem *> FeedDataProvider::listItems() const
{
return m_listItems;
}
void FeedDataProvider::errored(SimpleHttpClient::ErrorType e)
{
logDebug(10052) << "got error on downloading the feed:" << e;
if (m_httpClient.get())
logDebug(10052) << " http error code:" << m_httpClient->httpErrorCode();
}
// ------------------------------------
ListItem::ListItem(QObject *parent)
: QObject(parent)
{
}
QDate ListItem::date() const
{
return m_date;
}
QString ListItem::videoLength() const
{
return m_videoLength;
}
QString ListItem::text() const
{
return m_text;
}
QString ListItem::title() const
{
return m_title;
}
QString ListItem::url() const
{
return m_url;
}