SlideShare ist ein Scribd-Unternehmen logo
1 von 32
Downloaden Sie, um offline zu lesen
Простой REST сервер на Qt с
рефлексией
Василий Сорокин
Москва 2017
Введение
● Qt и moc
● Abstract Server
● Concrete Server
● Рефлексия
● Authorization (and tags)
● Сложности/Проблемы
● Рефлексия в тестировании
● Заключение
Meta-Object Compiler
● Когда запускается
● Что делает
● Почему это важно
● Ограничения
Что должен уметь сервер?
● Получать запросы
● Разбирать данные
● Возвращать ответы
● Обрабатывать ошибки
● Авторизация
Abstract Server
#ifndef Q_MOC_RUN
# define NO_AUTH_REQUIRED
#endif
class AbstractRestServer : public QTcpServer
{
public:
explicit AbstractRestServer(const QString &pathPrefix, int port, QObject *parent = 0);
Q_INVOKABLE void startListen();
Q_INVOKABLE void stopListen();
protected:
void incomingConnection(qintptr socketDescriptor) override;
Abstract Server
void tryToCallMethod(QTcpSocket *socket, const
QString &type, const QString &method, QStringList
headers, const QByteArray &body);
QStringList makeMethodName(const QString &type,
const QString &name);
MethodNode *findMethod(const QStringList
&splittedMethod, QStringList &methodVariableParts);
void fillMethods();
void addMethodToTree(const QString &realMethod,
const QString &tag);
Abstract Server
void sendAnswer(QTcpSocket *socket, const
QByteArray &body, const QString &contentType, const
QHash<QString, QString> &headers,
int returnCode = 200, const QString &reason
= QString());
void registerSocket(QTcpSocket *socket);
void deleteSocket(QTcpSocket *socket, WorkerThread
*worker);
Abstract Server
private:
QThread *m_serverThread = nullptr;
QList<WorkerThreadInfo> m_threadPool;
QSet<QTcpSocket *> m_sockets;
QMutex m_socketsMutex;
MethodNode m_methodsTreeRoot;
int m_maxThreadsCount;
WorkerThread
class WorkerThread: public QThread
…
public:
WorkerThread(Proof::AbstractRestServer *const _server);
void sendAnswer(QTcpSocket *socket, const QByteArray &body, const
QString &contentType,
const QHash<QString, QString> &headers, int returnCode, const
QString &reason);
void handleNewConnection(qintptr socketDescriptor);
void deleteSocket(QTcpSocket *socket);
void onReadyRead(QTcpSocket *socket);
void stop();
WorkerThread
private:
Proof::AbstractRestServer* const m_server;
QHash<QTcpSocket *, SocketInfo> m_sockets;
WorkerThreadInfo
struct WorkerThreadInfo
{
explicit WorkerThreadInfo(WorkerThread *thread,
quint32 socketCount)
: thread(thread), socketCount(socketCount) {}
WorkerThread *thread;
quint32 socketCount;
};
SocketInfo
struct SocketInfo
{
Proof::HttpParser parser;
QMetaObject::Connection readyReadConnection;
QMetaObject::Connection disconnectConnection;
QMetaObject::Connection errorConnection;
};
Abstract Server implementation
static const QString NO_AUTH_TAG = QString("NO_AUTH_REQUIRED");
AbstractRestServer::AbstractRestServer(...) : QTcpServer(parent) {
m_serverThread = new QThread(this);
m_maxThreadsCount = QThread::idealThreadCount();
if (m_maxThreadsCount < MIN_THREADS_COUNT)
m_maxThreadsCount = MIN_THREADS_COUNT;
else
m_maxThreadsCount += 2;
moveToThread(m_serverThread);
m_serverThread->moveToThread(m_serverThread);
m_serverThread->start();
Abstract Server implementation
void AbstractRestServer::startListen()
{
if (!PrObject::call(this, &AbstractRestServer::startListen)) {
fillMethods();
bool isListen = listen(QHostAddress::Any, m_port);
}
}
void AbstractRestServer::stopListen()
{
if (!PrObject::call(this, &AbstractRestServer::stopListen, Proof::Call::Block))
close();
}
Make route tree
void AbstractRestServer::fillMethods() {
m_methodsTreeRoot.clear();
for (int i = 0; i < metaObject()->methodCount(); ++i) {
QMetaMethod method = metaObject()->method(i);
if (method.methodType() == QMetaMethod::Slot) {
QString currentMethod = QString(method.name());
if (currentMethod.startsWith(REST_METHOD_PREFIX))
addMethodToTree(currentMethod, method.tag());
}
}
}
Make route tree
void AbstractRestServer::addMethodToTree(const QString &realMethod,
const QString &tag)
{
QString method =
realMethod.mid(QString(REST_METHOD_PREFIX).length());
for (int i = 0; i < method.length(); ++i) {
if (method[i].isUpper()) {
method[i] = method[i].toLower();
if (i > 0 && method[i - 1] != '_')
method.insert(i++, '-');
}
} // rest_get_SourceList => get_source-list
Make route tree
QStringList splittedMethod = method.split("_");
MethodNode *currentNode = &m_methodsTreeRoot;
for (int i = 0; i < splittedMethod.count(); ++i) {
if (!currentNode->contains(splittedMethod[i]))
(*currentNode)[splittedMethod[i]] = MethodNode();
currentNode = &(*currentNode)[splittedMethod[i]];
}
currentNode->setValue(realMethod);
currentNode->setTag(tag);
}
Make route tree
class MethodNode {
public:
MethodNode();
bool contains(const QString &name) const;
void clear();
operator QString();
MethodNode &operator [](const QString &name);
const MethodNode operator [](const QString &name) const;
void setValue(const QString &value);
QString tag() const;
void setTag(const QString &tag);
private:
QHash<QString, MethodNode> m_nodes;
QString m_value = "";
QString m_tag;
};
New connection handling
void AbstractRestServer::incomingConnection(qintptr socketDescriptor) {
WorkerThread *worker = nullptr;
if (!m_threadPool.isEmpty()) {
auto iter = std::min_element(d->threadPool.begin(), d->threadPool.end(),
[](const WorkerThreadInfo &lhs, const WorkerThreadInfo &rhs)
{
return lhs.socketCount < rhs.socketCount;
});
if (iter->socketCount == 0 || m_threadPool.count() >= m_maxThreadsCount) {
worker = iter->thread;
++iter->socketCount;
}
}
New connection handling
if (worker == nullptr) {
worker = new WorkerThread(this);
worker->start();
m_threadPool << WorkerThreadInfo{worker, 1};
}
worker->handleNewConnection(socketDescriptor);
}
New connection handling
void WorkerThread::handleNewConnection(qintptr socketDescriptor) {
if (PrObject::call(this, &WorkerThread::handleNewConnection, socketDescriptor))
return;
QTcpSocket *tcpSocket = new QTcpSocket();
m_server->registerSocket(tcpSocket);
SocketInfo info;
info.readyReadConnection = connect(tcpSocket, &QTcpSocket::readyRead, this,
[tcpSocket, this] { onReadyRead(tcpSocket); }, Qt::QueuedConnection);
void (QTcpSocket:: *errorSignal)(QAbstractSocket::SocketError) =
&QTcpSocket::error;
info.errorConnection = connect(tcpSocket, errorSignal, this, [tcpSocket, this] {…},
Qt::QueuedConnection);
info.disconnectConnection = connect(tcpSocket, &QTcpSocket::disconnected, this,
[tcpSocket, this] {...}, Qt::QueuedConnection);
New connection handling
if (!tcpSocket->setSocketDescriptor(socketDescriptor)) {
m_server->deleteSocket(tcpSocket, this);
return;
}
sockets[tcpSocket] = info;
}
New connection handling
void WorkerThread::onReadyRead(QTcpSocket *socket) {
SocketInfo &info = m_sockets[socket];
HttpParser::Result result = info.parser.parseNextPart(socket->readAll());
switch (result) {
case HttpParser::Result::Success:
disconnect(info.readyReadConnection);
m_server->tryToCallMethod(socket, info.parser.method(), info.parser.uri(),
info.parser.headers(), info.parser.body());
break;
case HttpParser::Result::Error:
disconnect(info.readyReadConnection);
sendAnswer(socket, "", "text/plain; charset=utf-8", QHash<QString, QString>(), 400, "Bad
Request");
break;
case HttpParser::Result::NeedMore:
break;
}
}
Call method
void AbstractRestServer::tryToCallMethod(QTcpSocket *socket, const
QString &type, const QString &method, QStringList headers, const
QByteArray &body)
{
QStringList splittedByParamsMethod = method.split('?');
QStringList methodVariableParts;
QUrlQuery queryParams;
if (splittedByParamsMethod.count() > 1)
queryParams = QUrlQuery(splittedByParamsMethod.at(1));
MethodNode *methodNode = findMethod(makeMethodName(type,
splittedByParamsMethod.at(0)), methodVariableParts);
QString methodName = methodNode ? (*methodNode) : QString();
Call method
if (methodNode) {
bool isAuthenticationSuccessful = true;
if (methodNode->tag() != NO_AUTH_TAG) {
QString encryptedAuth;
for (int i = 0; i < headers.count(); ++i) {
if (headers.at(i).startsWith("Authorization", Qt::CaseInsensitive)) {
encryptedAuth = parseAuth(socket, headers.at(i));
break;
}
}
isAuthenticationSuccessful = (!encryptedAuth.isEmpty() && q-
>checkBasicAuth(encryptedAuth));
}
Call method
if (isAuthenticationSuccessful) {
QMetaObject::invokeMethod(this,
methodName.toLatin1().constData(), Qt::DirectConnection,
Q_ARG(QTcpSocket *,socket), Q_ARG(const
QStringList &, headers),
Q_ARG(const QStringList &, methodVariableParts),
Q_ARG(const QUrlQuery &, queryParams),
Q_ARG(const QByteArray &, body));
} else { sendNotAuthorized(socket); }
} else { sendNotFound(socket, "Wrong method"); }
}
Concrete Server
class RestServer : public Proof::AbstractRestServer
{
Q_OBJECT
public:
explicit RestServer(QObject *parent = 0);
protected slots:
NO_AUTH_REQUIRED void rest_get_Status(QTcpSocket *socket, const
QStringList &headers, const QStringList &methodVariableParts,
const QUrlQuery &query, const QByteArray &body);
void rest_get_Items_ValidList(...);
// GET /items/valid-list
}
Concrete Server implementation
void RestServer::rest_get_Items_ValidList(QTcpSocket *socket, const
QStringList &, const QStringList &, const QUrlQuery &, const
QByteArray &)
{
QJsonArray answerArray = m_somethingDataWorker->
getItems(ItemStatus::Valid);
sendAnswer(socket, QJsonDocument(answerArray).toJson(),
"text/json");
}
Сложности/Проблемы
● /press/123/start, /press/123/stop, item/321/transition
● Если нельзя вернуть данные сразу
Рефлексия в тестировании
TEST_F(AddressTest, updateFrom)
{
QList<QSignalSpy *> spies = spiesForObject(addressUT.data());
addressUT->updateFrom(addressUT2);
for (QSignalSpy *spy: spies)
EXPECT_EQ(1, spy->count()) << spy->signal().constData();
qDeleteAll(spies);
spies.clear();
EXPECT_EQ(addressUT2->city(), addressUT->city());
EXPECT_EQ(addressUT2->state(), addressUT->state());
EXPECT_EQ(addressUT2->postalCode(), addressUT->postalCode());
}
Рефлексия в тестировании
QList<QSignalSpy *> spiesForObject(QObject *obj, const QStringList &excludes)
{
QList<QSignalSpy *> spies;
for (int i = obj->metaObject()->methodOffset(); i < obj->metaObject()->methodCount(); ++i) {
if (obj->metaObject()->method(i).methodType() == QMetaMethod::Signal) {
QByteArray sign = obj->metaObject()->method(i).methodSignature();
if (excludes.contains(sign))
continue;
//Because QSignalSpy can't signals without SIGNAL() macros, but this hack cheating it
//# define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
sign.prepend("2");
spies << new QSignalSpy(obj, qFlagLocation(sign.constData()));
}
}
return spies;
}
Заключение / Вопросы
Спасибо
vasiliy.a.sorokin@gmail.com

Weitere ähnliche Inhalte

Was ist angesagt?

생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트기룡 남
 
Welcome to Modern C++
Welcome to Modern C++Welcome to Modern C++
Welcome to Modern C++Seok-joon Yun
 
Refactoring for testability c++
Refactoring for testability c++Refactoring for testability c++
Refactoring for testability c++Dimitrios Platis
 
Pro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptPro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptSeok-joon Yun
 
OpenResty TCP 服务代理和动态路由
OpenResty TCP 服务代理和动态路由OpenResty TCP 服务代理和动态路由
OpenResty TCP 服务代理和动态路由Orangle Liu
 
[grcpp] Refactoring for testability c++
[grcpp] Refactoring for testability c++[grcpp] Refactoring for testability c++
[grcpp] Refactoring for testability c++Dimitrios Platis
 
Java 5 concurrency
Java 5 concurrencyJava 5 concurrency
Java 5 concurrencypriyank09
 
Multithreading done right
Multithreading done rightMultithreading done right
Multithreading done rightPlatonov Sergey
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?Andrei Pangin
 
The Art of JVM Profiling
The Art of JVM ProfilingThe Art of JVM Profiling
The Art of JVM ProfilingAndrei Pangin
 
DataStax: Making Cassandra Fail (for effective testing)
DataStax: Making Cassandra Fail (for effective testing)DataStax: Making Cassandra Fail (for effective testing)
DataStax: Making Cassandra Fail (for effective testing)DataStax Academy
 
Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency IdiomsAlex Miller
 
The Ring programming language version 1.8 book - Part 105 of 202
The Ring programming language version 1.8 book - Part 105 of 202The Ring programming language version 1.8 book - Part 105 of 202
The Ring programming language version 1.8 book - Part 105 of 202Mahmoud Samir Fayed
 
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerabilityCsw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerabilityCanSecWest
 
Preparation for mit ose lab4
Preparation for mit ose lab4Preparation for mit ose lab4
Preparation for mit ose lab4Benux Wei
 
Cassandra is great but how do I test my application?
Cassandra is great but how do I test my application?Cassandra is great but how do I test my application?
Cassandra is great but how do I test my application?Christopher Batey
 
Locks (Concurrency)
Locks (Concurrency)Locks (Concurrency)
Locks (Concurrency)Sri Prasanna
 

Was ist angesagt? (19)

생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트
 
Welcome to Modern C++
Welcome to Modern C++Welcome to Modern C++
Welcome to Modern C++
 
Refactoring for testability c++
Refactoring for testability c++Refactoring for testability c++
Refactoring for testability c++
 
Pro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptPro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScript
 
OpenResty TCP 服务代理和动态路由
OpenResty TCP 服务代理和动态路由OpenResty TCP 服务代理和动态路由
OpenResty TCP 服务代理和动态路由
 
[grcpp] Refactoring for testability c++
[grcpp] Refactoring for testability c++[grcpp] Refactoring for testability c++
[grcpp] Refactoring for testability c++
 
Java 5 concurrency
Java 5 concurrencyJava 5 concurrency
Java 5 concurrency
 
Circuit breaker
Circuit breakerCircuit breaker
Circuit breaker
 
3
33
3
 
Multithreading done right
Multithreading done rightMultithreading done right
Multithreading done right
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?
 
The Art of JVM Profiling
The Art of JVM ProfilingThe Art of JVM Profiling
The Art of JVM Profiling
 
DataStax: Making Cassandra Fail (for effective testing)
DataStax: Making Cassandra Fail (for effective testing)DataStax: Making Cassandra Fail (for effective testing)
DataStax: Making Cassandra Fail (for effective testing)
 
Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency Idioms
 
The Ring programming language version 1.8 book - Part 105 of 202
The Ring programming language version 1.8 book - Part 105 of 202The Ring programming language version 1.8 book - Part 105 of 202
The Ring programming language version 1.8 book - Part 105 of 202
 
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerabilityCsw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
 
Preparation for mit ose lab4
Preparation for mit ose lab4Preparation for mit ose lab4
Preparation for mit ose lab4
 
Cassandra is great but how do I test my application?
Cassandra is great but how do I test my application?Cassandra is great but how do I test my application?
Cassandra is great but how do I test my application?
 
Locks (Concurrency)
Locks (Concurrency)Locks (Concurrency)
Locks (Concurrency)
 

Andere mochten auch

Consell Assessor de Dones en Xarxa
Consell Assessor de Dones en XarxaConsell Assessor de Dones en Xarxa
Consell Assessor de Dones en XarxaDones en Xarxa
 
Yogalcoholicos 2292
Yogalcoholicos 2292Yogalcoholicos 2292
Yogalcoholicos 2292Jose Mario
 
Citas Y Proverbios 2185
Citas Y Proverbios 2185Citas Y Proverbios 2185
Citas Y Proverbios 2185Jose Mario
 
Agenda dones barcelona primera quinzena - novembre de 2015
Agenda dones barcelona   primera quinzena - novembre de 2015Agenda dones barcelona   primera quinzena - novembre de 2015
Agenda dones barcelona primera quinzena - novembre de 2015Dones en Xarxa
 
La xarxa un espai de participacio.
La xarxa un espai de participacio.La xarxa un espai de participacio.
La xarxa un espai de participacio.Dones en Xarxa
 
Beijing Facundo,Franco,Ppt
Beijing Facundo,Franco,PptBeijing Facundo,Franco,Ppt
Beijing Facundo,Franco,Pptsonia rodriguez
 
Water, water everywhere...thinking and writing about probability
Water, water everywhere...thinking and writing about probabilityWater, water everywhere...thinking and writing about probability
Water, water everywhere...thinking and writing about probabilityKim Moore
 
Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014dirazola
 
Bush Y El Infierno 2247
Bush Y El Infierno 2247Bush Y El Infierno 2247
Bush Y El Infierno 2247Jose Mario
 
WOMANLIDERTIC Mesa 2 Mujeres liderando la economia digital. Alicia calvo Orange
WOMANLIDERTIC Mesa 2  Mujeres liderando la economia digital. Alicia calvo OrangeWOMANLIDERTIC Mesa 2  Mujeres liderando la economia digital. Alicia calvo Orange
WOMANLIDERTIC Mesa 2 Mujeres liderando la economia digital. Alicia calvo OrangeDones en Xarxa
 
PresentacióNche
PresentacióNchePresentacióNche
PresentacióNcheJose Mario
 
El futuro en la comunicación 1
El futuro en la comunicación 1El futuro en la comunicación 1
El futuro en la comunicación 1carlaornella
 
25 de novembre, Dia Internacional contra la Violència de Gèner
25 de novembre, Dia Internacional contra la Violència de Gèner25 de novembre, Dia Internacional contra la Violència de Gèner
25 de novembre, Dia Internacional contra la Violència de GènerDones en Xarxa
 
Catalogo Perspective on war
Catalogo Perspective on warCatalogo Perspective on war
Catalogo Perspective on warRiccardo Zaniol
 
Einstein 2286 Frases
Einstein 2286 FrasesEinstein 2286 Frases
Einstein 2286 FrasesJose Mario
 

Andere mochten auch (20)

Gandhi
GandhiGandhi
Gandhi
 
Consell Assessor de Dones en Xarxa
Consell Assessor de Dones en XarxaConsell Assessor de Dones en Xarxa
Consell Assessor de Dones en Xarxa
 
Yogalcoholicos 2292
Yogalcoholicos 2292Yogalcoholicos 2292
Yogalcoholicos 2292
 
Citas Y Proverbios 2185
Citas Y Proverbios 2185Citas Y Proverbios 2185
Citas Y Proverbios 2185
 
Agenda dones barcelona primera quinzena - novembre de 2015
Agenda dones barcelona   primera quinzena - novembre de 2015Agenda dones barcelona   primera quinzena - novembre de 2015
Agenda dones barcelona primera quinzena - novembre de 2015
 
La xarxa un espai de participacio.
La xarxa un espai de participacio.La xarxa un espai de participacio.
La xarxa un espai de participacio.
 
News agengies
News agengiesNews agengies
News agengies
 
Beijing Facundo,Franco,Ppt
Beijing Facundo,Franco,PptBeijing Facundo,Franco,Ppt
Beijing Facundo,Franco,Ppt
 
Water, water everywhere...thinking and writing about probability
Water, water everywhere...thinking and writing about probabilityWater, water everywhere...thinking and writing about probability
Water, water everywhere...thinking and writing about probability
 
Francisco Rs
Francisco RsFrancisco Rs
Francisco Rs
 
Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014
 
Bush Y El Infierno 2247
Bush Y El Infierno 2247Bush Y El Infierno 2247
Bush Y El Infierno 2247
 
WOMANLIDERTIC Mesa 2 Mujeres liderando la economia digital. Alicia calvo Orange
WOMANLIDERTIC Mesa 2  Mujeres liderando la economia digital. Alicia calvo OrangeWOMANLIDERTIC Mesa 2  Mujeres liderando la economia digital. Alicia calvo Orange
WOMANLIDERTIC Mesa 2 Mujeres liderando la economia digital. Alicia calvo Orange
 
PresentacióNche
PresentacióNchePresentacióNche
PresentacióNche
 
xx
xxxx
xx
 
El futuro en la comunicación 1
El futuro en la comunicación 1El futuro en la comunicación 1
El futuro en la comunicación 1
 
Beijin IñAki
Beijin IñAkiBeijin IñAki
Beijin IñAki
 
25 de novembre, Dia Internacional contra la Violència de Gèner
25 de novembre, Dia Internacional contra la Violència de Gèner25 de novembre, Dia Internacional contra la Violència de Gèner
25 de novembre, Dia Internacional contra la Violència de Gèner
 
Catalogo Perspective on war
Catalogo Perspective on warCatalogo Perspective on war
Catalogo Perspective on war
 
Einstein 2286 Frases
Einstein 2286 FrasesEinstein 2286 Frases
Einstein 2286 Frases
 

Ähnlich wie Qt Rest Server

RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueGleicon Moraes
 
[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data product[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data productIgor Lozynskyi
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authenticationWindowsPhoneRocks
 
Spring MVC 3 Restful
Spring MVC 3 RestfulSpring MVC 3 Restful
Spring MVC 3 Restfulknight1128
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화NAVER D2
 
[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화NAVER D2
 
Cassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewCassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewJoshua McKenzie
 
Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018  Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018 Ballerina
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeKAI CHU CHUNG
 
Introduction to ATS plugins
Introduction to ATS pluginsIntroduction to ATS plugins
Introduction to ATS pluginsPSUdaemon
 
Refactoring Jdbc Programming
Refactoring Jdbc ProgrammingRefactoring Jdbc Programming
Refactoring Jdbc Programmingchanwook Park
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereSergey Platonov
 
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...Srikanth Reddy Pallerla
 

Ähnlich wie Qt Rest Server (20)

Reactive server with netty
Reactive server with nettyReactive server with netty
Reactive server with netty
 
Winform
WinformWinform
Winform
 
RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message Queue
 
Ipc
IpcIpc
Ipc
 
java sockets
 java sockets java sockets
java sockets
 
[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data product[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data product
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
 
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene EuroconSolr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
 
Spring MVC 3 Restful
Spring MVC 3 RestfulSpring MVC 3 Restful
Spring MVC 3 Restful
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
 
[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화
 
Cassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewCassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, Overview
 
Network
NetworkNetwork
Network
 
Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018  Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Introduction to ATS plugins
Introduction to ATS pluginsIntroduction to ATS plugins
Introduction to ATS plugins
 
Refactoring Jdbc Programming
Refactoring Jdbc ProgrammingRefactoring Jdbc Programming
Refactoring Jdbc Programming
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhere
 
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...
Polling Techniques, Ajax, protocol Switching from Http to Websocket standard ...
 
Packet filtering using jpcap
Packet filtering using jpcapPacket filtering using jpcap
Packet filtering using jpcap
 

Kürzlich hochgeladen

%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...kalichargn70th171
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024Mind IT Systems
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxalwaysnagaraju26
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedDelhi Call girls
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...Nitya salvi
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 

Kürzlich hochgeladen (20)

%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 

Qt Rest Server

  • 1. Простой REST сервер на Qt с рефлексией Василий Сорокин Москва 2017
  • 2. Введение ● Qt и moc ● Abstract Server ● Concrete Server ● Рефлексия ● Authorization (and tags) ● Сложности/Проблемы ● Рефлексия в тестировании ● Заключение
  • 3. Meta-Object Compiler ● Когда запускается ● Что делает ● Почему это важно ● Ограничения
  • 4. Что должен уметь сервер? ● Получать запросы ● Разбирать данные ● Возвращать ответы ● Обрабатывать ошибки ● Авторизация
  • 5. Abstract Server #ifndef Q_MOC_RUN # define NO_AUTH_REQUIRED #endif class AbstractRestServer : public QTcpServer { public: explicit AbstractRestServer(const QString &pathPrefix, int port, QObject *parent = 0); Q_INVOKABLE void startListen(); Q_INVOKABLE void stopListen(); protected: void incomingConnection(qintptr socketDescriptor) override;
  • 6. Abstract Server void tryToCallMethod(QTcpSocket *socket, const QString &type, const QString &method, QStringList headers, const QByteArray &body); QStringList makeMethodName(const QString &type, const QString &name); MethodNode *findMethod(const QStringList &splittedMethod, QStringList &methodVariableParts); void fillMethods(); void addMethodToTree(const QString &realMethod, const QString &tag);
  • 7. Abstract Server void sendAnswer(QTcpSocket *socket, const QByteArray &body, const QString &contentType, const QHash<QString, QString> &headers, int returnCode = 200, const QString &reason = QString()); void registerSocket(QTcpSocket *socket); void deleteSocket(QTcpSocket *socket, WorkerThread *worker);
  • 8. Abstract Server private: QThread *m_serverThread = nullptr; QList<WorkerThreadInfo> m_threadPool; QSet<QTcpSocket *> m_sockets; QMutex m_socketsMutex; MethodNode m_methodsTreeRoot; int m_maxThreadsCount;
  • 9. WorkerThread class WorkerThread: public QThread … public: WorkerThread(Proof::AbstractRestServer *const _server); void sendAnswer(QTcpSocket *socket, const QByteArray &body, const QString &contentType, const QHash<QString, QString> &headers, int returnCode, const QString &reason); void handleNewConnection(qintptr socketDescriptor); void deleteSocket(QTcpSocket *socket); void onReadyRead(QTcpSocket *socket); void stop();
  • 11. WorkerThreadInfo struct WorkerThreadInfo { explicit WorkerThreadInfo(WorkerThread *thread, quint32 socketCount) : thread(thread), socketCount(socketCount) {} WorkerThread *thread; quint32 socketCount; };
  • 12. SocketInfo struct SocketInfo { Proof::HttpParser parser; QMetaObject::Connection readyReadConnection; QMetaObject::Connection disconnectConnection; QMetaObject::Connection errorConnection; };
  • 13. Abstract Server implementation static const QString NO_AUTH_TAG = QString("NO_AUTH_REQUIRED"); AbstractRestServer::AbstractRestServer(...) : QTcpServer(parent) { m_serverThread = new QThread(this); m_maxThreadsCount = QThread::idealThreadCount(); if (m_maxThreadsCount < MIN_THREADS_COUNT) m_maxThreadsCount = MIN_THREADS_COUNT; else m_maxThreadsCount += 2; moveToThread(m_serverThread); m_serverThread->moveToThread(m_serverThread); m_serverThread->start();
  • 14. Abstract Server implementation void AbstractRestServer::startListen() { if (!PrObject::call(this, &AbstractRestServer::startListen)) { fillMethods(); bool isListen = listen(QHostAddress::Any, m_port); } } void AbstractRestServer::stopListen() { if (!PrObject::call(this, &AbstractRestServer::stopListen, Proof::Call::Block)) close(); }
  • 15. Make route tree void AbstractRestServer::fillMethods() { m_methodsTreeRoot.clear(); for (int i = 0; i < metaObject()->methodCount(); ++i) { QMetaMethod method = metaObject()->method(i); if (method.methodType() == QMetaMethod::Slot) { QString currentMethod = QString(method.name()); if (currentMethod.startsWith(REST_METHOD_PREFIX)) addMethodToTree(currentMethod, method.tag()); } } }
  • 16. Make route tree void AbstractRestServer::addMethodToTree(const QString &realMethod, const QString &tag) { QString method = realMethod.mid(QString(REST_METHOD_PREFIX).length()); for (int i = 0; i < method.length(); ++i) { if (method[i].isUpper()) { method[i] = method[i].toLower(); if (i > 0 && method[i - 1] != '_') method.insert(i++, '-'); } } // rest_get_SourceList => get_source-list
  • 17. Make route tree QStringList splittedMethod = method.split("_"); MethodNode *currentNode = &m_methodsTreeRoot; for (int i = 0; i < splittedMethod.count(); ++i) { if (!currentNode->contains(splittedMethod[i])) (*currentNode)[splittedMethod[i]] = MethodNode(); currentNode = &(*currentNode)[splittedMethod[i]]; } currentNode->setValue(realMethod); currentNode->setTag(tag); }
  • 18. Make route tree class MethodNode { public: MethodNode(); bool contains(const QString &name) const; void clear(); operator QString(); MethodNode &operator [](const QString &name); const MethodNode operator [](const QString &name) const; void setValue(const QString &value); QString tag() const; void setTag(const QString &tag); private: QHash<QString, MethodNode> m_nodes; QString m_value = ""; QString m_tag; };
  • 19. New connection handling void AbstractRestServer::incomingConnection(qintptr socketDescriptor) { WorkerThread *worker = nullptr; if (!m_threadPool.isEmpty()) { auto iter = std::min_element(d->threadPool.begin(), d->threadPool.end(), [](const WorkerThreadInfo &lhs, const WorkerThreadInfo &rhs) { return lhs.socketCount < rhs.socketCount; }); if (iter->socketCount == 0 || m_threadPool.count() >= m_maxThreadsCount) { worker = iter->thread; ++iter->socketCount; } }
  • 20. New connection handling if (worker == nullptr) { worker = new WorkerThread(this); worker->start(); m_threadPool << WorkerThreadInfo{worker, 1}; } worker->handleNewConnection(socketDescriptor); }
  • 21. New connection handling void WorkerThread::handleNewConnection(qintptr socketDescriptor) { if (PrObject::call(this, &WorkerThread::handleNewConnection, socketDescriptor)) return; QTcpSocket *tcpSocket = new QTcpSocket(); m_server->registerSocket(tcpSocket); SocketInfo info; info.readyReadConnection = connect(tcpSocket, &QTcpSocket::readyRead, this, [tcpSocket, this] { onReadyRead(tcpSocket); }, Qt::QueuedConnection); void (QTcpSocket:: *errorSignal)(QAbstractSocket::SocketError) = &QTcpSocket::error; info.errorConnection = connect(tcpSocket, errorSignal, this, [tcpSocket, this] {…}, Qt::QueuedConnection); info.disconnectConnection = connect(tcpSocket, &QTcpSocket::disconnected, this, [tcpSocket, this] {...}, Qt::QueuedConnection);
  • 22. New connection handling if (!tcpSocket->setSocketDescriptor(socketDescriptor)) { m_server->deleteSocket(tcpSocket, this); return; } sockets[tcpSocket] = info; }
  • 23. New connection handling void WorkerThread::onReadyRead(QTcpSocket *socket) { SocketInfo &info = m_sockets[socket]; HttpParser::Result result = info.parser.parseNextPart(socket->readAll()); switch (result) { case HttpParser::Result::Success: disconnect(info.readyReadConnection); m_server->tryToCallMethod(socket, info.parser.method(), info.parser.uri(), info.parser.headers(), info.parser.body()); break; case HttpParser::Result::Error: disconnect(info.readyReadConnection); sendAnswer(socket, "", "text/plain; charset=utf-8", QHash<QString, QString>(), 400, "Bad Request"); break; case HttpParser::Result::NeedMore: break; } }
  • 24. Call method void AbstractRestServer::tryToCallMethod(QTcpSocket *socket, const QString &type, const QString &method, QStringList headers, const QByteArray &body) { QStringList splittedByParamsMethod = method.split('?'); QStringList methodVariableParts; QUrlQuery queryParams; if (splittedByParamsMethod.count() > 1) queryParams = QUrlQuery(splittedByParamsMethod.at(1)); MethodNode *methodNode = findMethod(makeMethodName(type, splittedByParamsMethod.at(0)), methodVariableParts); QString methodName = methodNode ? (*methodNode) : QString();
  • 25. Call method if (methodNode) { bool isAuthenticationSuccessful = true; if (methodNode->tag() != NO_AUTH_TAG) { QString encryptedAuth; for (int i = 0; i < headers.count(); ++i) { if (headers.at(i).startsWith("Authorization", Qt::CaseInsensitive)) { encryptedAuth = parseAuth(socket, headers.at(i)); break; } } isAuthenticationSuccessful = (!encryptedAuth.isEmpty() && q- >checkBasicAuth(encryptedAuth)); }
  • 26. Call method if (isAuthenticationSuccessful) { QMetaObject::invokeMethod(this, methodName.toLatin1().constData(), Qt::DirectConnection, Q_ARG(QTcpSocket *,socket), Q_ARG(const QStringList &, headers), Q_ARG(const QStringList &, methodVariableParts), Q_ARG(const QUrlQuery &, queryParams), Q_ARG(const QByteArray &, body)); } else { sendNotAuthorized(socket); } } else { sendNotFound(socket, "Wrong method"); } }
  • 27. Concrete Server class RestServer : public Proof::AbstractRestServer { Q_OBJECT public: explicit RestServer(QObject *parent = 0); protected slots: NO_AUTH_REQUIRED void rest_get_Status(QTcpSocket *socket, const QStringList &headers, const QStringList &methodVariableParts, const QUrlQuery &query, const QByteArray &body); void rest_get_Items_ValidList(...); // GET /items/valid-list }
  • 28. Concrete Server implementation void RestServer::rest_get_Items_ValidList(QTcpSocket *socket, const QStringList &, const QStringList &, const QUrlQuery &, const QByteArray &) { QJsonArray answerArray = m_somethingDataWorker-> getItems(ItemStatus::Valid); sendAnswer(socket, QJsonDocument(answerArray).toJson(), "text/json"); }
  • 29. Сложности/Проблемы ● /press/123/start, /press/123/stop, item/321/transition ● Если нельзя вернуть данные сразу
  • 30. Рефлексия в тестировании TEST_F(AddressTest, updateFrom) { QList<QSignalSpy *> spies = spiesForObject(addressUT.data()); addressUT->updateFrom(addressUT2); for (QSignalSpy *spy: spies) EXPECT_EQ(1, spy->count()) << spy->signal().constData(); qDeleteAll(spies); spies.clear(); EXPECT_EQ(addressUT2->city(), addressUT->city()); EXPECT_EQ(addressUT2->state(), addressUT->state()); EXPECT_EQ(addressUT2->postalCode(), addressUT->postalCode()); }
  • 31. Рефлексия в тестировании QList<QSignalSpy *> spiesForObject(QObject *obj, const QStringList &excludes) { QList<QSignalSpy *> spies; for (int i = obj->metaObject()->methodOffset(); i < obj->metaObject()->methodCount(); ++i) { if (obj->metaObject()->method(i).methodType() == QMetaMethod::Signal) { QByteArray sign = obj->metaObject()->method(i).methodSignature(); if (excludes.contains(sign)) continue; //Because QSignalSpy can't signals without SIGNAL() macros, but this hack cheating it //# define SIGNAL(a) qFlagLocation("2"#a QLOCATION) sign.prepend("2"); spies << new QSignalSpy(obj, qFlagLocation(sign.constData())); } } return spies; }