graceful shutdown by SIGINT

ver3
acetone 2023-05-04 22:21:57 +03:00
parent 9020aea208
commit 89f471736d
9 changed files with 93 additions and 17 deletions

View File

@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <QDebug>
#include <QThread>
#include <QApplication>
HttpServer::HttpServer(QObject *parent) : QTcpServer(parent)
{
@ -36,9 +37,21 @@ HttpServer::HttpServer(QObject *parent) : QTcpServer(parent)
}
qInfo().noquote() << "[WebUI] HTTP server started at" << Config::webUiAddress() + ":" + QString::number( Config::webUiPort() );
qInfo().noquote() << "[WebUI] HTTP server threads:" << m_pool->maxThreadCount();
connect (this, &HttpServer::doStopPrivate, this, &HttpServer::stopPrivate, Qt::QueuedConnection);
}
HttpServer::~HttpServer()
{
qInfo().noquote() << "[WebUI] Stopped";
}
void HttpServer::stop()
{
emit doStopPrivate();
}
void HttpServer::stopPrivate()
{
if (QTcpServer::isListening()) QTcpServer::close();
@ -47,9 +60,10 @@ HttpServer::~HttpServer()
m_pool->clear();
if (not m_pool->waitForDone(100))
{
qWarning() << "[WebUI] Thread pool of HTTP server not finished at 100ms";
qWarning() << "[WebUI] Thread pool not finished in 100 ms";
}
m_pool->deleteLater();
m_pool = nullptr;
}
}

View File

@ -47,6 +47,13 @@ class HttpServer : public QTcpServer
public:
HttpServer(QObject* parent = nullptr);
~HttpServer();
void stop();
signals:
void doStopPrivate();
private slots:
void stopPrivate();
protected:
void incomingConnection(qintptr handle);

View File

@ -46,6 +46,11 @@ constexpr const char DIRECT_MESSAGE_TRIGGER_VOICEGATE[] = "voice";
IRCNetworkClient::IRCNetworkClient(QObject *parent) : QObject(parent) {}
IRCNetworkClient::~IRCNetworkClient()
{
LOG_INFO << "Stopped";
}
void IRCNetworkClient::setConfig(QSharedPointer<Config::Network> config)
{
if (config->instance != nullptr)
@ -327,7 +332,7 @@ void IRCNetworkClient::Slot_onWelcome()
void IRCNetworkClient::Slot_onDisconnected()
{
LOG_INFO << "Disconnected from server. Auto reconnect" << (m_config->autoReconnect ? "enabled" : "disabled");
LOG_INFO << "Disconnected from server. Auto reconnect" << (m_config->autoReconnect ? "enabled" : "disabled") + QString(".");
if (m_config->autoReconnect)
{
QThread::sleep(m_sleepPeriod >= 20 ? m_sleepPeriod : m_sleepPeriod++);
@ -337,9 +342,11 @@ void IRCNetworkClient::Slot_onDisconnected()
void IRCNetworkClient::stopPrivate()
{
connect (m_network.data(), &libircclient::Network::Event_Disconnected, m_network.data(), &libircclient::Network::stop);
connect (m_network.data(), &libircclient::Network::Event_stopped, this, &IRCNetworkClient::stopped);
m_config->autoReconnect = false;
m_network->Disconnect("Shutdowned");
connect (m_network.data(), &libircclient::Network::Event_Disconnected, this, [&](){ emit stopped(); });
}
void IRCNetworkClient::processVoiceRequest(const QString& sender)

View File

@ -34,6 +34,7 @@ class IRCNetworkClient : public QObject
Q_OBJECT
public:
IRCNetworkClient(QObject* parent = nullptr);
~IRCNetworkClient();
void setConfig(QSharedPointer<Config::Network> config);
// after config change; voiceGate have effect in run-time automatically
uint reloadChannelList();
@ -82,6 +83,6 @@ private:
QMutex m_mtxNetworkChannelsIteration;
QMutex m_mtxvoiceGateRequestsTimestamp;
uint8_t m_sleepPeriod = 1;
uint8_t m_sleepPeriod = 1; // reconnect timer
};

View File

@ -24,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <QDebug>
#include <QApplication>
QList<QSharedPointer<IRCNetworkClient>> IRCNetworkClientStarter::m_instanses;
QList<QPair<QSharedPointer<IRCNetworkClient>, QThread*>> IRCNetworkClientStarter::m_instanses;
void IRCNetworkClientStarter::run()
{
@ -40,9 +40,9 @@ void IRCNetworkClientStarter::run()
QThread* thread = new QThread;
network->moveToThread(thread);
network->setConfig(config);
m_instanses.push_back(network);
m_instanses.push_back( {network, thread} );
QObject::connect(thread, &QThread::started, network.data(), &IRCNetworkClient::start);
QObject::connect(network.data(), &IRCNetworkClient::stopped, thread, &QThread::terminate);
QObject::connect(network.data(), &IRCNetworkClient::stopped, thread, &QThread::quit, Qt::DirectConnection);
thread->start();
qDebug().noquote() << "["+config->networkName+"]" << "Thread started";
}
@ -52,9 +52,15 @@ void IRCNetworkClientStarter::stop()
{
foreach (auto inst, m_instanses)
{
inst->stop();
qDebug().noquote() << "["+inst->m_config->networkName+"]" << "Shutdown requested";
inst.first->stop();
qDebug().noquote() << "["+inst.first->m_config->networkName+"]" << "Shutdown requested";
QApplication::sync();
if (not inst.second->wait(1000))
{
qWarning().noquote() << "[Core] IRC network client thread not stopped properly in 1000 ms";
}
inst.second->deleteLater();
}
m_instanses.clear();
}

View File

@ -32,6 +32,6 @@ public:
static void stop();
private:
static QList<QSharedPointer<IRCNetworkClient>> m_instanses;
static QList<QPair<QSharedPointer<IRCNetworkClient>, QThread*>> m_instanses;
};

View File

@ -10,9 +10,12 @@
// Copyright (c) Petr Bena 2015 - 2019
// Modified for IRCaBot project by acetone, 2023
#include <QtNetwork>
#include <QAbstractSocket>
#include <QDebug>
#include <QApplication>
#include "network.h"
#include "server.h"
#include "channel.h"
@ -53,20 +56,26 @@ Network::Network(libirc::ServerAddress &server, const QString &name, const Encod
this->channelsToJoin.append(channel);
}
}
connect(this, &Network::Event_doStopPrivate, this, &Network::onStopPrivate, Qt::QueuedConnection);
}
Network::Network(const QHash<QString, QVariant> &hash) : libirc::Network("")
{
this->initialize();
this->LoadHash(hash);
connect(this, &Network::Event_doStopPrivate, this, &Network::onStopPrivate, Qt::QueuedConnection);
}
Network::~Network()
{
delete this->server;
this->deleteTimers();
delete this->socket;
this->freemm();
stop();
}
void Network::stop()
{
emit Event_doStopPrivate();
}
void Network::Connect()
@ -754,6 +763,25 @@ QHash<QString, QVariant> Network::ToHash()
return hash;
}
void Network::onStopPrivate()
{
if (this->server)
{
delete this->server;
this->server = nullptr;
}
this->deleteTimers();
if (this->socket)
{
delete this->socket;
this->socket = nullptr;
}
this->freemm();
emit Event_stopped();
QThread::msleep(10);
}
// This is a slot so don't change the signature to const QList<QSslError> &errors
void Network::OnSslHandshakeFailure(QList<QSslError> errors)
{

View File

@ -10,6 +10,8 @@
// Copyright (c) Petr Bena 2015 - 2019
// Modified for IRCaBot project by acetone, 2023
#ifndef NETWORK_H
#define NETWORK_H
@ -25,7 +27,6 @@
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QTimer>
#include "../libirc/irc_standards.h"
class QTcpSocket;
@ -67,6 +68,7 @@ namespace libircclient
Network(libirc::ServerAddress &server, const QString &name, const Encoding &enc = EncodingDefault);
Network(const QHash<QString, QVariant> &hash);
~Network() override;
void stop();
virtual void Connect();
virtual void Reconnect();
virtual void Disconnect(QString reason = "");
@ -305,6 +307,13 @@ namespace libircclient
void Event_CAP_Timeout();
void Event_CAP_RequestedCapNotSupported(QString name);
// Shutdown
void Event_doStopPrivate();
void Event_stopped();
private slots:
void onStopPrivate();
protected slots:
virtual void OnSslHandshakeFailure(QList<QSslError> errors);
virtual void OnError(QAbstractSocket::SocketError er);

View File

@ -39,7 +39,10 @@ void signalHandler(int SIGNAL)
{
if (SIGNAL == SIGINT)
{
qInfo() << "SIGINT handling...";
qInfo().noquote() << "";
qInfo().noquote() << "SIGINT handling...";
webUi->stop();
QApplication::sync();
webUi->deleteLater();
IRCNetworkClientStarter::stop();
QApplication::sync();
@ -118,7 +121,8 @@ int main(int argc, char *argv[])
" _ ___ __ __ ___ ___ _____ _ ___\n"
"| | | |_) / /` / /\\ | |_) / / \\ | | \\ \\ / ) )\n"
"|_| |_| \\ \\_\\_, /_/--\\ |_|_) \\_\\_/ |_| \\_\\/ _)_)\n"
<< info::SOURCE_CODE << " " << info::VERSION << "\n" <<std::endl;
<< info::SOURCE_CODE << " " << info::VERSION << "\n"
<< info::NAME << ": " << info::COPYRIGHT << "\n" <<std::endl;
QString error;
if (not Config::initFromFile(&error))