add socket activation for extensions (#118)

Option `X-AW-Socket` is used. Any message received by this socket will
trigger extension update. If the option is set, `X-AW-Interval` will be
ignored
This commit is contained in:
Evgenii Alekseev 2017-02-06 12:16:16 +03:00
parent 9543122816
commit bfdaadfc8b
19 changed files with 204 additions and 40 deletions

View File

@ -18,6 +18,7 @@
#include "abstractextitem.h"
#include <QDir>
#include <QLocalServer>
#include <QSettings>
#include <QStandardPaths>
#include <QTime>
@ -41,6 +42,12 @@ AbstractExtItem::AbstractExtItem(QWidget *parent, const QString filePath)
AbstractExtItem::~AbstractExtItem()
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
if (m_socket) {
m_socket->close();
m_socket->removeServer(socket());
delete m_socket;
}
}
@ -65,6 +72,7 @@ void AbstractExtItem::copyDefaults(AbstractExtItem *_other) const
_other->setComment(comment());
_other->setInterval(interval());
_other->setName(name());
_other->setSocket(socket());
}
@ -125,6 +133,12 @@ int AbstractExtItem::number() const
}
QString AbstractExtItem::socket() const
{
return m_socketFile;
}
QString AbstractExtItem::tag(const QString _type) const
{
qCDebug(LOG_LIB) << "Tag type" << _type;
@ -196,6 +210,44 @@ void AbstractExtItem::setNumber(int _number)
}
void AbstractExtItem::setSocket(const QString _socket)
{
qCDebug(LOG_LIB) << "Socket" << _socket;
// remove old socket first
deinitSocket();
m_socketFile = _socket;
if (socket().isEmpty())
return;
}
void AbstractExtItem::deinitSocket()
{
if (!m_socket)
return;
m_socket->close();
m_socket->removeServer(socket());
delete m_socket;
disconnect(m_socket, SIGNAL(newConnection()), this,
SLOT(newConnectionReceived()));
}
void AbstractExtItem::initSocket()
{
// remove old socket first
deinitSocket();
m_socket = new QLocalServer(this);
bool listening = m_socket->listen(socket());
qCInfo(LOG_LIB) << "Server listening on" << socket() << listening;
connect(m_socket, SIGNAL(newConnection()), this,
SLOT(newConnectionReceived()));
}
void AbstractExtItem::readConfiguration()
{
QSettings settings(m_fileName, QSettings::IniFormat);
@ -210,6 +262,7 @@ void AbstractExtItem::readConfiguration()
== QString("true"));
setInterval(settings.value(QString("X-AW-Interval"), interval()).toInt());
setNumber(settings.value(QString("X-AW-Number"), number()).toInt());
setSocket(settings.value(QString("X-AW-Socket"), socket()).toString());
settings.endGroup();
}
@ -236,7 +289,14 @@ void AbstractExtItem::writeConfiguration() const
settings.setValue(QString("X-AW-Active"), QVariant(isActive()).toString());
settings.setValue(QString("X-AW-Interval"), interval());
settings.setValue(QString("X-AW-Number"), number());
settings.setValue(QString("X-AW-Socket"), socket());
settings.endGroup();
settings.sync();
}
void AbstractExtItem::newConnectionReceived()
{
emit(socketActivated());
}

View File

@ -22,6 +22,8 @@
#include <QVariant>
class QLocalServer;
class AbstractExtItem : public QDialog
{
Q_OBJECT
@ -32,6 +34,7 @@ class AbstractExtItem : public QDialog
Q_PROPERTY(int interval READ interval WRITE setInterval)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int number READ number WRITE setNumber)
Q_PROPERTY(QString socket READ socket WRITE setSocket)
Q_PROPERTY(QString uniq READ uniq)
public:
@ -51,6 +54,7 @@ public:
bool isActive() const;
QString name() const;
int number() const;
QString socket() const;
QString tag(const QString _type) const;
virtual QString uniq() const = 0;
// set methods
@ -60,17 +64,24 @@ public:
void setInterval(const int _interval = 1);
void setName(const QString _name = QString("none"));
void setNumber(int _number = -1);
void setSocket(const QString _socket = QString(""));
signals:
void dataReceived(const QVariantHash &data);
void socketActivated();
public slots:
virtual void deinitSocket();
virtual void initSocket();
virtual void readConfiguration();
virtual QVariantHash run() = 0;
virtual int showConfiguration(const QVariant args = QVariant()) = 0;
bool tryDelete() const;
virtual void writeConfiguration() const;
private slots:
void newConnectionReceived();
private:
QString m_fileName = QString("/dev/null");
virtual void translate() = 0;
@ -81,6 +92,8 @@ private:
int m_interval = 1;
QString m_name = QString("none");
int m_number = -1;
QLocalServer *m_socket = nullptr;
QString m_socketFile = QString("");
};

View File

@ -61,6 +61,15 @@ public:
qCInfo(LOG_LIB) << "Dialog returns" << ret;
};
void initSockets()
{
// HACK as soon as per one widget instance we have two objects each of
// them will try to control socket, whereas actually only one of them
// should be owner of the socket
for (auto item : m_items)
item->initSocket();
}
T *itemByTag(const QString _tag, const QString _type) const
{
qCDebug(LOG_LIB) << "Tag" << _tag << "with used type" << _type;

View File

@ -49,6 +49,8 @@ ExtNetworkRequest::ExtNetworkRequest(QWidget *parent, const QString filePath)
m_manager = new QNetworkAccessManager(nullptr);
connect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(networkReplyReceived(QNetworkReply *)));
connect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
}
@ -58,6 +60,7 @@ ExtNetworkRequest::~ExtNetworkRequest()
disconnect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(networkReplyReceived(QNetworkReply *)));
disconnect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
m_manager->deleteLater();
delete ui;
@ -116,15 +119,11 @@ void ExtNetworkRequest::readConfiguration()
QVariantHash ExtNetworkRequest::run()
{
if ((!isActive()) || (m_isRunning))
if (!canRun())
return m_values;
if (m_times == 1) {
qCInfo(LOG_LIB) << "Send request";
m_isRunning = true;
QNetworkReply *reply = m_manager->get(QNetworkRequest(m_url));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
if (m_times == 1)
sendRequest();
// update value
if (m_times >= interval())
@ -193,6 +192,20 @@ void ExtNetworkRequest::networkReplyReceived(QNetworkReply *reply)
}
void ExtNetworkRequest::sendRequest()
{
m_isRunning = true;
QNetworkReply *reply = m_manager->get(QNetworkRequest(m_url));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
bool ExtNetworkRequest::canRun() const
{
return ((isActive()) && (!m_isRunning) && (socket().isEmpty()));
}
void ExtNetworkRequest::initUrl()
{
m_url = QUrl(m_stringUrl);

View File

@ -52,12 +52,14 @@ public slots:
private slots:
void networkReplyReceived(QNetworkReply *reply);
void sendRequest();
private:
QNetworkAccessManager *m_manager = nullptr;
QUrl m_url;
bool m_isRunning = false;
Ui::ExtNetworkRequest *ui = nullptr;
bool canRun() const;
void initUrl();
void translate();
// properties

View File

@ -59,6 +59,8 @@ ExtQuotes::ExtQuotes(QWidget *parent, const QString filePath)
m_manager = new QNetworkAccessManager(nullptr);
connect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(quotesReplyReceived(QNetworkReply *)));
connect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
}
@ -68,6 +70,7 @@ ExtQuotes::~ExtQuotes()
disconnect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(quotesReplyReceived(QNetworkReply *)));
disconnect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
m_manager->deleteLater();
delete ui;
@ -125,15 +128,11 @@ void ExtQuotes::readConfiguration()
QVariantHash ExtQuotes::run()
{
if ((!isActive()) || (m_isRunning))
if (!canRun())
return m_values;
if (m_times == 1) {
qCInfo(LOG_LIB) << "Send request";
m_isRunning = true;
QNetworkReply *reply = m_manager->get(QNetworkRequest(m_url));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
if (m_times == 1)
sendRequest();
// update value
if (m_times >= interval())
@ -245,6 +244,20 @@ void ExtQuotes::quotesReplyReceived(QNetworkReply *reply)
}
void ExtQuotes::sendRequest()
{
m_isRunning = true;
QNetworkReply *reply = m_manager->get(QNetworkRequest(m_url));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
bool ExtQuotes::canRun() const
{
return ((isActive()) && (!m_isRunning) && (socket().isEmpty()));
}
void ExtQuotes::initUrl()
{
// init query

View File

@ -55,12 +55,14 @@ public slots:
private slots:
void quotesReplyReceived(QNetworkReply *reply);
void sendRequest();
private:
QNetworkAccessManager *m_manager = nullptr;
QUrl m_url;
bool m_isRunning = false;
Ui::ExtQuotes *ui = nullptr;
bool canRun() const;
void initUrl();
void translate();
// properties

View File

@ -48,6 +48,8 @@ ExtScript::ExtScript(QWidget *parent, const QString filePath)
connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(updateValue()));
m_process->waitForFinished(0);
connect(this, SIGNAL(socketActivated()), this, SLOT(startProcess()));
}
@ -55,8 +57,11 @@ ExtScript::~ExtScript()
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
disconnect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(updateValue()));
m_process->kill();
m_process->deleteLater();
disconnect(this, SIGNAL(socketActivated()), this, SLOT(startProcess()));
delete ui;
}
@ -260,22 +265,14 @@ void ExtScript::readJsonFilters()
}
#include <QThread>
QVariantHash ExtScript::run()
{
if (!isActive())
if (!canRun())
return m_values;
if (m_process->state() != QProcess::NotRunning)
qCWarning(LOG_LIB) << "Another process is already running"
<< m_process->state();
if ((m_times == 1) && (m_process->state() == QProcess::NotRunning)) {
QStringList cmdList;
if (!prefix().isEmpty())
cmdList.append(prefix());
cmdList.append(executable());
qCInfo(LOG_LIB) << "Run cmd" << cmdList.join(QChar(' '));
m_process->start(cmdList.join(QChar(' ')));
}
if (m_times == 1)
startProcess();
// update value
if (m_times >= interval())
@ -350,6 +347,17 @@ void ExtScript::writeConfiguration() const
}
void ExtScript::startProcess()
{
QStringList cmdList;
if (!prefix().isEmpty())
cmdList.append(prefix());
cmdList.append(executable());
qCInfo(LOG_LIB) << "Run cmd" << cmdList.join(QChar(' '));
m_process->start(cmdList.join(QChar(' ')));
}
void ExtScript::updateValue()
{
qCInfo(LOG_LIB) << "Cmd returns" << m_process->exitCode();
@ -383,6 +391,13 @@ void ExtScript::updateValue()
}
bool ExtScript::canRun() const
{
return ((isActive()) && (m_process->state() == QProcess::NotRunning)
&& (socket().isEmpty()));
}
void ExtScript::translate()
{
ui->label_name->setText(i18n("Name"));

View File

@ -73,11 +73,13 @@ public slots:
void writeConfiguration() const;
private slots:
void startProcess();
void updateValue();
private:
QProcess *m_process = nullptr;
Ui::ExtScript *ui = nullptr;
bool canRun() const;
void translate();
// properties
QString m_executable = QString("/usr/bin/true");

View File

@ -44,6 +44,8 @@ ExtUpgrade::ExtUpgrade(QWidget *parent, const QString filePath)
m_process = new QProcess(nullptr);
connect(m_process, SIGNAL(finished(int)), this, SLOT(updateValue()));
m_process->waitForFinished(0);
connect(this, SIGNAL(socketActivated()), this, SLOT(startProcess()));
}
@ -53,6 +55,7 @@ ExtUpgrade::~ExtUpgrade()
m_process->kill();
m_process->deleteLater();
disconnect(this, SIGNAL(socketActivated()), this, SLOT(startProcess()));
delete ui;
}
@ -145,11 +148,8 @@ QVariantHash ExtUpgrade::run()
if (!isActive())
return m_values;
if ((m_times == 1) && (m_process->state() == QProcess::NotRunning)) {
QString cmd = QString("sh -c \"%1\"").arg(executable());
qCInfo(LOG_LIB) << "Run cmd" << cmd;
m_process->start(cmd);
}
if (m_times == 1)
startProcess();
// update value
if (m_times >= interval())
@ -209,6 +209,14 @@ void ExtUpgrade::writeConfiguration() const
}
void ExtUpgrade::startProcess()
{
QString cmd = QString("sh -c \"%1\"").arg(executable());
qCInfo(LOG_LIB) << "Run cmd" << cmd;
m_process->start(cmd);
}
void ExtUpgrade::updateValue()
{
qCInfo(LOG_LIB) << "Cmd returns" << m_process->exitCode();
@ -230,6 +238,13 @@ void ExtUpgrade::updateValue()
}
bool ExtUpgrade::canRun()
{
return ((isActive()) && (m_process->state() == QProcess::NotRunning)
&& (socket().isEmpty()));
}
void ExtUpgrade::translate()
{
ui->label_name->setText(i18n("Name"));

View File

@ -56,11 +56,13 @@ public slots:
void writeConfiguration() const;
private slots:
void startProcess();
void updateValue();
private:
QProcess *m_process = nullptr;
Ui::ExtUpgrade *ui = nullptr;
bool canRun();
void translate();
// properties
QString m_executable = QString("/usr/bin/true");

View File

@ -58,6 +58,8 @@ ExtWeather::ExtWeather(QWidget *parent, const QString filePath)
m_manager = new QNetworkAccessManager(nullptr);
connect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(weatherReplyReceived(QNetworkReply *)));
connect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
}
@ -67,6 +69,7 @@ ExtWeather::~ExtWeather()
disconnect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(weatherReplyReceived(QNetworkReply *)));
disconnect(this, SIGNAL(socketActivated()), this, SLOT(sendRequest()));
m_manager->deleteLater();
delete m_providerObject;
@ -262,13 +265,8 @@ QVariantHash ExtWeather::run()
if ((!isActive()) || (m_isRunning))
return m_values;
if (m_times == 1) {
qCInfo(LOG_LIB) << "Send request";
m_isRunning = true;
QNetworkReply *reply
= m_manager->get(QNetworkRequest(m_providerObject->url()));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
if (m_times == 1)
sendRequest();
// update value
if (m_times >= interval())
@ -334,6 +332,15 @@ void ExtWeather::writeConfiguration() const
}
void ExtWeather::sendRequest()
{
m_isRunning = true;
QNetworkReply *reply
= m_manager->get(QNetworkRequest(m_providerObject->url()));
new QReplyTimeout(reply, REQUEST_TIMEOUT);
}
void ExtWeather::weatherReplyReceived(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
@ -362,6 +369,12 @@ void ExtWeather::weatherReplyReceived(QNetworkReply *reply)
}
bool ExtWeather::canRun()
{
return ((isActive()) && (!m_isRunning) && (socket().isEmpty()));
}
void ExtWeather::initProvider()
{
delete m_providerObject;

View File

@ -70,6 +70,7 @@ public slots:
void writeConfiguration() const;
private slots:
void sendRequest();
void weatherReplyReceived(QNetworkReply *reply);
private:
@ -77,6 +78,7 @@ private:
AbstractWeatherProvider *m_providerObject = nullptr;
bool m_isRunning = false;
Ui::ExtWeather *ui = nullptr;
bool canRun();
void initProvider();
void translate();
// properties

View File

@ -30,6 +30,7 @@ CustomSource::CustomSource(QObject *parent, const QStringList args)
m_extScripts
= new ExtItemAggregator<ExtScript>(nullptr, QString("scripts"));
m_extScripts->initSockets();
m_sources = getSources();
}

View File

@ -29,6 +29,7 @@ QuotesSource::QuotesSource(QObject *parent, const QStringList args)
qCDebug(LOG_ESS) << __PRETTY_FUNCTION__;
m_extQuotes = new ExtItemAggregator<ExtQuotes>(nullptr, QString("quotes"));
m_extQuotes->initSockets();
m_sources = getSources();
}

View File

@ -30,6 +30,7 @@ RequestSource::RequestSource(QObject *parent, const QStringList args)
m_extNetRequest = new ExtItemAggregator<ExtNetworkRequest>(
nullptr, QString("requests"));
m_extNetRequest->initSockets();
m_sources = getSources();
}

View File

@ -30,6 +30,7 @@ UpgradeSource::UpgradeSource(QObject *parent, const QStringList args)
m_extUpgrade
= new ExtItemAggregator<ExtUpgrade>(nullptr, QString("upgrade"));
m_extUpgrade->initSockets();
m_sources = getSources();
}

View File

@ -30,6 +30,7 @@ WeatherSource::WeatherSource(QObject *parent, const QStringList args)
m_extWeather
= new ExtItemAggregator<ExtWeather>(nullptr, QString("weather"));
m_extWeather->initSockets();
m_sources = getSources();
}

View File

@ -68,7 +68,6 @@ void TestExtQuotes::test_run()
QCOMPARE(firstValue[extQuotes->tag(QString("bid"))].toDouble(), 0.0);
QCOMPARE(firstValue[extQuotes->tag(QString("price"))].toDouble(), 0.0);
for (auto type : types) {
qDebug() << "Test type" << type;
QVERIFY((cache[type].toDouble() > price.first)
&& (cache[type].toDouble() < price.second));
}
@ -93,7 +92,6 @@ void TestExtQuotes::test_derivatives()
= arguments.at(0).toHash()[extQuotes->tag(QString("price"))];
for (auto type : types) {
qDebug() << "Test type" << type;
QCOMPARE(arguments.at(0)
.toHash()[extQuotes->tag(QString("%1chg").arg(type))]
.toDouble(),