SlideShare a Scribd company logo
1 of 32
Download to read offline
Простой 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

More Related Content

What's hot

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
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++corehard_by
 
Windbg랑 친해지기
Windbg랑 친해지기Windbg랑 친해지기
Windbg랑 친해지기Ji Hun Kim
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++NextSergey Platonov
 
модели акторов в с++ миф или реальность
модели акторов в с++ миф или реальностьмодели акторов в с++ миф или реальность
модели акторов в с++ миф или реальностьcorehard_by
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Sergey Platonov
 
Node.js flow control
Node.js flow controlNode.js flow control
Node.js flow controlSimon Su
 
How to make a large C++-code base manageable
How to make a large C++-code base manageableHow to make a large C++-code base manageable
How to make a large C++-code base manageablecorehard_by
 
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Mr. Vengineer
 
Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations DVClub
 
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Mr. Vengineer
 
201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harianKhairunnisaPekanbaru
 
Travel management
Travel managementTravel management
Travel management1Parimal2
 
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеДмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеSergey Platonov
 
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствамиАнтон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствамиSergey Platonov
 
Fuzzing: The New Unit Testing
Fuzzing: The New Unit TestingFuzzing: The New Unit Testing
Fuzzing: The New Unit TestingDmitry Vyukov
 

What's hot (20)

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
 
Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++Работа с реляционными базами данных в C++
Работа с реляционными базами данных в C++
 
Windbg랑 친해지기
Windbg랑 친해지기Windbg랑 친해지기
Windbg랑 친해지기
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
 
модели акторов в с++ миф или реальность
модели акторов в с++ миф или реальностьмодели акторов в с++ миф или реальность
модели акторов в с++ миф или реальность
 
3
33
3
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++
 
TensorFlow XLA RPC
TensorFlow XLA RPCTensorFlow XLA RPC
TensorFlow XLA RPC
 
Node.js flow control
Node.js flow controlNode.js flow control
Node.js flow control
 
How to make a large C++-code base manageable
How to make a large C++-code base manageableHow to make a large C++-code base manageable
How to make a large C++-code base manageable
 
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)Bridge TensorFlow to run on Intel nGraph backends (v0.4)
Bridge TensorFlow to run on Intel nGraph backends (v0.4)
 
Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations
 
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)Bridge TensorFlow to run on Intel nGraph backends (v0.5)
Bridge TensorFlow to run on Intel nGraph backends (v0.5)
 
201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian
 
Fia fabila
Fia fabilaFia fabila
Fia fabila
 
Tugas 2
Tugas 2Tugas 2
Tugas 2
 
Travel management
Travel managementTravel management
Travel management
 
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI векеДмитрий Нестерук, Паттерны проектирования в XXI веке
Дмитрий Нестерук, Паттерны проектирования в XXI веке
 
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствамиАнтон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствами
 
Fuzzing: The New Unit Testing
Fuzzing: The New Unit TestingFuzzing: The New Unit Testing
Fuzzing: The New Unit Testing
 

Viewers also liked

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Platonov Sergey
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castRoman Orlov
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines Sergey Zubkov
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3Platonov Sergey
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеIlia Shishkov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерSergey Platonov
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
Quality assurance of large c++ projects
Quality assurance of large c++ projectsQuality assurance of large c++ projects
Quality assurance of large c++ projectscorehard_by
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Mikhail Matrosov
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxPlatonov Sergey
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеPlatonov Sergey
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17Sergey Platonov
 
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
Gor Nishanov,  C++ Coroutines – a negative overhead abstractionGor Nishanov,  C++ Coroutines – a negative overhead abstraction
Gor Nishanov, C++ Coroutines – a negative overhead abstractionSergey Platonov
 
Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы corehard_by
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IPlatonov Sergey
 

Viewers also liked (20)

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в форме
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Quality assurance of large c++ projects
Quality assurance of large c++ projectsQuality assurance of large c++ projects
Quality assurance of large c++ projects
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17
 
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
Gor Nishanov,  C++ Coroutines – a negative overhead abstractionGor Nishanov,  C++ Coroutines – a negative overhead abstraction
Gor Nishanov, C++ Coroutines – a negative overhead abstraction
 
Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
 

Similar to Василий Сорокин, Простой REST сервер на Qt с рефлексией

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
 
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
 
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
 

Similar to Василий Сорокин, Простой REST сервер на Qt с рефлексией (20)

Qt Network Explained (Portuguese)
Qt Network Explained (Portuguese)Qt Network Explained (Portuguese)
Qt Network Explained (Portuguese)
 
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
 
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?
 
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
 
分散式系統
分散式系統分散式系統
分散式系統
 

More from Sergey Platonov

Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаЛев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаSergey Platonov
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Sergey Platonov
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioSergey Platonov
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
 
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtДенис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtSergey Platonov
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Sergey Platonov
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковSergey Platonov
 
Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Sergey Platonov
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Sergey Platonov
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Sergey Platonov
 
Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Sergey Platonov
 
Михаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLМихаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLSergey Platonov
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Sergey Platonov
 
Алексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляАлексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляSergey Platonov
 
Илья Шишков, Принципы создания тестируемого кода
Илья Шишков, Принципы создания тестируемого кодаИлья Шишков, Принципы создания тестируемого кода
Илья Шишков, Принципы создания тестируемого кодаSergey Platonov
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаSergey Platonov
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 

More from Sergey Platonov (18)

Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного багаЛев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
Лев Казаркин, Удивительные приключения регистров SSE или в поисках одного бага
 
Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.io
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++
 
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на QtДенис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
Денис Кандров, Пушкова Евгения, QSpec: тестирование графических приложений на Qt
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...Dori Exterman, Considerations for choosing the parallel computing strategy th...
Dori Exterman, Considerations for choosing the parallel computing strategy th...
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++
 
Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++Антон Нонко, Классические строки в C++
Антон Нонко, Классические строки в C++
 
Михаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STLМихаил Матросов, Повседневный С++: boost и STL
Михаил Матросов, Повседневный С++: boost и STL
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Алексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуляАлексей Кутумов, Вектор с нуля
Алексей Кутумов, Вектор с нуля
 
Илья Шишков, Принципы создания тестируемого кода
Илья Шишков, Принципы создания тестируемого кодаИлья Шишков, Принципы создания тестируемого кода
Илья Шишков, Принципы создания тестируемого кода
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 

Recently uploaded

How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
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
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 

Recently uploaded (20)

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
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
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
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 

Василий Сорокин, Простой REST сервер на Qt с рефлексией

  • 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; }