Skip to content

Instantly share code, notes, and snippets.

@legnaleurc
Last active April 14, 2019 18:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save legnaleurc/1038309 to your computer and use it in GitHub Desktop.
Save legnaleurc/1038309 to your computer and use it in GitHub Desktop.
Qt signal/slot + Boost.Coroutine
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})
#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();
}
#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
#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();
}
#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();
}
#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
#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
@falemagn
Copy link

Hi!

Line 6 in CMakeLists.txt should read

find_package(Boost REQUIRED COMPONENTS coroutine system context thread)

Otherwise it won't link. Notice the added thread component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment