#include #include #include #include #include #include #include #include #include #include #include void DialogAgent::createUI() { this->setWindowTitle("Generate Agent"); this->setProperty("Main", "base"); listenerLabel = new QLabel("Listener:", this); listenerInput = new QLineEdit(this); listenerInput->setReadOnly(true); listenerDisplayEdit = new QLineEdit(this); listenerDisplayEdit->setReadOnly(true); listenerDisplayEdit->setPlaceholderText("Click to select listeners..."); listenerSelectBtn = new QPushButton("...", this); listenerSelectBtn->setToolTip("Select listeners"); listenerListWidget = new QListWidget(); listenerListWidget->setSelectionMode(QAbstractItemView::SingleSelection); listenerListWidget->setDragDropMode(QAbstractItemView::InternalMove); listenerListWidget->setDefaultDropAction(Qt::MoveAction); listenerListWidget->setMinimumWidth(250); listenerListWidget->setMinimumHeight(150); btnMoveUp = new QPushButton("↑"); btnMoveUp->setToolTip("Move selected listener up"); btnMoveDown = new QPushButton("↓"); btnMoveDown->setToolTip("Move selected listener down"); auto btnLayout = new QVBoxLayout(); btnLayout->setContentsMargins(0, 0, 0, 0); btnLayout->setSpacing(4); btnLayout->addWidget(btnMoveUp); btnLayout->addWidget(btnMoveDown); btnLayout->addStretch(); auto popupLayout = new QHBoxLayout(); popupLayout->setContentsMargins(8, 8, 8, 8); popupLayout->setSpacing(4); popupLayout->addWidget(listenerListWidget); popupLayout->addLayout(btnLayout); listenerPopupDialog = new QDialog(this, Qt::Popup | Qt::FramelessWindowHint); listenerPopupDialog->setLayout(popupLayout); listenerPopupDialog->setProperty("Main", "base"); listenerSelectionWidget = new QWidget(this); auto listenerSelectionLayout = new QHBoxLayout(listenerSelectionWidget); listenerSelectionLayout->setContentsMargins(0, 0, 0, 0); listenerSelectionLayout->setSpacing(4); listenerSelectionLayout->addWidget(listenerDisplayEdit); listenerSelectionLayout->addWidget(listenerSelectBtn); listenerSelectionWidget->setVisible(false); agentLabel = new QLabel("Agent:", this); agentCombobox = new QComboBox(this); profileLabel = new QLabel("Profile:", this); inputProfileName = new QLineEdit(this); inputProfileName->setToolTip("Profile name"); actionSaveProfile = new QAction(this); actionSaveProfile->setCheckable(true); actionSaveProfile->setChecked(true); actionSaveProfile->setToolTip("Click to toggle: Save as profile"); actionSaveProfile->setIcon(QIcon(":/icons/check")); inputProfileName->addAction(actionSaveProfile, QLineEdit::TrailingPosition); auto stackGridLayout = new QGridLayout(); stackGridLayout->setHorizontalSpacing(0); stackGridLayout->setContentsMargins(0, 0, 0, 0); configStackWidget = new QStackedWidget(this); stackGridLayout->addWidget(configStackWidget, 0, 0, 1, 1); // stackGridLayout->setRowStretch(0, 1); // stackGridLayout->setColumnStretch(0, 1); agentConfigGroupbox = new QGroupBox("Agent config", this); agentConfigGroupbox->setAlignment(Qt::AlignHCenter); agentConfigGroupbox->setLayout(stackGridLayout); buildButton = new QPushButton("Generate", this); buildButton->setDefault(true); buildButton->setFixedWidth(160); buildButton->setFocus(); menuContext = new QMenu(this); menuContext->addAction("Rename", this, &DialogAgent::onProfileRename); menuContext->addAction("Remove", this, &DialogAgent::onProfileRemove); label_Profiles = new QLabel(this); label_Profiles->setAlignment(Qt::AlignCenter); label_Profiles->setText("Profiles"); cardWidget = new CardListWidget(this); cardWidget->setFixedWidth(220); cardWidget->setContextMenuPolicy(Qt::CustomContextMenu); cardWidget->addAction(menuContext->menuAction()); cardWidget->setSelectionMode(QAbstractItemView::SingleSelection); cardWidget->setFocusPolicy(Qt::NoFocus); buttonNewProfile = new QPushButton(this); buttonNewProfile->setText("New Profile"); buttonNewProfile->setMinimumSize(QSize(10, 30)); buttonLoad = new QPushButton(QIcon(":/icons/file_open"), "", this); buttonLoad->setIconSize(QSize(20, 20)); buttonLoad->setFixedSize(QSize(30, 30)); buttonLoad->setToolTip("Load profile from file"); buttonSave = new QPushButton(QIcon(":/icons/save_as"), "", this); buttonSave->setIconSize(QSize(20, 20)); buttonSave->setFixedSize(QSize(30, 30)); buttonSave->setToolTip("Save profile to file"); auto leftPanelLayout = new QGridLayout(); leftPanelLayout->setVerticalSpacing(8); leftPanelLayout->setHorizontalSpacing(8); leftPanelLayout->setContentsMargins(5, 5, 5, 5); leftPanelLayout->addWidget(listenerLabel, 0, 0); leftPanelLayout->addWidget(listenerInput, 0, 1); leftPanelLayout->addWidget(listenerSelectionWidget, 0, 1); leftPanelLayout->addWidget(agentLabel, 1, 0); leftPanelLayout->addWidget(agentCombobox, 1, 1); leftPanelLayout->addWidget(profileLabel, 2, 0); leftPanelLayout->addWidget(inputProfileName, 2, 1); leftPanelLayout->addWidget(agentConfigGroupbox, 3, 0, 1, 2); leftPanelLayout->setRowStretch(0, 0); leftPanelLayout->setRowStretch(1, 0); leftPanelLayout->setRowStretch(2, 0); leftPanelLayout->setRowStretch(3, 1); leftPanelLayout->setColumnStretch(0, 0); leftPanelLayout->setColumnStretch(1, 1); auto actionButtonsLayout = new QHBoxLayout(); actionButtonsLayout->addStretch(); actionButtonsLayout->addWidget(buildButton); actionButtonsLayout->addStretch(); auto formLayout = new QVBoxLayout(); formLayout->setContentsMargins(10, 10, 10, 10); formLayout->setSpacing(10); formLayout->addLayout(leftPanelLayout, 1); formLayout->addLayout(actionButtonsLayout); auto formWidget = new QWidget(this); formWidget->setLayout(formLayout); auto separatorLine = new QFrame(this); separatorLine->setFrameShape(QFrame::VLine); separatorLine->setFrameShadow(QFrame::Sunken); auto profileButtonsLayout = new QHBoxLayout(); profileButtonsLayout->setContentsMargins(0, 0, 0, 0); profileButtonsLayout->setSpacing(5); profileButtonsLayout->addWidget(buttonNewProfile, 1); profileButtonsLayout->addWidget(buttonLoad); profileButtonsLayout->addWidget(buttonSave); auto profilesLayout = new QVBoxLayout(); profilesLayout->setContentsMargins(5, 5, 5, 5); profilesLayout->setSpacing(5); profilesLayout->addWidget(label_Profiles); profilesLayout->addWidget(cardWidget, 1); profilesLayout->addLayout(profileButtonsLayout); auto profilesPanel = new QWidget(this); profilesPanel->setLayout(profilesLayout); collapseButton = new QPushButton(QIcon(":/icons/arrow_drop_down"), " build log", this); collapseButton->setFlat(true); collapseButton->setIconSize(QSize(16, 16)); collapseButton->setFixedHeight(24); collapseButton->setCursor(Qt::PointingHandCursor); connect(collapseButton, &QPushButton::clicked, this, [this]() { bool visible = buildLogOutput->isVisible(); buildLogOutput->setVisible(!visible); collapseButton->setIcon(QIcon(visible ? ":/icons/arrow_right" : ":/icons/arrow_drop_down")); }); buildLogOutput = new QTextEdit(this); buildLogOutput->setReadOnly(true); buildLogOutput->setMinimumHeight(150); buildLogOutput->setVisible(false); buildLogOutput->setStyleSheet("background-color: #151515; color: #BEBEBE; border: 1px solid #2A2A2A; border-radius: 4px;"); buildLogOutput->setFont(FontManager::instance().getFont("Hack")); auto buildLogLayout = new QVBoxLayout(); buildLogLayout->setContentsMargins(5, 0, 5, 5); buildLogLayout->setSpacing(2); buildLogLayout->addWidget(collapseButton); buildLogLayout->addWidget(buildLogOutput, 1); buildLogPanel = new QWidget(this); buildLogPanel->setLayout(buildLogLayout); buildLogPanel->setVisible(false); auto topLayout = new QHBoxLayout(); topLayout->setContentsMargins(0, 0, 0, 0); topLayout->setSpacing(0); topLayout->addWidget(formWidget, 1); topLayout->addWidget(separatorLine); topLayout->addWidget(profilesPanel); auto mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(5, 5, 5, 5); mainLayout->setSpacing(5); mainLayout->addLayout(topLayout, 1); mainLayout->addWidget(buildLogPanel); this->setLayout(mainLayout); } DialogAgent::DialogAgent(AdaptixWidget* adaptixWidget, const QString &listenerName, const QString &listenerType) { this->adaptixWidget = adaptixWidget; this->createUI(); this->listenerName = listenerName; this->listenerType = listenerType; connect(cardWidget, &QListWidget::itemPressed, this, &DialogAgent::onProfileSelected); connect(cardWidget, &QListWidget::customContextMenuRequested, this, &DialogAgent::handleProfileContextMenu); connect(agentCombobox, &QComboBox::currentTextChanged, this, &DialogAgent::changeConfig); connect(buildButton, &QPushButton::clicked, this, &DialogAgent::onButtonBuild); connect(buttonNewProfile, &QPushButton::clicked, this, &DialogAgent::onButtonNewProfile); connect(buttonLoad, &QPushButton::clicked, this, &DialogAgent::onButtonLoad); connect(buttonSave, &QPushButton::clicked, this, &DialogAgent::onButtonSave); connect(inputProfileName, &QLineEdit::textEdited, this, &DialogAgent::onProfileNameEdited); connect(actionSaveProfile, &QAction::toggled, this, &DialogAgent::onSaveProfileToggled); connect(listenerListWidget, &QListWidget::itemChanged, this, &DialogAgent::onListenerSelectionChanged); connect(btnMoveUp, &QPushButton::clicked, this, &DialogAgent::onMoveListenerUp); connect(btnMoveDown, &QPushButton::clicked, this, &DialogAgent::onMoveListenerDown); connect(listenerSelectBtn, &QPushButton::clicked, this, &DialogAgent::showListenerPopup); this->listenerInput->setText(listenerName); } DialogAgent::~DialogAgent() { stopBuild(); } void DialogAgent::AddExAgents(const QStringList &agents, const QMap &uis) { agentCombobox->clear(); this->agents = agents; this->ax_uis = uis; for (auto agent : agents) { auto ax_ui = &this->ax_uis[agent]; ax_ui->widget->setParent(nullptr); ax_ui->widget->setParent(this); ax_ui->container->setParent(nullptr); ax_ui->container->setParent(this); configStackWidget->addWidget(ax_ui->widget); agentCombobox->addItem(agent); } } void DialogAgent::SetProfile(const AuthProfile &profile) { this->authProfile = profile; loadProfiles(); } void DialogAgent::SetAvailableListeners(const QVector &listeners) { this->availableListeners = listeners; } void DialogAgent::SetAgentTypes(const QMap &types) { this->agentTypes = types; } void DialogAgent::Start() { this->setModal(true); this->show(); } // void DialogAgent::onButtonGenerate() // { // QString agentName = agentCombobox->currentText(); // QString profileName = inputProfileName->text().trimmed(); // bool shouldSaveProfile = actionSaveProfile->isChecked() && !profileName.isEmpty(); // // auto configData = QString(); // if (ax_uis.contains(agentName) && ax_uis[agentName].container) // configData = ax_uis[agentName].container->toJson(); // // QString baseDir = authProfile.GetProjectDir(); // // QPointer safeThis = this; // /// ToDo: listenersName array // HttpReqAgentGenerateAsync(listenerName, agentName, configData, authProfile, // [safeThis, baseDir, agentName, configData, profileName, shouldSaveProfile](bool success, const QString &message, const QJsonObject&) { // if (!success) { // MessageError(message); // return; // } // // if (safeThis && shouldSaveProfile) { // safeThis->saveProfile(profileName, agentName, configData); // safeThis->loadProfiles(); // } // // QStringList parts = message.split(":"); // if (parts.size() != 2) { // MessageError("The response format is not supported"); // return; // } // // QByteArray content = QByteArray::fromBase64(parts[1].toUtf8()); // QString filename = QString( QByteArray::fromBase64(parts[0].toUtf8())); // QString initialPath = QDir(baseDir).filePath(filename); // // NonBlockingDialogs::getSaveFileName(safeThis, "Save File", initialPath, "All Files (*.*)", // [safeThis, content](const QString& filePath) { // if (filePath.isEmpty()) // return; // // QFile file(filePath); // if (!file.open(QIODevice::WriteOnly)) { // MessageError("Failed to open file for writing"); // return; // } // // file.write(content); // file.close(); // // QInputDialog inputDialog; // inputDialog.setWindowTitle("Save agent"); // inputDialog.setLabelText("File saved to:"); // inputDialog.setTextEchoMode(QLineEdit::Normal); // inputDialog.setTextValue(filePath); // inputDialog.adjustSize(); // inputDialog.move(QGuiApplication::primaryScreen()->geometry().center() - inputDialog.geometry().center()); // inputDialog.exec(); // // if (safeThis) // safeThis->close(); // }); // }); // } void DialogAgent::onButtonLoad() { QString baseDir = authProfile.GetProjectDir(); QPointer safeThis = this; QString currentListenerType = listenerType; NonBlockingDialogs::getOpenFileName(this, "Select file", baseDir, "JSON files (*.json)", [safeThis, currentListenerType](const QString& filePath) { if (filePath.isEmpty()) return; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return; QByteArray fileContent = file.readAll(); file.close(); QJsonParseError parseError; QJsonDocument document = QJsonDocument::fromJson(fileContent, &parseError); if (parseError.error != QJsonParseError::NoError || !document.isObject()) { MessageError("Error JSON parse"); return; } QJsonObject jsonObject = document.object(); if ( !jsonObject.contains("listener_type") || !jsonObject["listener_type"].isString() ) { MessageError("Required parameter 'listener_type' is missing"); return; } if ( !jsonObject.contains("agent") || !jsonObject["agent"].isString() ) { MessageError("Required parameter 'agent' is missing"); return; } if ( !jsonObject.contains("config") || !jsonObject["config"].isString() ) { MessageError("Required parameter 'config' is missing"); return; } if(currentListenerType != jsonObject["listener_type"].toString()) { MessageError("Listener type mismatch"); return; } if (!safeThis) return; QString agentType = jsonObject["agent"].toString(); int typeIndex = safeThis->agentCombobox->findText( agentType ); if ( typeIndex == -1 ) { MessageError("No such agent exists"); return; } safeThis->agentCombobox->setCurrentIndex(typeIndex); safeThis->changeConfig(agentType); QString configData = jsonObject["config"].toString(); safeThis->ax_uis[agentType].container->fromJson(configData); }); } void DialogAgent::onButtonSave() { QString configType = agentCombobox->currentText(); auto configData = QString(); if (ax_uis.contains(configType) && ax_uis[configType].container) configData = ax_uis[configType].container->toJson(); QJsonObject dataJson; dataJson["listener_type"] = listenerType; dataJson["agent"] = configType; dataJson["config"] = configData; QByteArray fileContent = QJsonDocument(dataJson).toJson(); QString tmpFilename = QString("%1_config.json").arg(configType); QString baseDir = authProfile.GetProjectDir(); QString initialPath = QDir(baseDir).filePath(tmpFilename); NonBlockingDialogs::getSaveFileName(this, "Save File", initialPath, "JSON files (*.json)", [this, fileContent](const QString& filePath) { if (filePath.isEmpty()) return; QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { MessageError("Failed to open file for writing"); return; } file.write(fileContent); file.close(); QInputDialog inputDialog; inputDialog.setWindowTitle("Save config"); inputDialog.setLabelText("File saved to:"); inputDialog.setTextEchoMode(QLineEdit::Normal); inputDialog.setTextValue(filePath); inputDialog.adjustSize(); inputDialog.move(QGuiApplication::primaryScreen()->geometry().center() - inputDialog.geometry().center()); inputDialog.exec(); }); } void DialogAgent::changeConfig(const QString &agentName) { if (ax_uis.contains(agentName)) { auto ax_ui = &ax_uis[agentName]; if (ax_ui) { configStackWidget->setCurrentWidget(ax_ui->widget); this->resize(ax_ui->width, ax_ui->height); } } AgentTypeInfo typeInfo = agentTypes.value(agentName, AgentTypeInfo{false, QStringList()}); bool isMultiListeners = typeInfo.multiListeners; listenerSelectionWidget->setVisible(isMultiListeners); listenerInput->setVisible(!isMultiListeners); listenerLabel->setText(isMultiListeners ? "Listeners:" : "Listener:"); if (isMultiListeners) { QStringList supportedTypes = typeInfo.listenerTypes; listenerListWidget->blockSignals(true); listenerListWidget->clear(); for (const auto &listener : availableListeners) { if (!supportedTypes.contains(listener.ListenerRegName)) continue; auto *item = new QListWidgetItem(listener.Name); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(listener.Name == listenerName ? Qt::Checked : Qt::Unchecked); item->setData(Qt::UserRole, listener.Name); listenerListWidget->addItem(item); } listenerListWidget->blockSignals(false); } QString baseName = agentName; if (!profileNameManuallyEdited) inputProfileName->setText(generateUniqueProfileName(baseName)); } void DialogAgent::loadProfiles() { cardWidget->clear(); QString project = authProfile.GetProject(); if (project.isEmpty()) return; QVector> profiles = Storage::ListAgentProfiles(project); for (const auto& profile : profiles) { QString profileName = profile.first; QString profileData = profile.second; QJsonParseError parseError; QJsonDocument document = QJsonDocument::fromJson(profileData.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError || !document.isObject()) continue; QJsonObject jsonObject = document.object(); QString profileListenerType = jsonObject.contains("listener_type") && jsonObject["listener_type"].isString() ? jsonObject["listener_type"].toString() : ""; if (profileListenerType != listenerType) continue; QString profileListener = jsonObject.contains("listener") && jsonObject["listener"].isString() ? jsonObject["listener"].toString() : ""; QString timestamp = jsonObject.contains("timestamp") && jsonObject["timestamp"].isString() ? jsonObject["timestamp"].toString() : ""; QString subtitle = profileListener; if (!timestamp.isEmpty()) subtitle = profileListener + " | " + timestamp; cardWidget->addCard(profileName, subtitle); } } void DialogAgent::saveProfile(const QString &profileName, const QString &agentName, const QString &configData) { QString project = authProfile.GetProject(); QVector> existingProfiles = Storage::ListAgentProfiles(project); for (const auto& profile : existingProfiles) { QJsonDocument doc = QJsonDocument::fromJson(profile.second.toUtf8()); QJsonObject obj = doc.object(); if (obj["listener_type"].toString() == listenerType && obj["agent"].toString() == agentName && obj["config"].toString() == configData) return; } QJsonObject dataJson; dataJson["listener_type"] = listenerType; dataJson["listener"] = listenerName; dataJson["agent"] = agentName; dataJson["config"] = configData; dataJson["timestamp"] = QDateTime::currentDateTime().toString("dd.MM hh:mm"); QString profileData = QJsonDocument(dataJson).toJson(QJsonDocument::Compact); Storage::AddAgentProfile(project, profileName, profileData); } QString DialogAgent::generateUniqueProfileName(const QString &baseName) { QString project = authProfile.GetProject(); if (project.isEmpty()) return baseName + "_1"; QVector> profiles = Storage::ListAgentProfiles(project); QSet existingNames; for (const auto& profile : profiles) existingNames.insert(profile.first); int num = 1; QString candidate; do { candidate = QString("%1_%2").arg(baseName).arg(num); num++; } while (existingNames.contains(candidate)); return candidate; } void DialogAgent::onButtonNewProfile() { inputProfileName->clear(); cardWidget->clearSelection(); actionSaveProfile->setChecked(true); profileNameManuallyEdited = false; QString agentName = agentCombobox->currentText(); if (!agentName.isEmpty()) inputProfileName->setText(generateUniqueProfileName(agentName)); } void DialogAgent::onProfileSelected() { auto* item = cardWidget->currentItem(); if (!item) return; QString profileName = item->data(CardListWidget::TitleRole).toString(); if (profileName.isEmpty()) return; QString project = authProfile.GetProject(); if (project.isEmpty()) return; QString profileData = Storage::GetAgentProfile(project, profileName); if (profileData.isEmpty()) return; QJsonParseError parseError; QJsonDocument document = QJsonDocument::fromJson(profileData.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError || !document.isObject()) { MessageError("Error parsing profile data"); return; } QJsonObject jsonObject = document.object(); profileNameManuallyEdited = true; inputProfileName->setText(profileName); if (jsonObject.contains("agent") && jsonObject["agent"].isString()) { QString agentType = jsonObject["agent"].toString(); int typeIndex = agentCombobox->findText(agentType); if (typeIndex != -1 && ax_uis.contains(agentType)) { agentCombobox->setCurrentIndex(typeIndex); if (jsonObject.contains("config") && jsonObject["config"].isString()) { QString configData = jsonObject["config"].toString(); ax_uis[agentType].container->fromJson(configData); } } } } void DialogAgent::handleProfileContextMenu(const QPoint &pos) { QPoint globalPos = cardWidget->mapToGlobal(pos); menuContext->exec(globalPos); } void DialogAgent::onProfileRemove() { auto* item = cardWidget->currentItem(); if (!item) return; QString profileName = item->data(CardListWidget::TitleRole).toString(); if (!profileName.isEmpty()) { QString project = authProfile.GetProject(); if (!project.isEmpty()) Storage::RemoveAgentProfile(project, profileName); } delete cardWidget->takeItem(cardWidget->row(item)); loadProfiles(); } void DialogAgent::onProfileRename() { auto* item = cardWidget->currentItem(); if (!item) return; QString oldName = item->data(CardListWidget::TitleRole).toString(); if (oldName.isEmpty()) return; QString project = authProfile.GetProject(); if (project.isEmpty()) return; bool ok; QString newName = QInputDialog::getText(this, "Rename Profile", "New profile name:", QLineEdit::Normal, oldName, &ok); if (!ok || newName.trimmed().isEmpty() || newName == oldName) return; newName = newName.trimmed(); QString profileData = Storage::GetAgentProfile(project, oldName); if (profileData.isEmpty()) return; Storage::RemoveAgentProfile(project, oldName); Storage::AddAgentProfile(project, newName, profileData); loadProfiles(); if (inputProfileName->text() == oldName) inputProfileName->setText(newName); } void DialogAgent::onProfileNameEdited(const QString &text) { Q_UNUSED(text); profileNameManuallyEdited = true; } void DialogAgent::onSaveProfileToggled(bool checked) { if (checked) actionSaveProfile->setIcon(QIcon(":/icons/check")); else actionSaveProfile->setIcon(QIcon(":/icons/close")); } void DialogAgent::onButtonBuild() { if (buildWorker) { stopBuild(); return; } QString agentName = agentCombobox->currentText(); QString profileName = inputProfileName->text().trimmed(); bool shouldSaveProfile = actionSaveProfile->isChecked() && !profileName.isEmpty(); auto configData = QString(); if (ax_uis.contains(agentName) && ax_uis[agentName].container) configData = ax_uis[agentName].container->toJson(); if (shouldSaveProfile) { saveProfile(profileName, agentName, configData); loadProfiles(); } QStringList selectedListeners; bool isMultiListeners = agentTypes.value(agentName, AgentTypeInfo{false, QStringList()}).multiListeners; if (isMultiListeners) { for (int i = 0; i < listenerListWidget->count(); ++i) { auto *item = listenerListWidget->item(i); if (item->checkState() == Qt::Checked) { selectedListeners.append(item->data(Qt::UserRole).toString()); } } if (selectedListeners.isEmpty()) { MessageError("Please select at least one listener"); return; } } else { selectedListeners.append(listenerName); } buildLogOutput->clear(); buildLogPanel->setVisible(true); buildLogOutput->setVisible(true); collapseButton->setIcon(QIcon(":/icons/arrow_drop_down")); buildButton->setText("Stop"); QString urlTemplate = "wss://%1:%2%3/channel"; QString sUrl = urlTemplate.arg(authProfile.GetHost()).arg(authProfile.GetPort()).arg(authProfile.GetEndpoint()); QJsonArray listenersArray; for (const QString &listener : selectedListeners) listenersArray.append(listener); QJsonObject otpData; otpData["agent_name"] = agentName; otpData["listeners_name"] = listenersArray; QString otp; bool otpResult = HttpReqGetOTP("channel_agent_build", otpData, authProfile.GetURL(), authProfile.GetAccessToken(), &otp); if (!otpResult) { buildButton->setText("Build"); MessageError("Failed to generate OTP for build"); return; } buildThread = new QThread; buildWorker = new BuildWorker(otp, sUrl, configData); buildWorker->moveToThread(buildThread); connect(buildThread, &QThread::started, buildWorker, &BuildWorker::start); connect(buildWorker, &BuildWorker::finished, buildThread, &QThread::quit); connect(buildWorker, &BuildWorker::finished, buildWorker, &BuildWorker::deleteLater); connect(buildThread, &QThread::finished, buildThread, &QThread::deleteLater); connect(buildWorker, &BuildWorker::connected, this, &DialogAgent::onBuildConnected, Qt::QueuedConnection); connect(buildWorker, &BuildWorker::textMessageReceived, this, &DialogAgent::onBuildMessage, Qt::QueuedConnection); connect(buildWorker, &BuildWorker::finished, this, &DialogAgent::onBuildFinished, Qt::QueuedConnection); buildThread->start(); } void DialogAgent::onBuildConnected() { buildLogOutput->append("----- Build process start -----"); } void DialogAgent::onBuildMessage(const QString &msg) { if (msg.isEmpty()) return; QJsonParseError parseError; QJsonDocument doc = QJsonDocument::fromJson(msg.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError || !doc.isObject()) { buildLogOutput->append(msg.toHtmlEscaped()); return; } QJsonObject obj = doc.object(); int status = obj.value("status").toInt(0); QString message = obj.value("message").toString(); if (status != 4 && message.isEmpty()) return; QString htmlMsg = message.toHtmlEscaped(); htmlMsg.replace("\\n", "
"); switch (status) { case 0: // BUILD_LOG_NONE buildLogOutput->append(htmlMsg); break; case 1: // BUILD_LOG_INFO buildLogOutput->append(QString("[*] %1").arg(htmlMsg)); break; case 2: // BUILD_LOG_ERROR buildLogOutput->append(QString("[-] %1").arg(htmlMsg)); break; case 3: // BUILD_LOG_SUCCESS buildLogOutput->append(QString("[+] %1").arg(htmlMsg)); break; case 4: { // BUILD_LOG_SAVE_FILE QString filename = obj.value("filename").toString(); QString contentBase64 = obj.value("content").toString(); QByteArray content = QByteArray::fromBase64(contentBase64.toUtf8()); if (filename.isEmpty() || content.isEmpty()) return; QString baseDir = authProfile.GetProjectDir(); QString initialPath = QDir(baseDir).filePath(filename); QPointer safeThis = this; NonBlockingDialogs::getSaveFileName(this, "Save File", initialPath, "All Files (*.*)", [safeThis, content](const QString& filePath) { if (filePath.isEmpty()) return; QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { MessageError("Failed to open file for writing"); return; } file.write(content); file.close(); if (safeThis) { safeThis->buildLogOutput->append(QString("[+] File saved: %1").arg(filePath.toHtmlEscaped())); } }); return; } default: break; } QScrollBar *scrollBar = buildLogOutput->verticalScrollBar(); scrollBar->setValue(scrollBar->maximum()); } void DialogAgent::onBuildFinished() { buildLogOutput->append("----- Build process finished -----"); buildButton->setText("Build"); buildWorker = nullptr; buildThread = nullptr; } void DialogAgent::stopBuild() { if (!buildWorker || !buildThread) return; auto worker = buildWorker; auto thread = buildThread; buildWorker = nullptr; buildThread = nullptr; connect(worker, &BuildWorker::finished, this, [this, thread]() { if (thread->isRunning()) { thread->quit(); thread->wait(); } buildLogPanel->setVisible(false); buildButton->setText("Build"); }); QMetaObject::invokeMethod(worker, "stop", Qt::QueuedConnection); } void DialogAgent::onListenerSelectionChanged(const QListWidgetItem *item) { Q_UNUSED(item); updateListenerDisplay(); QString agentName = agentCombobox->currentText(); if (agentName.isEmpty() || !agentTypes.value(agentName, AgentTypeInfo{false, QStringList()}).multiListeners) return; QStringList selectedListeners; for (int i = 0; i < listenerListWidget->count(); ++i) { auto *listItem = listenerListWidget->item(i); if (listItem->checkState() == Qt::Checked) { selectedListeners.append(listItem->data(Qt::UserRole).toString()); } } regenerateAgentUI(agentName, selectedListeners); } void DialogAgent::onMoveListenerUp() { int currentRow = listenerListWidget->currentRow(); if (currentRow <= 0) return; listenerListWidget->blockSignals(true); QListWidgetItem *item = listenerListWidget->takeItem(currentRow); listenerListWidget->insertItem(currentRow - 1, item); listenerListWidget->setCurrentRow(currentRow - 1); listenerListWidget->blockSignals(false); updateListenerDisplay(); QString agentName = agentCombobox->currentText(); if (!agentName.isEmpty()) { QStringList selectedListeners; for (int i = 0; i < listenerListWidget->count(); ++i) { auto *listItem = listenerListWidget->item(i); if (listItem->checkState() == Qt::Checked) { selectedListeners.append(listItem->data(Qt::UserRole).toString()); } } regenerateAgentUI(agentName, selectedListeners); } } void DialogAgent::onMoveListenerDown() { int currentRow = listenerListWidget->currentRow(); if (currentRow < 0 || currentRow >= listenerListWidget->count() - 1) return; listenerListWidget->blockSignals(true); QListWidgetItem *item = listenerListWidget->takeItem(currentRow); listenerListWidget->insertItem(currentRow + 1, item); listenerListWidget->setCurrentRow(currentRow + 1); listenerListWidget->blockSignals(false); updateListenerDisplay(); QString agentName = agentCombobox->currentText(); if (!agentName.isEmpty()) { QStringList selectedListeners; for (int i = 0; i < listenerListWidget->count(); ++i) { auto *listItem = listenerListWidget->item(i); if (listItem->checkState() == Qt::Checked) { selectedListeners.append(listItem->data(Qt::UserRole).toString()); } } regenerateAgentUI(agentName, selectedListeners); } } void DialogAgent::regenerateAgentUI(const QString &agentName, const QStringList &selectedListeners) { if (!adaptixWidget || agentName.isEmpty()) return; auto engine = adaptixWidget->ScriptManager->AgentScriptEngine(agentName); if (engine == nullptr) return; QJSValue func = engine->globalObject().property("GenerateUI"); if (!func.isCallable()) return; QJSValue jsListeners = engine->newArray(selectedListeners.size()); for (int i = 0; i < selectedListeners.size(); ++i) { jsListeners.setProperty(i, selectedListeners[i]); } QJSValueList args; args << jsListeners; QJSValue result = func.call(args); if (result.isError()) { QString error = QStringLiteral("%1\n at line %2 in %3\n stack: %4") .arg(result.toString()) .arg(result.property("lineNumber").toInt()) .arg(agentName) .arg(result.property("stack").toString()); adaptixWidget->ScriptManager->consolePrintError(error); return; } if (!result.isObject()) return; QJSValue ui_container = result.property("ui_container"); QJSValue ui_panel = result.property("ui_panel"); QJSValue ui_height = result.property("ui_height"); QJSValue ui_width = result.property("ui_width"); if (ui_container.isUndefined() || !ui_container.isObject() || ui_panel.isUndefined() || !ui_panel.isQObject()) return; QObject* objPanel = ui_panel.toQObject(); auto* formElement = dynamic_cast(objPanel); if (!formElement) return; QObject* objContainer = ui_container.toQObject(); auto* container = dynamic_cast(objContainer); if (!container) return; int h = 550; if (ui_height.isNumber() && ui_height.toInt() > 0) h = ui_height.toInt(); int w = 550; if (ui_width.isNumber() && ui_width.toInt() > 0) w = ui_width.toInt(); if (ax_uis.contains(agentName)) { auto &oldUi = ax_uis[agentName]; if (oldUi.widget) { configStackWidget->removeWidget(oldUi.widget); oldUi.widget->deleteLater(); } } ax_uis[agentName] = { container, formElement->widget(), h, w }; configStackWidget->addWidget(formElement->widget()); configStackWidget->setCurrentWidget(formElement->widget()); this->resize(w, h); } void DialogAgent::showListenerPopup() { QPoint pos = listenerSelectBtn->mapToGlobal(QPoint(0, listenerSelectBtn->height())); listenerPopupDialog->move(pos); listenerPopupDialog->show(); listenerPopupDialog->raise(); listenerPopupDialog->activateWindow(); } void DialogAgent::updateListenerDisplay() { QStringList selectedNames; for (int i = 0; i < listenerListWidget->count(); ++i) { auto *item = listenerListWidget->item(i); if (item->checkState() == Qt::Checked) { selectedNames.append(item->text()); } } listenerDisplayEdit->setText(selectedNames.join(", ")); }