/
breton75
/
modus2
Обзор
Документация
Войти
/
breton75
/
modus2
Код
Запросы
0
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
utils/mdserver/src/control_server.cpp
1 152 строки
38 KB
s.sviridov
Update control_server.cpp
19 фев 2026, 19:16
19 фев 2026, 19:16
0f3bf24
Код
Авторство
О чём код?
#include "control_server.h" #include <QLibrary> #include <QFileInfo> auto var2str = [](QVariant value) -> QString { QString result = "null"; if(value.isValid() && !value.isNull()) { switch (QMetaType::type(value.typeName())) { /* Although this function is declared as returning QVariant::Type, * the return value should be interpreted as QMetaType::Type */ case QMetaType::Bool: result = value.toBool() ? "1" : "0"; break; case QMetaType::Int: result = QString::number(value.toInt()); break; case QMetaType::UInt: result = QString::number(value.toUInt()); break; case QMetaType::LongLong: result = QString::number(value.toLongLong()); break; case QMetaType::ULongLong: result = QString::number(value.toULongLong()); break; case QMetaType::Float: result = QString::number(value.toFloat()); break; case QMetaType::Double: result = QString::number(value.toDouble()); break; case QMetaType::QString: result = value.toString(); break; default: result = QString("Тип сигнала %1 не поддерживается в данной версии").arg(value.typeName()); } } return result; }; modus::ControlServer::ControlServer(): sv::SvHttpRestApiServer() // m_ws_server(new QWebSocketServer(QStringLiteral("Modus WebSocket Server"), QWebSocketServer::SecureMode)), { } modus::ControlServer::~ControlServer() { // сначала будет вызван этот деструктор. затем деструктор базового класса } bool modus::ControlServer::configure(Params params, modus::Configuration* configuration, modus::Entities* entities, modus::MasterLogger* masterLogger) { try { if(!sv::SvHttpRestApiServer::configure(params)) throw sv::SvException(p_last_error); m_modus_configiration = configuration; m_modus_entities = entities; MASTERLOGGER = masterLogger; connect(MASTERLOGGER, &MasterLogger::connectControl, this, &ControlServer::setLogger); connect(MASTERLOGGER, &MasterLogger::disconnectControl, this, &ControlServer::deleteLogger); loadAuthPlugin(); /*if(m_modus_configiration->json().contains(P_EVENTS)) { QJsonDocument doc; QJsonObject obj; obj.insert(P_EVENTS, m_modus_configiration->json().value(P_EVENTS)); doc.setObject(obj); QString resultString = ""; QByteArray arr = doc.toJson(); if(!parseEvents(arr,resultString)) throw sv::SvException(resultString); // if(m_modus_configiration->json().value(P_EVENTS).isArray()) // { // QJsonArray loggersArray = m_modus_configiration->json().value(P_LOGGERS).toArray(); // for(auto logger : loggersArray) // { // QJsonObject obj = logger.toObject(); // createLogger(obj.value(P_PATH).toString(), obj.value(P_NAME), obj.value(P_PARAMS)); // } // } } // if (!m_ws_server->listen(QHostAddress::Any, 8001)) { // p_last_error = "Failed to open WebSocket server."; // return false; // }*/ return true; } catch(sv::SvException& e) { p_last_error = e.error; return false; } } void modus::ControlServer::start() { sv::SvHttpRestApiServer::start(); // connect(m_ws_server, &QWebSocketServer::newConnection, this, &modus::SvControlServer::newWebSockeConnection); } void modus::ControlServer::stop() { sv::SvHttpRestApiServer::stop(); } /* POST методы, для удаленного вызова */ sv::http::MessageBody modus::ControlServer::get_signal_values(const sv::http::HttpRequest& request) { /* в качестве идентификатора могут использоваться и id сигналов и их имена * то есть допускаются списки типа 1;AD_01;23;TANK_LEVEL_pb .... * Если в качестве идентификаоора передается символ '*', то метод возвращает все сигналы */ QByteArray content = request.content; sv::http::MessageBody result; sv::http::DataContent result_content{}; if(QString(content).trimmed() == "*") { for(int i = 0; i < m_modus_entities->Signals()->items().count(); i++) { modus::Signal* signal = m_modus_entities->Signals()->items().at(i); result_content.appendData(signal->config()->name, var2str(signal->value()), signal->lastUpdate()); } } else { QList<QString> ids = QString(content).split(QRegExp("[;, |]{1,}"), QString::SkipEmptyParts); // QChar(separator), QString::SkipEmptyParts); if(ids.isEmpty()) return sv::http::MessageBody(sv::http::DataContent().appendError("Неверный запрос. Список идентификаторов сигналов пуст.\n" "В качестве идентификатора могут использоваться и id сигналов и их имена. " "Допускаются списки типа 1378;AD_01;203;TANK_LEVEL_pb .... Разделителями могут быть символы ';', ',', ' ', '|'.\n" "Если в качестве параметра передается символ '*', то метод возвращает все сигналы").toByteArray(), 400); // bool ok; for(QString identifier: ids) { // modus::Signal* signal; // // сначала патаемся перевернуть идентификатор в число. если да, то берем значение по id // // иначе, считаем идентификатор именем сигнала и ищем его по имени // int id = identifier.trimmed().toInt(&ok); // if(ok) // signal = m_modus_entities->Signals()->mapById()->value(id, nullptr); // else // signal = m_modus_entities->Signals()->mapByName()->value(identifier.trimmed(), nullptr); modus::Signal* signal = m_modus_entities->Signals()->mapByUid().value(modus::Token(modus::eSignal, identifier.trimmed()).uid, nullptr); if(signal) result_content.appendData(identifier.trimmed(),var2str(signal->value()), signal->lastUpdate()); else result_content.appendError(QString("Сигнал с идентификатором '%1' не найден").arg(identifier.trimmed())); } } result.setData(result_content.toByteArray(), result_content.getCode()); return result; } sv::http::MessageBody modus::ControlServer::get_signal_values_csv(const sv::http::HttpRequest& request) { /* в качестве идентификатора могут использоваться и id сигналов и их имена * то есть допускаются списки типа 1;AD_01;23;TANK_LEVEL_pb .... * Если в качестве идентификаоора передается символ '*', то метод возвращает все сигналы */ QByteArray content = request.content; sv::http::MessageBody result(sv::http::ctcsv); sv::http::DataContent result_content; if(QString(content).trimmed() == "*") { for(int i = 0; i < m_modus_entities->Signals()->items().count(); i++) { modus::Signal* signal = m_modus_entities->Signals()->items().at(i); result_content.appendData(signal->config()->name, var2str(signal->value()), signal->lastUpdate()); } } else { QList<QString> ids = QString(content).split(QRegExp("[;, |]{1,}"), QString::SkipEmptyParts); if(ids.isEmpty()) return sv::http::MessageBody(sv::http::DataContent().appendError("Неверный запрос значений сигналов. Список идентификаторов сигналов пуст.").toByteArray(),400); // bool ok; for(QString identifier: ids) { // modus::SvSignal* signal; // // сначала пытаемся перевернуть идентификатор в число. если да, то берем значение по id // // иначе, считаем идентификатор именем сигнала и ищем его по имени // int id = identifier.trimmed().toInt(&ok); // if(ok) // signal = m_modus_entities->Signals()->mapById()->value(id, nullptr); // else // signal = m_modus_entities->Signals()->mapByName()->value(identifier.trimmed(), nullptr); modus::Signal* signal = m_modus_entities->Signals()->mapByUid().value(modus::Token(modus::eSignal, identifier.trimmed()).uid, nullptr); if(signal) result_content.appendData(identifier.trimmed(), var2str(signal->value()), signal->lastUpdate()); else result_content.appendError(identifier.trimmed()); } } result.setData(result_content.toByteArray(sv::http::ContentType::ctcsv), result_content.getCode()); return result; } sv::http::MessageBody modus::ControlServer::set_signal_values(const sv::http::HttpRequest& request) { // QString data = "{ \"signals\": [ { \"id\": 83886080, \"value\": 100} ] }"; QByteArray content = request.content; QJsonParseError je; QJsonDocument jd = QJsonDocument::fromJson(content, &je); if(je.error != QJsonParseError::NoError) return sv::http::MessageBody(sv::http::DataContent().appendError(je.errorString()).toByteArray(), 400); QJsonObject jo = jd.object(); if(!jo.contains(P_SIGNALS) || !jo.value(P_SIGNALS).isArray()) return sv::http::MessageBody(sv::http::DataContent().appendError(QString("Для операции %1 данные должны содержать массив %2 с идентификаторами и значениями сигналов") .arg("set_signal_values").arg(P_SIGNALS)).toByteArray(),400); QJsonArray ja = jo.value(P_SIGNALS).toArray(); sv::http::MessageBody result; sv::http::DataContent result_content; for(QJsonValue jv: ja) { if(!jv.isObject()) continue; QJsonObject o = jv.toObject(); if(!o.contains(P_VALUE)) continue; // if(o.contains(P_ID)) { // int id = o.value(P_ID).toInt(-1); // if(!m_modus_entities->Signals()->mapById()->contains(id)) { // result_content.appendError(QString(M_SIGNAL_ID_NOT_FOUND).arg(id)); // continue; // } // m_modus_entities->Signals()->mapById()->value(id)->setValue(o.value(P_VALUE).toVariant()); //// qDebug() << m_modus_entities->Signals()->mapById()->value(id)->value().toInt() << o.value("value").toVariant(); // } // else modus::Token token; if(o.contains(P_NAME)) token.set(modus::eSignal, o.value(P_NAME).toString("")); else token.set(modus::eSignal, o.value(P_KEY).toString("")); if(m_modus_entities->Signals()->contains(token.uid)) m_modus_entities->Signals()->item(token.uid)->setValue(o.value(P_VALUE).toVariant()); else result_content.appendError(QString(M_SIGNAL_NAME_NOT_FOUND).arg(token.name)); } result.setData(result_content.toByteArray(), result_content.getCode()); return result; } sv::http::MessageBody modus::ControlServer::get_signal_info(const sv::http::HttpRequest& request) { QByteArray content = request.content; QList<QString> ids = QString(content).split(QRegExp("[;, |]{1,}"), QString::SkipEmptyParts); // QChar(separator), QString::SkipEmptyParts); if(ids.isEmpty()) return sv::http::MessageBody(sv::http::DataContent().appendError("Неверный запрос значений сигналов. Список идентификаторов сигналов пуст.").toByteArray(),400); sv::http::MessageBody result(sv::http::ctcsv); sv::http::DataContent result_content; for(QString identifier: ids) { modus::Token token = modus::Token(modus::eSignal, identifier.trimmed()); modus::Signal* signal = m_modus_entities->Signals()->item(token.uid); if(signal) { QString master_params = QString("%1 %2 %3").arg(signal->config()->master.token.entity).arg(signal->config()->master.token.name).arg(signal->config()->master.params); QString bindings_params = QString{}; for(modus::signal::Binding reader: signal->config()->readers.values()) bindings_params.append(QString("%1 %2 %3\n").arg(reader.token.entity).arg(reader.token.name).arg(reader.params)); result_content.appendData(token.name, QString("Имя: %2\nОписание: %3\nТекущее значение: %4\nМастер: %5\nПривязки:\n%6\n") .arg(signal->config()->name) .arg(signal->config()->description) .arg(var2str(signal->value())) .arg(master_params) .arg(bindings_params).replace("\"", "'"), signal->lastUpdate()); } else result_content.appendError(QString("Сигнал с идентификатором '%1' не найден").arg(token.name)); } result.setData(result_content.toByteArray(), result_content.getCode()); return result; } sv::http::MessageBody modus::ControlServer::reset_signals(const sv::http::HttpRequest& request) { QByteArray content = request.content; QList<QString> ids = QString(content).split(QRegExp("[;, |]{1,}"), QString::SkipEmptyParts); // QChar(separator), QString::SkipEmptyParts); if(ids.isEmpty()) return sv::http::MessageBody(sv::http::DataContent().appendError("Неверный запрос значений сигналов. Список идентификаторов сигналов пуст.").toByteArray(),400); sv::http::MessageBody result; sv::http::DataContent result_content; // bool ok; for(QString identifier: ids) { modus::Token token = modus::Token(modus::eSignal, identifier.trimmed()); modus::Signal* signal = m_modus_entities->Signals()->item(token.uid); if(signal) signal->reset(); else result_content.appendError(QString("Сигнал с идентификатором '%1' не найден").arg(token.name)); } result.setData(result_content.toByteArray(), result_content.getCode()); return result; } sv::http::MessageBody modus::ControlServer::getConfiguration(const sv::http::HttpRequest& request) { return(get_configuration(request)); } sv::http::MessageBody modus::ControlServer::get_configuration(const sv::http::HttpRequest& request) { QByteArray content = request.content; sv::http::MessageBody result(sv::http::ctbytea); try { if(content.isEmpty()) { QByteArray config = QByteArray(); for(QByteArray line: *m_modus_configiration->lines()) config.append(line); result.setData(config); return result; } else { QString file = ""; QStringList params = QString(content).split("&", QString::SkipEmptyParts); for(QString p: params) { QStringList l = p.trimmed().split("="); if(l.count() != 2) continue; // if(l.first().toLower() == P_BIG) // big = (QStringList() << "t" << "true" << "1" << "yes" << "on").contains(l.last().toLower()); if(l.first().toLower() == P_FILE) file = QString(l.last()); } if(file.isEmpty()) { QByteArray config = QByteArray(); for(QByteArray line: *m_modus_configiration->lines()) config.append(line); result.setData(config); } else { // путь к основному файлу конфигурации QDir main_json_dir = QDir(QFileInfo(m_modus_configiration->file_absolute_path()).absolutePath()); QFile f(QFileInfo(main_json_dir, file).absoluteFilePath()); if(!f.open(QIODevice::ReadOnly)) throw sv::SvException(QString("Невозможно открыть файл %1.\nОшибка: %2").arg(file).arg(f.errorString())); else result.setData(f.readAll()); f.close(); } } } catch(sv::SvException& e) { result.setData(sv::http::DataContent().appendError(e.error.toUtf8()).toByteArray(),400); } return result; } sv::http::MessageBody modus::ControlServer::get_file(const sv::http::HttpRequest& request) { sv::http::MessageBody errorReply; if(!checkPermission(request.headers.get(P_AUTHORIZATION), standartPermissionsMap.value(readFiles), errorReply)) return errorReply; sv::http::MessageBody result; result.setData(sv::http::DataContent().appendError("Не реализовано в данной версии").toByteArray(), 500); return result; } sv::http::MessageBody modus::ControlServer::save_file(const sv::http::HttpRequest& request) { sv::http::MessageBody errorReply; if(!checkPermission(request.headers.get(P_AUTHORIZATION), standartPermissionsMap.value(readFiles), errorReply)) return errorReply; sv::http::MessageBody result; result.setData(sv::http::DataContent().appendError("Не реализовано в данной версии").toByteArray(), 500); return result; } sv::http::MessageBody modus::ControlServer::set_eventlog(const sv::http::HttpRequest& request) { // QByteArray content = request.content; sv::http::MessageBody result; QString s = QString{}; if(MASTERLOGGER->setEventLog(request.content, s)) result.setData(s.toUtf8(), 200); else result.setData(sv::http::DataContent().appendError(s).toByteArray(), 400); // if(!parseEvents(content, resultString)) // result.setData(sv::http::DataContent().appendError(resultString).toByteArray(), 400); // else // result.setData(resultString.toUtf8(), 200); return result; } sv::http::MessageBody modus::ControlServer::setEventLog(const sv::http::HttpRequest& request) { return set_eventlog(request); } sv::http::MessageBody modus::ControlServer::addEventLogger(const sv::http::HttpRequest& request) { sv::http::MessageBody result; QString s = QString{}; if(MASTERLOGGER->addEventLogger(request.content, s)) result.setData(s.toUtf8(), 200); else result.setData(sv::http::DataContent().appendError(s).toByteArray(), 400); return result; } sv::http::MessageBody modus::ControlServer::delEventLogger(const sv::http::HttpRequest& request) { sv::http::MessageBody result; QString s = QString{}; if(MASTERLOGGER->delEventLogger(request.content, s)) result.setData(s.toUtf8(), 200); else result.setData(sv::http::DataContent().appendError(s).toByteArray(), 400); return result; } http::MessageBody modus::ControlServer::getLoggerEntities(const http::HttpRequest&) { QJsonObject jobj; QJsonArray jarr; for(const auto& entity : modus::EntityCode.keys()) jarr.append(QJsonValue(entity)); jobj.insert("entities", jarr); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200); } http::MessageBody modus::ControlServer::getLoggerLevels(const http::HttpRequest&) { QJsonObject jobj; QJsonArray jarr; for(const auto& level : modus::event::levelStrMap) jarr.append(QJsonValue(level)); jobj.insert("levels", jarr); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200); } http::MessageBody modus::ControlServer::getLoggerTypes(const http::HttpRequest&) { QJsonObject jobj; QJsonArray jarr; for(const auto& type : modus::event::typeStrMap) jarr.append(QJsonValue(type)); jobj.insert("types", jarr); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200); } sv::http::MessageBody modus::ControlServer::getEventLoggers(const sv::http::HttpRequest&) { QJsonObject jobj{}; QJsonArray jarr{}; for(auto info: MASTERLOGGER->getEventLoggers().values()) jarr.append(info.toJsonObject()); jobj.insert(P_EVENTLOG, jarr); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200, sv::http::ctjson); } sv::http::MessageBody modus::ControlServer::getAvailableLoggers(const sv::http::HttpRequest& request) { Q_UNUSED(request); QJsonObject jobj{}; QJsonArray jarr{}; QList<LoggerInfo> loggerInfos = MASTERLOGGER->getAvailableLoggerPlugins(); // формируем JSON массив LoggerInfo for (const LoggerInfo& info : loggerInfos) jarr.append(info.toJsonObject()); jobj.insert(P_LOGGERS, QJsonValue(jarr)); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200, sv::http::ctjson); } sv::http::MessageBody modus::ControlServer::get_usernames(const sv::http::HttpRequest&) { if(!m_authPlugin) return sv::http::MessageBody(sv::http::DataContent().appendError("Данный сервер не поддерживает функцию авторизации").toByteArray(), 506); QJsonObject jobj; QJsonArray jarr; QSet<QString> usernamesSet; m_authPlugin->getAllUsernames(usernamesSet); for(auto username: usernamesSet) { jarr.append(QJsonValue(username)); } jobj.insert("usernames", jarr); return sv::http::MessageBody(QJsonDocument(jobj).toJson(QJsonDocument::Compact), 200); } sv::http::MessageBody modus::ControlServer::get_user_data(const sv::http::HttpRequest& request) { QString username; sv::http::MessageBody errorReply; if(!parseToken(request.headers.get(P_AUTHORIZATION), username, errorReply)) return errorReply; if(!m_usersData.contains(username)) return errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("Пользователь не найден на сервере. Попробуйте авторизироваться заново")).toByteArray(), 401); return sv::http::MessageBody(QJsonDocument(m_usersData.value(username).toJsonObject()).toJson(QJsonDocument::Compact), 200); } sv::http::MessageBody modus::ControlServer::registerUser(const sv::http::HttpRequest& request) { sv::http::MessageBody errorReply; if(!checkPermission(request.headers.get(P_AUTHORIZATION), standartPermissionsMap.value(readFiles), errorReply)) return errorReply; sv::http::MessageBody result; result.setData(sv::http::DataContent().appendError("Не реализовано в данной версии").toByteArray(), 500); return result; } sv::http::MessageBody modus::ControlServer::updateUser(const sv::http::HttpRequest& request) { sv::http::MessageBody errorReply; if(!checkPermission(request.headers.get(P_AUTHORIZATION), standartPermissionsMap.value(readFiles), errorReply)) return errorReply; sv::http::MessageBody result; result.setData(sv::http::DataContent().appendError("Не реализовано в данной версии").toByteArray(), 500); return result; } sv::http::MessageBody modus::ControlServer::login(const sv::http::HttpRequest& request) { if(!m_authPlugin) return sv::http::MessageBody(sv::http::DataContent().appendError("Данный сервер не поддерживает функцию авторизации").toByteArray(), 506); QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(request.content,&parseError); if(parseError.error != QJsonParseError::NoError) return sv::http::MessageBody(sv::http::DataContent().appendError(QString("Невозможно разобрать параметры для авторизации %1").arg(parseError.errorString())).toByteArray(), 400); QJsonObject jobj = doc.object(); JWT* jwt = m_authPlugin->createToken(jobj.value(P_USER_NAME).toString(), jobj.value(P_PASSWORD).toString()); if(!jwt) return sv::http::MessageBody(sv::http::DataContent().appendError(QString("Ошибка авторизации Неправильный логин или пароль")).toByteArray(), 400); m_usersData[jobj.value(P_USER_NAME).toString()] = m_authPlugin->loadUserData(jobj.value(P_USER_NAME).toString());; QJsonObject jo; jo.insert(P_TOKEN, jwt->toString()); return sv::http::MessageBody(QJsonDocument(jo).toJson(QJsonDocument::Compact), 200); } sv::http::MessageBody modus::ControlServer::user_action(const sv::http::HttpRequest& request) { QByteArray content = request.content; sv::http::MessageBody result; QJsonParseError je; QJsonDocument jd = QJsonDocument::fromJson(content, &je); if(je.error != QJsonParseError::NoError) return sv::http::MessageBody(sv::http::DataContent().appendError(je.errorString()).toByteArray(), 400); QJsonObject jo = jd.object(); JWT* token = JWT::fromString(request.headers.get(P_AUTHORIZATION)); QString username = ""; if(!token) username = "unauthorized"; else username = token->username(); qInfo()<< modus::event::Message(modus::Token(P_CONTROL, 0), QString("%1 %2").arg(username).arg(jo.value(P_ACTION).toString()), mtact, llinf, nodata); result.setData(sv::http::DataContent().appendData("result", "OK", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()).toByteArray()); return result; } void modus::ControlServer::loadAuthPlugin() { if(m_authPlugin) delete m_authPlugin; m_authPlugin = nullptr; if(!QFileInfo(QDir(qApp->applicationDirPath()).absoluteFilePath("lib/libfileAuth.so")).exists()) { qDebug() << QString("Библиотека авторизации не найдена %1").arg(QDir(qApp->applicationDirPath()).absoluteFilePath("lib/libfileAuth.so")); return; } QPluginLoader pluginLoader(QDir(qApp->applicationDirPath()).absoluteFilePath("lib/libfileAuth.so")); m_authPlugin = qobject_cast<AuthPluginInterface*>(pluginLoader.instance()); if(!m_authPlugin) { qDebug() << QString("Ошибка загрузки библиотеки авторизации %1").arg(pluginLoader.errorString()); } else { QString projectName = QFileInfo(m_modus_configiration->file_absolute_path()).fileName(); // m_modus_configiration->file_absolute_path().right(m_modus_configiration->file_absolute_path().length() - m_modus_configiration->file_absolute_path().lastIndexOf('/') - 1); QString projectPath = QFileInfo(m_modus_configiration->file_absolute_path()).absoluteFilePath(); // m_modus_configiration->file_absolute_path().left(m_modus_configiration->file_absolute_path().lastIndexOf('/')); QString filePath = ""; if(projectName.split('.').count() == 2) filePath = QDir(projectPath.left(projectPath.length() - projectName.length())).absoluteFilePath(QString(".%1.users").arg(projectName.split('.').at(0))); QJsonDocument doc; QJsonObject obj; obj.insert("filePath", filePath); doc.setObject(obj); if(!m_authPlugin->init(QString(doc.toJson()))) qDebug() << QString("Ошибка загрузки библиотеки авторизации %1").arg(m_authPlugin->lastError()); } } bool modus::ControlServer::checkPermission(const QString& tokenString, const QString& permission, sv::http::MessageBody& errorReply) { QString username; if(!parseToken(tokenString, username, errorReply)) return false; if(!m_usersData.contains(username)){ errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("Пользователь не найден на сервере. Попробуйте авторизироваться заново")).toByteArray(), 401); return false; } if(!m_usersData.value(username).permissions.value(permission).toBool()){ errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("У вас нет доступа к этой команде")).toByteArray(), 403); return false; } return true; } bool modus::ControlServer::parseToken(const QString& tokenString, QString& username, sv::http::MessageBody& errorReply) { if(!JWT::verify(tokenString)){ errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("Для данной операции необходимо авторизироваться. Невалидный токен")).toByteArray(), 400); return false; } JWT* token = JWT::fromString(tokenString); if(!token){ errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("Не удалось разобрать токен. Обратитесь к администратору")).toByteArray(), 500); return false; } QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(token->getPayload(), &parseError); if(parseError.error != QJsonParseError::NoError){ delete token; errorReply = sv::http::MessageBody(sv::http::DataContent().appendError(QString("Не удалось разобрать токен. Обратитесь к администратору")).toByteArray(), 500); return false; } username = doc.object().value(P_SUB).toString(); delete token; return true; } http::MessageBody modus::ControlServer::getLibInfo(const sv::http::HttpRequest& request) { sv::http::MessageBody result(sv::http::ctbytea); QByteArray lib_info = QByteArray{}; try { QString lib_file_name = QStringLiteral(); QStringList http_params = QString(request.content).split("&", QString::SkipEmptyParts); for(QString p: http_params) { QStringList l = p.trimmed().split("="); if(l.count() != 2) continue; if(l.first().toLower() == P_FILE) { lib_file_name = QString(l.last()); break; } } // если имя библиотеки не указано, возвращаем клиенту ошибку if(lib_file_name.isEmpty()) throw sv::SvException("В операции отказано. Не указано имя библиотеки."); // ищем библиотеку по путям в paths, пытаемся зпгрузить ее и прочитать параметры // путь к основному файлу конфигурации QDir main_json_dir = QFileInfo(m_modus_configiration->file_absolute_path()).absoluteDir(); QStringList paths = m_modus_configiration->json().value(P_PATHS).toString().split(";"); for(const QString& path: qAsConst(paths)) { QString lib_path = QDir::cleanPath(main_json_dir.absoluteFilePath(path)); QFileInfo lib_fi = QFileInfo(lib_path, lib_file_name); // libs_fi = QDir(libpath).entryInfoList(QStringList() << "*.so", QDir::Files | QDir::NoDot | QDir::NoDotDot); // for(QFileInfo lib_fi: libs_fi) { if(lib_fi.exists() && lib_fi.isFile()) { // QString lib_path = lib_fi.absoluteFilePath(); // QFileInfo(QDir(main_json_dir).path()) QLibrary lib(lib_fi.absoluteFilePath()); if(!lib.load()) throw SvException(lib.errorString()); typedef const char*(*get_description)(void); get_description getDescription = (get_description)lib.resolve("getDescription"); typedef const char*(*get_params)(void); get_params getParams = (get_params)lib.resolve("getParams"); if(getDescription) lib_info.append(QString(getDescription()).toUtf8()); if(getParams) { QString p = QString(getParams()); QString params = QStringLiteral("\nОписание параметров:\n"); QJsonParseError pe; QJsonDocument d = QJsonDocument::fromJson(p.toUtf8(), &pe); if(pe.error == QJsonParseError::NoError) { QJsonObject o = d.object(); if(o.contains("params") && o.value("params").isArray()) { QJsonArray a = o.value("params").toArray(); for(QJsonValue v: a) { if(v.isObject()) { QJsonObject vo = v.toObject(); if(vo.contains("name")) { params.append(QString("%1\n").arg(vo.value("name").toString())); params.append(QString(" описание: %1\n").arg(vo.value("mean").toString())); params.append(QString(" тип: %1\n").arg(vo.value("type").toString())); params.append(QString(" обязательный: %1\n").arg(vo.contains("required") ? (vo.value("required").toBool() ? "да" : "нет") : "")); params.append(QString(" по умолчанию: %1\n").arg(vo.value("default").toString())); params.append(QString(" диапазон значений: %1\n").arg(vo.value("range").toString())); } } } } } else params.append(QString("Ошибка при формировании списка параметров: %1").arg(pe.errorString())); lib_info.append(params.toUtf8()); } lib.unload(); break; } } } catch(sv::SvException& e) { result.setData(sv::http::DataContent().appendError(e.error.toUtf8()).toByteArray(),400); } result.setData(lib_info, 200); return result; } /* python GET методы, для удаленного вызова */ QByteArray modus::ControlServer::call_get_method_python(const QString& method, const QString& params) { QDir dir(p_params.applets_path); QString python_script_file = dir.absoluteFilePath(QString("%1.py").arg(method)); QByteArray reply = QByteArray(); QFile f(python_script_file); if(!f.exists()) { reply = sv::http::HttpReply(sv::http::MessageBody(sv::http::DataContent() .appendError(QString("Метод '%1' не найден на данном сервере") .arg(method)).toByteArray(), 404) ).toByteArray(); } else { QProcess p{}; p.start(QString("/usr/bin/python3"), QStringList() << python_script_file << m_modus_configiration->file_absolute_path() << params); if(p.waitForStarted(1000)) { if(p.waitForReadyRead(1000)) { QByteArray r = p.readAll(); sv::http::DataContent dc = sv::http::DataContent() .appendData(QString("text"), QString("Результат выполнения апплета '%1': %2") .arg(method).arg(QString(r)), std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()); reply = sv::http::HttpReply(200, sv::http::MessageBody(dc.toByteArray(), 200).toByteArray()).toByteArray(); qDebug() << r; } else { reply = sv::http::HttpReply(sv::http::MessageBody(sv::http::DataContent() .appendError(QString("Апплет '%1' не ответил вовремя") .arg(method)).toByteArray(), 500 )).toByteArray(); } } else { reply = sv::http::HttpReply(sv::http::MessageBody(sv::http::DataContent() .appendError(QString("Апплет '%1' не ответил вовремя") .arg(method)).toByteArray(), 500) ).toByteArray(); } p.close(); } return reply; } void modus::ControlServer::setLogger() { deleteLogger(); connect(this, &sv::SvHttpRestApiServer::message, this, &modus::ControlServer::log); } void modus::ControlServer::deleteLogger() { disconnect(this, &sv::SvHttpRestApiServer::message, this, &modus::ControlServer::log); } /* Web Socket */ //void modus::SvControlServer::newWebSockeConnection() //{ // static int client_id = 0; // m_websocket_clients.append(m_ws_server->nextPendingConnection()); // QWebSocket* new_client = m_websocket_clients.last(); // new_client->setObjectName(QString("client %1").arg(client_id++)); // new_client->sendTextMessage(QString("Hello %1").arg(new_client->objectName())); //// qDebug() << QString("ws %1 connected").arg(new_client->objectName()) << new_client->peerAddress().toString(); // connect(new_client, &QWebSocket::disconnected, this, &modus::SvControlServer::webSocketDisconnected); // connect(new_client, &QWebSocket::textMessageReceived, this, &modus::SvControlServer::webSocketDisconnected); //} void modus::ControlServer::messageSlot(const QString &entity, int id, const QString &type, const QString& time, const QString& message) { // if(!m_websocket_clients.count()) // return; QString prn = "{entity}:{id}:{time}:{type}\t{message}"; prn = prn.replace("{entity}", entity) .replace("{id}", QString::number(id)) .replace("{time}", time) .replace("{type}", type) .replace("{message}", message); // for(QWebSocket* client: m_websocket_clients) // client->sendTextMessage(prn); } void modus::ControlServer::log(const QString& msg) { qInfo()<< modus::event::Message(modus::Token(P_CONTROL, 0), msg, mtdbg, lldbg, nodata); } /*bool modus::ControlServer::parseEvents(QByteArray& content, QString& resultString) { QList<modus::event::Filter> filters; QString statusString; if(!MASTERLOGGER->parseRequest(content, statusString, filters)) { resultString = QString("Ошибка разбора запроса:\n%1").arg(statusString); return false; } for(auto filter: filters) { qCritical() << "ControlServer::parseEvents" << filter.sender().entity_s() << filter.sender().name; if(filter.sender().entity == modus::eControl) { setLogger(); resultString = filter.sender().toString(); // QString("%1:%2").arg(filter.sender().entity()).arg(filter.sender().identifier().toString()); } } if(!MASTERLOGGER->setEventLog(filters, statusString)) { resultString = QString("Ошибка создания логера1:\n%1").arg(statusString); return false; } return true; }*/ //void modus::SvControlServer::processWebSocketRequest() //{ //} //void modus::SvControlServer::webSocketDisconnected() //{ // QWebSocket* client = qobject_cast<QWebSocket*>(sender()); // if(!client) { // qDebug() << QString("disconnect client is null"); // return; // } // qDebug() << QString("%1 disconnected").arg(client->objectName()); // m_websocket_clients.removeAt(m_websocket_clients.indexOf(client)); // client->deleteLater(); //}