Last active
April 14, 2019 18:16
-
-
Save legnaleurc/1038309 to your computer and use it in GitHub Desktop.
Qt signal/slot + Boost.Coroutine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 2.8) | |
find_package(Qt5Core REQUIRED) | |
find_package(Qt5Network REQUIRED) | |
set(CMAKE_AUTOMOC ON) | |
find_package(Boost REQUIRED COMPONENTS coroutine system context) | |
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") | |
set(SOURCES "src/main.cpp" "src/task.cpp" "src/task.hpp" "src/task_p.hpp" "src/httpserver.cpp" "src/httpserver.hpp") | |
add_executable(server ${SOURCES}) | |
qt5_use_modules(server Core Network) | |
target_link_libraries(server ${Boost_LIBRARIES}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "httpserver.hpp" | |
#include <QtNetwork/QTcpSocket> | |
#include <QtCore/QCoreApplication> | |
#include <QtCore/QTextCodec> | |
#include <QtCore/QUrl> | |
#include <QtCore/QUrlQuery> | |
#include "task.hpp" | |
namespace { | |
void handleRequest (QTextStream & sio) { | |
auto line = sio.readLine(); | |
auto parts = line.split(" "); | |
auto method = parts[0]; | |
auto rawResource = parts[1]; | |
auto protocol = parts[2]; | |
QUrl resource(rawResource); | |
QUrlQuery query(resource); | |
qDebug() << method; | |
qDebug() << resource.path(); | |
qDebug() << query.queryItems(); | |
sio << protocol << " 200 OK\r\n"; | |
sio << "Content-Type: text/plain; charset=\"utf-8\"\r\n"; | |
sio << "Content-Length: 0\r\n"; | |
sio << "\r\n"; | |
} | |
} | |
HttpServer::HttpServer(QObject *parent) : | |
QObject(parent), | |
_server(new QTcpServer(this)) | |
{ | |
this->connect(this->_server, SIGNAL(newConnection()), SLOT(_onNewConnection())); | |
} | |
bool HttpServer::listen(quint16 port) { | |
return this->_server->listen(QHostAddress::LocalHost, port); | |
} | |
void HttpServer::_onNewConnection() { | |
while (this->_server->hasPendingConnections()) { | |
auto socket = this->_server->nextPendingConnection(); | |
this->connect(socket, SIGNAL(readyRead()), SLOT(_onClientReadyRead())); | |
this->connect(socket, SIGNAL(disconnected()), SLOT(_onClientDisconnected())); | |
} | |
} | |
void HttpServer::_onClientReadyRead() { | |
auto socket = qobject_cast<QTcpSocket *>(this->sender()); | |
Task * task = new Task([=](const Task::Yield & yield)->void { | |
QTextStream sio(socket); | |
sio.setCodec(QTextCodec::codecForName("UTF-8")); | |
yield(500); | |
handleRequest(sio); | |
yield(500); | |
socket->close(); | |
}); | |
task->connect(task, SIGNAL(finished()), SLOT(deleteLater())); | |
task->start(); | |
} | |
void HttpServer::_onClientDisconnected() { | |
auto socket = qobject_cast<QTcpSocket *>(this->sender()); | |
socket->deleteLater(); | |
this->_server->close(); | |
QCoreApplication::instance()->quit(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef HTTPSERVER_H | |
#define HTTPSERVER_H | |
#include <QObject> | |
#include <QtNetwork/QTcpServer> | |
class HttpServer : public QObject | |
{ | |
Q_OBJECT | |
public: | |
explicit HttpServer(QObject *parent = 0); | |
bool listen(quint16 port); | |
signals: | |
public slots: | |
private slots: | |
void _onNewConnection(); | |
void _onClientReadyRead(); | |
void _onClientDisconnected(); | |
private: | |
QTcpServer * _server; | |
}; | |
#endif // HTTPSERVER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <QtCore/QCoreApplication> | |
#include <QtCore/QtDebug> | |
#include "httpserver.hpp" | |
int main(int argc, char *argv[]) | |
{ | |
QCoreApplication a(argc, argv); | |
HttpServer server; | |
bool ok = server.listen(1080); | |
qDebug() << ok; | |
return a.exec(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "task.hpp" | |
#include "task_p.hpp" | |
#include <QtCore/QTimer> | |
Task::Task(Callback task, QObject *parent) : | |
QObject(parent), | |
d(new Private(task, this)) | |
{ | |
this->connect(this->d, SIGNAL(finished()), SIGNAL(finished())); | |
} | |
void Task::start() { | |
this->d->fork = Private::Coroutine::pull_type([&](Private::Coroutine::push_type & yield)->void { | |
this->d->task([&](int interval)->void { | |
yield(interval); | |
}); | |
}); | |
this->d->chain(); | |
} | |
Task::Private::Private(Callback task, QObject *parent) : | |
QObject(parent), | |
task(task), | |
fork() | |
{ | |
} | |
void Task::Private::chain() { | |
if (!this->fork) { | |
emit this->finished(); | |
return; | |
} | |
int interval = this->fork.get(); | |
QTimer::singleShot(interval, this, SLOT(onTimeout())); | |
} | |
void Task::Private::onTimeout() { | |
assert(this->fork || !"coroutine error"); | |
this->fork(); | |
this->chain(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TASK_H | |
#define TASK_H | |
#include <QtCore/QObject> | |
#include <functional> | |
class Task : public QObject | |
{ | |
Q_OBJECT | |
public: | |
typedef std::function<void (int)> Yield; | |
typedef std::function<void (const Yield &)> Callback; | |
explicit Task(Callback task, QObject *parent = 0); | |
void start(); | |
signals: | |
void finished(); | |
private: | |
class Private; | |
Private * d; | |
}; | |
#endif // TASK_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TASK_P_H | |
#define TASK_P_H | |
#include "task.hpp" | |
#include <boost/coroutine/stack_allocator.hpp> | |
#include <boost/coroutine/coroutine.hpp> | |
class Task::Private: public QObject { | |
Q_OBJECT | |
public: | |
typedef boost::coroutines::coroutine<int> Coroutine; | |
Private(Task::Callback task, QObject * parent); | |
void chain(); | |
signals: | |
void finished(); | |
public slots: | |
void onTimeout(); | |
public: | |
Task::Callback task; | |
Coroutine::pull_type fork; | |
}; | |
#endif // TASK_P_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi!
Line 6 in
CMakeLists.txt
should readOtherwise it won't link. Notice the added thread component.