mirror of
https://github.com/arcan1s/queued.git
synced 2025-07-14 14:25:48 +00:00
add server proto
This commit is contained in:
13
sources/queued-server/CMakeLists.txt
Normal file
13
sources/queued-server/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# set project name
|
||||
set (SUBPROJECT "queued-server")
|
||||
message (STATUS "Subproject ${SUBPROJECT}")
|
||||
|
||||
add_subdirectory ("src")
|
||||
# build man
|
||||
file (GLOB SUBPROJECT_MAN_IN "*.1")
|
||||
file (RELATIVE_PATH SUBPROJECT_MAN "${CMAKE_SOURCE_DIR}" "${SUBPROJECT_MAN_IN}")
|
||||
configure_file ("${SUBPROJECT_MAN_IN}" "${CMAKE_CURRENT_BINARY_DIR}/${SUBPROJECT_MAN}")
|
||||
|
||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${SUBPROJECT_MAN}" DESTINATION "${DATA_INSTALL_DIR}/man/man1")
|
||||
install (FILES "bash-completions" DESTINATION "${DATA_INSTALL_DIR}/bash-completion/completions" RENAME "${SUBPROJECT}")
|
||||
install (FILES "zsh-completions" DESTINATION "${DATA_INSTALL_DIR}/zsh/site-functions" RENAME "_${SUBPROJECT}")
|
0
sources/queued-server/bash-completions
Normal file
0
sources/queued-server/bash-completions
Normal file
0
sources/queued-server/queued-server.1
Normal file
0
sources/queued-server/queued-server.1
Normal file
18
sources/queued-server/src/CMakeLists.txt
Normal file
18
sources/queued-server/src/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
# set files
|
||||
file (GLOB_RECURSE SUBPROJECT_SOURCES "*.cpp")
|
||||
file (GLOB_RECURSE SUBPROJECT_HEADERS "*.h")
|
||||
|
||||
# include_path
|
||||
include_directories ("${PROJECT_LIBRARY_DIR}/include"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${PROJECT_TRDPARTY_DIR}"
|
||||
"${Qt_INCLUDE}")
|
||||
|
||||
qt5_wrap_cpp (SUBPROJECT_MOC_SOURCES "${SUBPROJECT_HEADERS}")
|
||||
|
||||
add_executable ("${SUBPROJECT}" "${SUBPROJECT_HEADERS}" "${SUBPROJECT_SOURCES}"
|
||||
"${SUBPROJECT_MOC_SOURCES}")
|
||||
target_link_libraries ("${SUBPROJECT}" "${PROJECT_LIBRARY}" "${Qt_LIBRARIES}")
|
||||
# install properties
|
||||
install (TARGETS "${SUBPROJECT}" DESTINATION "${BIN_INSTALL_DIR}")
|
62
sources/queued-server/src/QueuedServer.cpp
Normal file
62
sources/queued-server/src/QueuedServer.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#include "QueuedServer.h"
|
||||
|
||||
#include <queued/Queued.h>
|
||||
|
||||
#include "QueuedTcpServer.h"
|
||||
|
||||
|
||||
QueuedServer::QueuedServer(QObject *parent, const QVariantHash &args)
|
||||
: QObject(parent)
|
||||
, m_configuration(args)
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
QueuedServer::~QueuedServer()
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
|
||||
deinit();
|
||||
}
|
||||
|
||||
|
||||
void QueuedServer::deinit()
|
||||
{
|
||||
if (m_server)
|
||||
delete m_server;
|
||||
}
|
||||
|
||||
|
||||
void QueuedServer::init()
|
||||
{
|
||||
deinit();
|
||||
|
||||
m_server = new QueuedTcpServer(this);
|
||||
m_server->listen(
|
||||
QHostAddress(QueuedCoreAdaptor::getOption("ServerAddress").toString()),
|
||||
QueuedCoreAdaptor::getOption("ServerPort").toUInt());
|
||||
m_server->setMaxPendingConnections(
|
||||
QueuedCoreAdaptor::getOption("ServerMaxConnections").toInt());
|
||||
|
||||
qCInfo(LOG_SERV) << "Server listen on" << m_server->serverAddress()
|
||||
<< m_server->serverPort();
|
||||
}
|
44
sources/queued-server/src/QueuedServer.h
Normal file
44
sources/queued-server/src/QueuedServer.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QUEUEDSERVER_H
|
||||
#define QUEUEDSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
class QueuedTcpServer;
|
||||
|
||||
class QueuedServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QueuedServer(QObject *parent, const QVariantHash &args);
|
||||
virtual ~QueuedServer();
|
||||
void deinit();
|
||||
void init();
|
||||
|
||||
private:
|
||||
// backend
|
||||
QueuedTcpServer *m_server = nullptr;
|
||||
// configuration
|
||||
QVariantHash m_configuration;
|
||||
};
|
||||
|
||||
|
||||
#endif /* QUEUEDSERVER_H */
|
56
sources/queued-server/src/QueuedTcpServer.cpp
Normal file
56
sources/queued-server/src/QueuedTcpServer.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#include "QueuedTcpServer.h"
|
||||
|
||||
#include <queued/Queued.h>
|
||||
|
||||
#include "QueuedTcpServerThread.h"
|
||||
|
||||
|
||||
QueuedTcpServer::QueuedTcpServer(QObject *parent)
|
||||
: QTcpServer(parent)
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
}
|
||||
|
||||
|
||||
QueuedTcpServer::~QueuedTcpServer()
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
|
||||
deinit();
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServer::deinit()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServer::init()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServer::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
QueuedTcpServerThread *thread
|
||||
= new QueuedTcpServerThread(socketDescriptor, this);
|
||||
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||
thread->start();
|
||||
}
|
40
sources/queued-server/src/QueuedTcpServer.h
Normal file
40
sources/queued-server/src/QueuedTcpServer.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QUEUEDTCPSERVER_H
|
||||
#define QUEUEDTCPSERVER_H
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
|
||||
class QueuedTcpServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QueuedTcpServer(QObject *parent);
|
||||
virtual ~QueuedTcpServer();
|
||||
void deinit();
|
||||
void init();
|
||||
|
||||
protected:
|
||||
void incomingConnection(qintptr socketDescriptor) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif /* QUEUEDTCPSERVER_H */
|
158
sources/queued-server/src/QueuedTcpServerThread.cpp
Normal file
158
sources/queued-server/src/QueuedTcpServerThread.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#include "QueuedTcpServerThread.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QJsonDocument>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <queued/Queued.h>
|
||||
|
||||
|
||||
QueuedTcpServerThread::QueuedTcpServerThread(int socketDescriptor,
|
||||
QObject *parent)
|
||||
: QThread(parent)
|
||||
, m_socketDescriptor(socketDescriptor)
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
}
|
||||
|
||||
|
||||
QueuedTcpServerThread::~QueuedTcpServerThread()
|
||||
{
|
||||
qCDebug(LOG_SERV) << __PRETTY_FUNCTION__;
|
||||
}
|
||||
|
||||
|
||||
QList<QByteArray> QueuedTcpServerThread::defaultResponse(const int code)
|
||||
{
|
||||
qCDebug(LOG_SERV) << "Build server response with code" << code;
|
||||
|
||||
QList<QByteArray> output;
|
||||
output += "HTTP/1.1 " + QByteArray::number(code) + " OK\r\n";
|
||||
output += "Server: QueuedServer/Qt" + QByteArray(qVersion()) + "\r\n";
|
||||
output += "Date: "
|
||||
+ QLocale::c()
|
||||
.toString(QDateTime::currentDateTimeUtc(),
|
||||
"ddd, d MMM yyyy HH:mm:dd t")
|
||||
.toUtf8()
|
||||
+ "\r\n";
|
||||
output += "Content-Type: application/json\r\n";
|
||||
output += "\r\n";
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
QueuedTcpServerThread::QueuedTcpServerRequest
|
||||
QueuedTcpServerThread::getRequest(const QStringList &headers,
|
||||
const QByteArray &body)
|
||||
{
|
||||
qCDebug(LOG_SERV) << "Get request object from headers" << headers
|
||||
<< "and body" << body;
|
||||
|
||||
QueuedTcpServerThread::QueuedTcpServerRequest request;
|
||||
request.valid = true;
|
||||
// method
|
||||
request.request = headers.first().split(' ').at(0);
|
||||
// path
|
||||
QUrl url(headers.first().split(' ').at(1));
|
||||
request.path = url.path();
|
||||
// body
|
||||
QJsonParseError error;
|
||||
auto jsonDoc = QJsonDocument::fromJson(body, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qCWarning(LOG_SERV) << "Parse error" << error.errorString();
|
||||
request.valid = false;
|
||||
} else {
|
||||
request.data = jsonDoc.object().toVariantHash();
|
||||
}
|
||||
// append from url if any
|
||||
auto items = QUrlQuery(url.query()).queryItems();
|
||||
for (auto &item : items) {
|
||||
auto key = item.first;
|
||||
auto value = item.second;
|
||||
QVariantList values;
|
||||
switch (request.data[key].type()) {
|
||||
case QVariant::List:
|
||||
values = request.data[key].toList();
|
||||
break;
|
||||
case QVariant::Invalid:
|
||||
break;
|
||||
default:
|
||||
values = QVariantList({request.data[key]});
|
||||
break;
|
||||
}
|
||||
values.append(key);
|
||||
request.data[key] = values.count() == 1 ? values.first() : values;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServerThread::run()
|
||||
{
|
||||
m_socket = new QTcpSocket(this);
|
||||
if (!m_socket->setSocketDescriptor(m_socketDescriptor)) {
|
||||
emit(error(m_socket->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()),
|
||||
Qt::DirectConnection);
|
||||
connect(m_socket, SIGNAL(disconnected()), this, SLOT(disconnected()),
|
||||
Qt::DirectConnection);
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServerThread::disconnected()
|
||||
{
|
||||
m_socket->deleteLater();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void QueuedTcpServerThread::readyRead()
|
||||
{
|
||||
QStringList headers;
|
||||
while (m_socket->canReadLine())
|
||||
headers += m_socket->readLine().simplified();
|
||||
// request body
|
||||
auto body = m_socket->readAll().simplified();
|
||||
|
||||
// get request object
|
||||
auto request = getRequest(headers, body);
|
||||
if (!request.valid) {
|
||||
emit(error(QTcpSocket::UnsupportedSocketOperationError));
|
||||
return;
|
||||
}
|
||||
|
||||
auto response = defaultResponse(200);
|
||||
for (auto &resp : response) {
|
||||
m_socket->write(resp);
|
||||
m_socket->flush();
|
||||
}
|
||||
|
||||
m_socket->waitForBytesWritten(3000);
|
||||
m_socket->disconnectFromHost();
|
||||
if (m_socket->state() != QAbstractSocket::UnconnectedState)
|
||||
m_socket->waitForDisconnected();
|
||||
}
|
59
sources/queued-server/src/QueuedTcpServerThread.h
Normal file
59
sources/queued-server/src/QueuedTcpServerThread.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QUEUEDTCPSERVERTHREAD_H
|
||||
#define QUEUEDTCPSERVERTHREAD_H
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QThread>
|
||||
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class QueuedTcpServerThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef struct {
|
||||
QString request;
|
||||
QString path;
|
||||
QVariantHash data;
|
||||
bool valid = false;
|
||||
} QueuedTcpServerRequest;
|
||||
|
||||
explicit QueuedTcpServerThread(int socketDescriptor, QObject *parent);
|
||||
virtual ~QueuedTcpServerThread();
|
||||
static QList<QByteArray> defaultResponse(const int code);
|
||||
static QueuedTcpServerRequest getRequest(const QStringList &headers,
|
||||
const QByteArray &body);
|
||||
QVariantHash response(const QueuedTcpServerRequest &request) const;
|
||||
void run() override;
|
||||
|
||||
signals:
|
||||
void error(QTcpSocket::SocketError socketError);
|
||||
|
||||
private slots:
|
||||
void disconnected();
|
||||
void readyRead();
|
||||
|
||||
private:
|
||||
QTcpSocket *m_socket = nullptr;
|
||||
int m_socketDescriptor;
|
||||
};
|
||||
|
||||
|
||||
#endif /* QUEUEDTCPSERVERTHREAD_H */
|
100
sources/queued-server/src/main.cpp
Normal file
100
sources/queued-server/src/main.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Evgeniy Alekseev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
*
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
|
||||
#include <queued/Queued.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "QueuedServer.h"
|
||||
#include "version.h"
|
||||
|
||||
extern "C" {
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
|
||||
QueuedServer *instance = nullptr;
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// HACK preparse arguments to find out if --daemon is set
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (std::string(argv[i]) != "--daemon")
|
||||
continue;
|
||||
::daemon(0, 0);
|
||||
break;
|
||||
}
|
||||
QueuedDebug::applyLogFormat();
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
app.setApplicationName(NAME);
|
||||
app.setApplicationVersion(VERSION);
|
||||
|
||||
// parser
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(
|
||||
"Daemon for starting jobs to queue of calculations");
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
// info
|
||||
QCommandLineOption infoOption(QStringList() << "i"
|
||||
<< "info",
|
||||
"Show additional info.");
|
||||
parser.addOption(infoOption);
|
||||
|
||||
// debug mode
|
||||
QCommandLineOption debugOption(QStringList() << "d"
|
||||
<< "debug",
|
||||
"Print debug information.");
|
||||
parser.addOption(debugOption);
|
||||
|
||||
// daemon mode
|
||||
QCommandLineOption daemonOption(QStringList() << "daemon",
|
||||
"Start detached.");
|
||||
parser.addOption(daemonOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
// show info and exit
|
||||
if (parser.isSet(infoOption)) {
|
||||
auto metadata = QueuedDebug::getBuildData();
|
||||
for (auto &string : metadata)
|
||||
std::cout << qPrintable(string) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// enable debug
|
||||
if (parser.isSet(debugOption))
|
||||
QueuedDebug::enableDebug();
|
||||
|
||||
QVariantHash arguments;
|
||||
|
||||
// start application
|
||||
instance = new QueuedServer(nullptr, arguments);
|
||||
// catch SIGHUP
|
||||
signal(SIGHUP, [](int sig) -> void {
|
||||
qCInfo(LOG_SERV) << "Received SIGHUP signal, reinit components";
|
||||
instance->init();
|
||||
});
|
||||
return app.exec();
|
||||
}
|
0
sources/queued-server/zsh-completions
Normal file
0
sources/queued-server/zsh-completions
Normal file
Reference in New Issue
Block a user