SlideShare a Scribd company logo
Простой 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
Ad

More Related Content

What's hot (19)

생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트
기룡 남
 
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 TypeScript
Seok-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 concurrency
priyank09
 
Circuit breaker
Circuit breakerCircuit breaker
Circuit breaker
bricemciver
 
3
33
3
Marat Vyshegorodtsev
 
Multithreading done right
Multithreading done rightMultithreading done right
Multithreading done right
Platonov 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 Profiling
Andrei 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 Idioms
Alex 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 202
Mahmoud 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_vulnerability
CanSecWest
 
Preparation for mit ose lab4
Preparation for mit ose lab4Preparation for mit ose lab4
Preparation for mit ose lab4
Benux 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
 
생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트
기룡 남
 
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 TypeScript
Seok-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 concurrency
priyank09
 
Multithreading done right
Multithreading done rightMultithreading done right
Multithreading done right
Platonov 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 Profiling
Andrei 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 Idioms
Alex 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 202
Mahmoud 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_vulnerability
CanSecWest
 
Preparation for mit ose lab4
Preparation for mit ose lab4Preparation for mit ose lab4
Preparation for mit ose lab4
Benux 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
 

Viewers also liked (20)

Gandhi
GandhiGandhi
Gandhi
Jose Mario
 
Consell Assessor de Dones en Xarxa
Consell Assessor de Dones en XarxaConsell Assessor de Dones en Xarxa
Consell Assessor de Dones en Xarxa
Dones en Xarxa
 
Yogalcoholicos 2292
Yogalcoholicos 2292Yogalcoholicos 2292
Yogalcoholicos 2292
Jose Mario
 
Citas Y Proverbios 2185
Citas Y Proverbios 2185Citas Y Proverbios 2185
Citas Y Proverbios 2185
Jose 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 2015
Dones 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
 
News agengies
News agengiesNews agengies
News agengies
Fatima Rifat
 
Beijing Facundo,Franco,Ppt
Beijing Facundo,Franco,PptBeijing Facundo,Franco,Ppt
Beijing Facundo,Franco,Ppt
sonia 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 probability
Kim Moore
 
Francisco Rs
Francisco RsFrancisco Rs
Francisco Rs
sonia rodriguez
 
Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014
dirazola
 
Bush Y El Infierno 2247
Bush Y El Infierno 2247Bush Y El Infierno 2247
Bush Y El Infierno 2247
Jose 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 Orange
Dones en Xarxa
 
PresentacióNche
PresentacióNchePresentacióNche
PresentacióNche
Jose Mario
 
xx
xxxx
xx
guest1dbcb0
 
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
carlaornella
 
Beijin IñAki
Beijin IñAkiBeijin IñAki
Beijin IñAki
sonia rodriguez
 
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
Dones en Xarxa
 
Catalogo Perspective on war
Catalogo Perspective on warCatalogo Perspective on war
Catalogo Perspective on war
Riccardo Zaniol
 
Einstein 2286 Frases
Einstein 2286 FrasesEinstein 2286 Frases
Einstein 2286 Frases
Jose Mario
 
Consell Assessor de Dones en Xarxa
Consell Assessor de Dones en XarxaConsell Assessor de Dones en Xarxa
Consell Assessor de Dones en Xarxa
Dones en Xarxa
 
Yogalcoholicos 2292
Yogalcoholicos 2292Yogalcoholicos 2292
Yogalcoholicos 2292
Jose Mario
 
Citas Y Proverbios 2185
Citas Y Proverbios 2185Citas Y Proverbios 2185
Citas Y Proverbios 2185
Jose 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 2015
Dones 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,Ppt
sonia 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 probability
Kim Moore
 
Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014Taller CITA/AulaBlog marzo2014
Taller CITA/AulaBlog marzo2014
dirazola
 
Bush Y El Infierno 2247
Bush Y El Infierno 2247Bush Y El Infierno 2247
Bush Y El Infierno 2247
Jose 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 Orange
Dones en Xarxa
 
PresentacióNche
PresentacióNchePresentacióNche
PresentacióNche
Jose 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 1
carlaornella
 
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
Dones en Xarxa
 
Catalogo Perspective on war
Catalogo Perspective on warCatalogo Perspective on war
Catalogo Perspective on war
Riccardo Zaniol
 
Einstein 2286 Frases
Einstein 2286 FrasesEinstein 2286 Frases
Einstein 2286 Frases
Jose Mario
 
Ad

Similar to Qt Rest Server (20)

Reactive server with netty
Reactive server with nettyReactive server with netty
Reactive server with netty
Dmitriy Dumanskiy
 
Winform
WinformWinform
Winform
quocphu199
 
RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message Queue
Gleicon Moraes
 
Ipc
IpcIpc
Ipc
deepakittude
 
java sockets
 java sockets java sockets
java sockets
Enam Ahmed Shahaz
 
[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
Igor Lozynskyi
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
WindowsPhoneRocks
 
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene EuroconSolr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
Giovanni Fernandez-Kincade
 
Spring MVC 3 Restful
Spring MVC 3 RestfulSpring MVC 3 Restful
Spring MVC 3 Restful
knight1128
 
[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, Overview
Joshua McKenzie
 
Network
NetworkNetwork
Network
phanleson
 
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 ease
KAI CHU CHUNG
 
Introduction to ATS plugins
Introduction to ATS pluginsIntroduction to ATS plugins
Introduction to ATS plugins
PSUdaemon
 
Refactoring Jdbc Programming
Refactoring Jdbc ProgrammingRefactoring Jdbc Programming
Refactoring Jdbc Programming
chanwook Park
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhere
Sergey 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
 
Packet filtering using jpcap
Packet filtering using jpcapPacket filtering using jpcap
Packet filtering using jpcap
Elanthendral Mariappan
 
RestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message QueueRestMQ - HTTP/Redis based Message Queue
RestMQ - HTTP/Redis based Message Queue
Gleicon 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 product
Igor Lozynskyi
 
13 networking, mobile services, and authentication
13   networking, mobile services, and authentication13   networking, mobile services, and authentication
13 networking, mobile services, and authentication
WindowsPhoneRocks
 
Spring MVC 3 Restful
Spring MVC 3 RestfulSpring MVC 3 Restful
Spring MVC 3 Restful
knight1128
 
[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, Overview
Joshua 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 ease
KAI CHU CHUNG
 
Introduction to ATS plugins
Introduction to ATS pluginsIntroduction to ATS plugins
Introduction to ATS plugins
PSUdaemon
 
Refactoring Jdbc Programming
Refactoring Jdbc ProgrammingRefactoring Jdbc Programming
Refactoring Jdbc Programming
chanwook Park
 
Алексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhereАлексей Кутумов, Coroutines everywhere
Алексей Кутумов, Coroutines everywhere
Sergey 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
 
Ad

Recently uploaded (20)

Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??
Web Designer
 
Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025
Web Designer
 
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdfTop Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
evrigsolution
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
GC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance EngineeringGC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance Engineering
Tier1 app
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
Why Tapitag Ranks Among the Best Digital Business Card Providers
Why Tapitag Ranks Among the Best Digital Business Card ProvidersWhy Tapitag Ranks Among the Best Digital Business Card Providers
Why Tapitag Ranks Among the Best Digital Business Card Providers
Tapitag
 
Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025
Phil Eaton
 
Download MathType Crack Version 2025???
Download MathType Crack  Version 2025???Download MathType Crack  Version 2025???
Download MathType Crack Version 2025???
Google
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509
Fermin Galan
 
How to Install and Activate ListGrabber Plugin
How to Install and Activate ListGrabber PluginHow to Install and Activate ListGrabber Plugin
How to Install and Activate ListGrabber Plugin
eGrabber
 
Download 4k Video Downloader Crack Pre-Activated
Download 4k Video Downloader Crack Pre-ActivatedDownload 4k Video Downloader Crack Pre-Activated
Download 4k Video Downloader Crack Pre-Activated
Web Designer
 
Adobe Audition Crack FRESH Version 2025 FREE
Adobe Audition Crack FRESH Version 2025 FREEAdobe Audition Crack FRESH Version 2025 FREE
Adobe Audition Crack FRESH Version 2025 FREE
zafranwaqar90
 
Buy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training techBuy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training tech
Rustici Software
 
Adobe InDesign Crack FREE Download 2025 link
Adobe InDesign Crack FREE Download 2025 linkAdobe InDesign Crack FREE Download 2025 link
Adobe InDesign Crack FREE Download 2025 link
mahmadzubair09
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 
Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??Serato DJ Pro Crack Latest Version 2025??
Serato DJ Pro Crack Latest Version 2025??
Web Designer
 
Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025
Web Designer
 
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdfTop Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
Top Magento Hyvä Theme Features That Make It Ideal for E-commerce.pdf
evrigsolution
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
GC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance EngineeringGC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance Engineering
Tier1 app
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
Why Tapitag Ranks Among the Best Digital Business Card Providers
Why Tapitag Ranks Among the Best Digital Business Card ProvidersWhy Tapitag Ranks Among the Best Digital Business Card Providers
Why Tapitag Ranks Among the Best Digital Business Card Providers
Tapitag
 
Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025
Phil Eaton
 
Download MathType Crack Version 2025???
Download MathType Crack  Version 2025???Download MathType Crack  Version 2025???
Download MathType Crack Version 2025???
Google
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509Orion Context Broker introduction 20250509
Orion Context Broker introduction 20250509
Fermin Galan
 
How to Install and Activate ListGrabber Plugin
How to Install and Activate ListGrabber PluginHow to Install and Activate ListGrabber Plugin
How to Install and Activate ListGrabber Plugin
eGrabber
 
Download 4k Video Downloader Crack Pre-Activated
Download 4k Video Downloader Crack Pre-ActivatedDownload 4k Video Downloader Crack Pre-Activated
Download 4k Video Downloader Crack Pre-Activated
Web Designer
 
Adobe Audition Crack FRESH Version 2025 FREE
Adobe Audition Crack FRESH Version 2025 FREEAdobe Audition Crack FRESH Version 2025 FREE
Adobe Audition Crack FRESH Version 2025 FREE
zafranwaqar90
 
Buy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training techBuy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training tech
Rustici Software
 
Adobe InDesign Crack FREE Download 2025 link
Adobe InDesign Crack FREE Download 2025 linkAdobe InDesign Crack FREE Download 2025 link
Adobe InDesign Crack FREE Download 2025 link
mahmadzubair09
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 

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; }
  翻译: