2021-08-22 20:46:52 +01:00
|
|
|
#include "Application.hpp"
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <iostream>
|
2022-07-24 12:17:44 +01:00
|
|
|
#include <QFile>
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "src/Logger/Logger.hpp"
|
2021-05-30 19:05:18 +01:00
|
|
|
#include "src/Helpers/Paths.hpp"
|
2022-06-22 22:24:27 +01:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
#include "src/Exceptions/InvalidConfig.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
namespace Bloom
|
|
|
|
|
{
|
|
|
|
|
using namespace Exceptions;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-06-22 22:24:27 +01:00
|
|
|
Application::Application(std::vector<std::string>&& arguments)
|
|
|
|
|
: arguments(std::move(arguments))
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
int Application::run() {
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
this->setName("Bloom");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-06-22 22:24:27 +01:00
|
|
|
if (this->arguments.size() > 1) {
|
|
|
|
|
auto& firstArg = this->arguments.at(1);
|
2022-05-28 23:11:00 +01:00
|
|
|
const auto commandHandlersByCommandName = this->getCommandHandlersByCommandName();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-05-28 23:11:00 +01:00
|
|
|
if (commandHandlersByCommandName.contains(firstArg)) {
|
2022-02-05 15:32:08 +00:00
|
|
|
// User has passed an argument that maps to a command callback - invoke the callback and shutdown
|
2022-05-28 23:11:00 +01:00
|
|
|
const auto returnValue = commandHandlersByCommandName.at(firstArg)();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->shutdown();
|
|
|
|
|
return returnValue;
|
|
|
|
|
}
|
2022-01-02 20:45:14 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// If the first argument didn't map to a command, we assume it's an environment name
|
2022-05-14 22:43:35 +01:00
|
|
|
this->selectedEnvironmentName = std::move(firstArg);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-04-24 16:22:04 +01:00
|
|
|
#ifdef BLOOM_DEBUG_BUILD
|
2022-06-22 22:24:27 +01:00
|
|
|
Logger::warning("This is a debug build - some functions may not work as expected");
|
2021-04-24 16:22:04 +01:00
|
|
|
#endif
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->startup();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->insightConfig->insightEnabled) {
|
|
|
|
|
this->insight = std::make_unique<Insight>(
|
2022-02-09 17:47:05 +00:00
|
|
|
*(this->applicationEventListener),
|
2022-02-05 15:32:08 +00:00
|
|
|
this->projectConfig.value(),
|
|
|
|
|
this->environmentConfig.value(),
|
|
|
|
|
this->insightConfig.value(),
|
|
|
|
|
this->projectSettings.value().insightSettings
|
|
|
|
|
);
|
2021-09-24 23:23:22 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* Before letting Insight occupy the main thread, process any pending events that accumulated
|
|
|
|
|
* during startup.
|
|
|
|
|
*/
|
|
|
|
|
this->applicationEventListener->dispatchCurrentEvents();
|
|
|
|
|
|
|
|
|
|
if (Thread::getThreadState() == ThreadState::READY) {
|
|
|
|
|
this->insight->run();
|
|
|
|
|
Logger::debug("Insight closed");
|
|
|
|
|
}
|
2021-09-24 23:23:22 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->shutdown();
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Main event loop
|
|
|
|
|
while (Thread::getThreadState() == ThreadState::READY) {
|
|
|
|
|
this->applicationEventListener->waitAndDispatch();
|
2021-09-24 23:23:22 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} catch (const InvalidConfig& exception) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::error(exception.getMessage());
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} catch (const Exception& exception) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::error(exception.getMessage());
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->shutdown();
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
bool Application::isRunningAsRoot() {
|
|
|
|
|
return geteuid() == 0;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-28 23:11:00 +01:00
|
|
|
std::map<std::string, std::function<int()>> Application::getCommandHandlersByCommandName() {
|
2022-05-06 19:34:12 +01:00
|
|
|
return std::map<std::string, std::function<int()>> {
|
|
|
|
|
{
|
|
|
|
|
"--help",
|
|
|
|
|
std::bind(&Application::presentHelpText, this)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"-h",
|
|
|
|
|
std::bind(&Application::presentHelpText, this)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"--version",
|
|
|
|
|
std::bind(&Application::presentVersionText, this)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"-v",
|
|
|
|
|
std::bind(&Application::presentVersionText, this)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"--version-machine",
|
|
|
|
|
std::bind(&Application::presentVersionMachineText, this)
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"init",
|
|
|
|
|
std::bind(&Application::initProject, this)
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::startup() {
|
2022-02-09 17:49:25 +00:00
|
|
|
auto& applicationEventListener = this->applicationEventListener;
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::registerListener(applicationEventListener);
|
2022-02-05 15:32:08 +00:00
|
|
|
applicationEventListener->registerCallbackForEventType<Events::ShutdownApplication>(
|
|
|
|
|
std::bind(&Application::onShutdownApplicationRequest, this, std::placeholders::_1)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->loadProjectSettings();
|
|
|
|
|
this->loadProjectConfiguration();
|
|
|
|
|
Logger::configure(this->projectConfig.value());
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Bloom version: " + Application::VERSION.toString());
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->blockAllSignalsOnCurrentThread();
|
|
|
|
|
this->startSignalHandler();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Selected environment: \"" + this->selectedEnvironmentName + "\"");
|
|
|
|
|
Logger::debug("Number of environments extracted from config: "
|
2022-02-06 13:45:35 +00:00
|
|
|
+ std::to_string(this->projectConfig->environments.size()));
|
2022-01-22 16:51:21 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
applicationEventListener->registerCallbackForEventType<Events::TargetControllerThreadStateChanged>(
|
|
|
|
|
std::bind(&Application::onTargetControllerThreadStateChanged, this, std::placeholders::_1)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
applicationEventListener->registerCallbackForEventType<Events::DebugServerThreadStateChanged>(
|
|
|
|
|
std::bind(&Application::onDebugServerThreadStateChanged, this, std::placeholders::_1)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-09 17:50:32 +00:00
|
|
|
applicationEventListener->registerCallbackForEventType<Events::DebugSessionFinished>(
|
|
|
|
|
std::bind(&Application::onDebugSessionFinished, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->startTargetController();
|
|
|
|
|
this->startDebugServer();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Thread::setThreadState(ThreadState::READY);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::shutdown() {
|
2022-05-14 22:43:35 +01:00
|
|
|
const auto appState = Thread::getThreadState();
|
2022-02-05 15:32:08 +00:00
|
|
|
if (appState == ThreadState::STOPPED || appState == ThreadState::SHUTDOWN_INITIATED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Thread::setThreadState(ThreadState::SHUTDOWN_INITIATED);
|
|
|
|
|
Logger::info("Shutting down Bloom");
|
|
|
|
|
|
2022-02-09 17:47:05 +00:00
|
|
|
if (this->insight != nullptr) {
|
|
|
|
|
this->insight->shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->stopDebugServer();
|
|
|
|
|
this->stopTargetController();
|
|
|
|
|
this->stopSignalHandler();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->saveProjectSettings();
|
|
|
|
|
Thread::setThreadState(ThreadState::STOPPED);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::loadProjectSettings() {
|
|
|
|
|
const auto projectSettingsPath = Paths::projectSettingsPath();
|
|
|
|
|
auto jsonSettingsFile = QFile(QString::fromStdString(projectSettingsPath));
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (jsonSettingsFile.exists()) {
|
|
|
|
|
try {
|
|
|
|
|
if (!jsonSettingsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
|
throw Exception("Failed to open settings file.");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-09 17:49:25 +00:00
|
|
|
this->projectSettings = ProjectSettings(
|
|
|
|
|
QJsonDocument::fromJson(jsonSettingsFile.readAll()).object()
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
jsonSettingsFile.close();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return;
|
2022-01-02 20:44:39 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} catch (const std::exception& exception) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::error(
|
|
|
|
|
"Failed to load project settings from " + projectSettingsPath + " - " + exception.what()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->projectSettings = ProjectSettings();
|
|
|
|
|
}
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::saveProjectSettings() {
|
|
|
|
|
if (!this->projectSettings.has_value()) {
|
2022-01-02 20:44:39 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
const auto projectSettingsPath = Paths::projectSettingsPath();
|
|
|
|
|
auto jsonSettingsFile = QFile(QString::fromStdString(projectSettingsPath));
|
2022-01-02 20:44:39 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Saving project settings to " + projectSettingsPath);
|
2022-01-22 16:45:42 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
QDir().mkpath(QString::fromStdString(Paths::projectSettingsDirPath()));
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
const auto jsonDocument = QJsonDocument(this->projectSettings->toJson());
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!jsonSettingsFile.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
|
|
|
|
|
throw Exception(
|
|
|
|
|
"failed to open/create settings file (" + projectSettingsPath + "). Check file permissions."
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
jsonSettingsFile.write(jsonDocument.toJson());
|
|
|
|
|
jsonSettingsFile.close();
|
2022-01-22 16:14:29 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} catch (const Exception& exception) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::error(
|
|
|
|
|
"Failed to save project settings - " + exception.getMessage()
|
2022-01-22 16:14:29 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::loadProjectConfiguration() {
|
2022-07-23 15:37:22 +01:00
|
|
|
auto configFile = QFile(QString::fromStdString(Paths::projectConfigPath()));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-07-23 15:37:22 +01:00
|
|
|
if (!configFile.exists()) {
|
2022-07-24 12:17:44 +01:00
|
|
|
// Try looking for the old bloom.json config file
|
|
|
|
|
configFile.setFileName(QString::fromStdString(Paths::projectDirPath()) + "/bloom.json");
|
|
|
|
|
|
|
|
|
|
if (configFile.exists()) {
|
|
|
|
|
Logger::warning(
|
|
|
|
|
"The recommended project configuration file format changed from JSON to YAML in Bloom v0.11.0."
|
|
|
|
|
" Bloom could not find a bloom.yaml configuration file, but did find bloom.json. Please convert"
|
|
|
|
|
" bloom.json to YAML format and rename to \"bloom.yaml\". There are numerous online JSON -> YAML"
|
|
|
|
|
" converters. For now, bloom.json will be used in the absence of bloom.yaml."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
throw InvalidConfig(
|
|
|
|
|
"Bloom configuration file (bloom.yaml) not found. Working directory: " + Paths::projectDirPath()
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-07-23 15:37:22 +01:00
|
|
|
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
2022-07-24 12:17:44 +01:00
|
|
|
throw InvalidConfig(
|
|
|
|
|
"Failed to open Bloom configuration file. Working directory: " + Paths::projectDirPath()
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-07-23 15:37:22 +01:00
|
|
|
const auto configNode = YAML::Load(configFile.readAll().toStdString());
|
|
|
|
|
configFile.close();
|
2021-12-31 19:44:20 +00:00
|
|
|
|
2022-07-23 15:37:22 +01:00
|
|
|
this->projectConfig = ProjectConfig(configNode);
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Validate the selected environment
|
|
|
|
|
if (!this->projectConfig->environments.contains(this->selectedEnvironmentName)) {
|
|
|
|
|
throw InvalidConfig(
|
|
|
|
|
"Environment (\"" + this->selectedEnvironmentName + "\") not found in configuration."
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->environmentConfig = this->projectConfig->environments.at(this->selectedEnvironmentName);
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->environmentConfig->insightConfig.has_value()) {
|
|
|
|
|
this->insightConfig = this->environmentConfig->insightConfig.value();
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} else if (this->projectConfig->insightConfig.has_value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->insightConfig = this->projectConfig->insightConfig.value();
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} else {
|
2022-02-05 15:32:08 +00:00
|
|
|
throw InvalidConfig("Insight configuration missing.");
|
|
|
|
|
}
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->environmentConfig->debugServerConfig.has_value()) {
|
|
|
|
|
this->debugServerConfig = this->environmentConfig->debugServerConfig.value();
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} else if (this->projectConfig->debugServerConfig.has_value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->debugServerConfig = this->projectConfig->debugServerConfig.value();
|
2022-01-02 20:13:18 +00:00
|
|
|
|
2022-02-06 13:45:35 +00:00
|
|
|
} else {
|
2022-02-05 15:32:08 +00:00
|
|
|
throw InvalidConfig("Debug server configuration missing.");
|
|
|
|
|
}
|
2022-01-02 20:13:18 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
int Application::presentHelpText() {
|
|
|
|
|
/*
|
|
|
|
|
* Silence all logging here, as we're just to display the help text and then exit the application. Any
|
|
|
|
|
* further logging will just be noise.
|
|
|
|
|
*/
|
|
|
|
|
Logger::silence();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-07-23 16:13:08 +01:00
|
|
|
// The file help.txt is included in Bloom's binary, as a resource. See the root-level CMakeLists.txt for more.
|
2022-02-06 13:45:35 +00:00
|
|
|
auto helpFile = QFile(QString::fromStdString(Paths::compiledResourcesPath() + "/resources/help.txt"));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!helpFile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
// This should never happen - if it does, something has gone very wrong
|
|
|
|
|
throw Exception(
|
|
|
|
|
"Failed to open help file - please report this issue at " + Paths::homeDomainName()
|
|
|
|
|
+ "/report-issue"
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
std::cout << "Bloom v" << Application::VERSION.toString() << "\n";
|
|
|
|
|
std::cout << QTextStream(&helpFile).readAll().toUtf8().constData() << "\n";
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
int Application::presentVersionText() {
|
|
|
|
|
Logger::silence();
|
|
|
|
|
|
|
|
|
|
std::cout << "Bloom v" << Application::VERSION.toString() << "\n";
|
2021-04-24 16:22:04 +01:00
|
|
|
|
|
|
|
|
#ifdef BLOOM_DEBUG_BUILD
|
2022-02-05 15:32:08 +00:00
|
|
|
std::cout << "DEBUG BUILD - Compilation timestamp: " << __DATE__ << " " << __TIME__ << "\n";
|
2021-04-24 16:22:04 +01:00
|
|
|
#endif
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
std::cout << Paths::homeDomainName() + "/\n";
|
|
|
|
|
std::cout << "Nav Mohammed\n";
|
|
|
|
|
return EXIT_SUCCESS;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-06 19:30:43 +01:00
|
|
|
int Application::presentVersionMachineText() {
|
|
|
|
|
Logger::silence();
|
|
|
|
|
|
|
|
|
|
std::cout << QJsonDocument(QJsonObject({
|
|
|
|
|
{"version", QString::fromStdString(Application::VERSION.toString())},
|
|
|
|
|
{"components", QJsonObject({
|
|
|
|
|
{"major", Application::VERSION.getMajor()},
|
|
|
|
|
{"minor", Application::VERSION.getMinor()},
|
|
|
|
|
{"patch", Application::VERSION.getPatch()},
|
|
|
|
|
})},
|
|
|
|
|
})).toJson().toStdString();
|
|
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
int Application::initProject() {
|
2022-06-22 22:24:27 +01:00
|
|
|
auto configFile = QFile(QString::fromStdString(Paths::projectConfigPath()));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (configFile.exists()) {
|
2022-07-23 15:37:22 +01:00
|
|
|
throw Exception("Bloom configuration file (bloom.yaml) already exists in working directory.");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
2022-07-23 16:13:08 +01:00
|
|
|
* The file bloom.template.yaml is just a template Bloom config file that is included in Bloom's binary, as a
|
|
|
|
|
* resource. See the root-level CMakeLists.txt for more.
|
2022-02-05 15:32:08 +00:00
|
|
|
*
|
|
|
|
|
* We simply copy the template file into the user's working directory.
|
|
|
|
|
*/
|
|
|
|
|
auto templateConfigFile = QFile(
|
2022-07-23 15:42:16 +01:00
|
|
|
QString::fromStdString(Paths::compiledResourcesPath()+ "/resources/bloom.template.yaml")
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!templateConfigFile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
throw Exception(
|
|
|
|
|
"Failed to open template configuration file - please report this issue at "
|
|
|
|
|
+ Paths::homeDomainName() + "/report-issue"
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!configFile.open(QIODevice::ReadWrite)) {
|
2022-07-23 15:37:22 +01:00
|
|
|
throw Exception("Failed to create Bloom configuration file (bloom.yaml)");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
configFile.write(templateConfigFile.readAll());
|
2022-01-09 14:25:52 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
configFile.close();
|
|
|
|
|
templateConfigFile.close();
|
2022-01-09 14:25:52 +00:00
|
|
|
|
2022-07-23 15:37:22 +01:00
|
|
|
Logger::info("Bloom configuration file (bloom.yaml) created in working directory.");
|
2022-02-05 15:32:08 +00:00
|
|
|
return EXIT_SUCCESS;
|
2022-01-09 14:25:52 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::startSignalHandler() {
|
|
|
|
|
this->signalHandlerThread = std::thread(&SignalHandler::run, std::ref(this->signalHandler));
|
2022-01-09 14:25:52 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::stopSignalHandler() {
|
2022-05-23 23:50:10 +01:00
|
|
|
const auto shThreadState = this->signalHandler.getThreadState();
|
|
|
|
|
|
|
|
|
|
if (shThreadState != ThreadState::STOPPED && shThreadState != ThreadState::UNINITIALISED) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->signalHandler.triggerShutdown();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* Send meaningless signal to the SignalHandler thread to have it shutdown. The signal will pull it out of
|
|
|
|
|
* a blocking state and allow it to action the shutdown. See SignalHandler::run() for more.
|
|
|
|
|
*/
|
|
|
|
|
pthread_kill(this->signalHandlerThread.native_handle(), SIGUSR1);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->signalHandlerThread.joinable()) {
|
|
|
|
|
Logger::debug("Joining SignalHandler thread");
|
|
|
|
|
this->signalHandlerThread.join();
|
|
|
|
|
Logger::debug("SignalHandler thread joined");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::startTargetController() {
|
2022-04-09 15:57:24 +01:00
|
|
|
this->targetController = std::make_unique<TargetController::TargetControllerComponent>(
|
2022-02-05 15:32:08 +00:00
|
|
|
this->projectConfig.value(),
|
|
|
|
|
this->environmentConfig.value()
|
|
|
|
|
);
|
2022-01-02 21:30:24 +00:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetControllerThread = std::thread(
|
2022-04-09 15:57:24 +01:00
|
|
|
&TargetController::TargetControllerComponent::run,
|
2022-02-05 15:32:08 +00:00
|
|
|
this->targetController.get()
|
2021-04-04 21:04:12 +01:00
|
|
|
);
|
|
|
|
|
|
2022-07-09 14:09:05 +01:00
|
|
|
const auto tcStateChangeEvent = this->applicationEventListener->waitForEvent<
|
|
|
|
|
Events::TargetControllerThreadStateChanged
|
|
|
|
|
>();
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
if (!tcStateChangeEvent.has_value() || tcStateChangeEvent->get()->getState() != ThreadState::READY) {
|
2022-08-27 17:56:55 +01:00
|
|
|
throw Exception("TargetController failed to start up");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::stopTargetController() {
|
|
|
|
|
if (this->targetController == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 14:09:05 +01:00
|
|
|
const auto targetControllerState = this->targetController->getThreadState();
|
2022-02-05 15:32:08 +00:00
|
|
|
if (targetControllerState == ThreadState::STARTING || targetControllerState == ThreadState::READY) {
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(std::make_shared<Events::ShutdownTargetController>());
|
2022-02-05 15:32:08 +00:00
|
|
|
this->applicationEventListener->waitForEvent<Events::TargetControllerThreadStateChanged>(
|
|
|
|
|
std::chrono::milliseconds(10000)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->targetControllerThread.joinable()) {
|
|
|
|
|
Logger::debug("Joining TargetController thread");
|
|
|
|
|
this->targetControllerThread.join();
|
|
|
|
|
Logger::debug("TargetController thread joined");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::startDebugServer() {
|
2022-03-31 16:05:39 +01:00
|
|
|
this->debugServer = std::make_unique<DebugServer::DebugServerComponent>(
|
2022-03-27 18:32:13 +01:00
|
|
|
this->debugServerConfig.value()
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->debugServerThread = std::thread(
|
2022-03-31 16:05:39 +01:00
|
|
|
&DebugServer::DebugServerComponent::run,
|
2022-02-05 15:32:08 +00:00
|
|
|
this->debugServer.get()
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-07-09 14:09:05 +01:00
|
|
|
const auto dsStateChangeEvent = this->applicationEventListener->waitForEvent<
|
|
|
|
|
Events::DebugServerThreadStateChanged
|
|
|
|
|
>();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!dsStateChangeEvent.has_value() || dsStateChangeEvent->get()->getState() != ThreadState::READY) {
|
2022-08-27 17:56:55 +01:00
|
|
|
throw Exception("DebugServer failed to start up");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::stopDebugServer() {
|
|
|
|
|
if (this->debugServer == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 14:09:05 +01:00
|
|
|
const auto debugServerState = this->debugServer->getThreadState();
|
2022-02-05 15:32:08 +00:00
|
|
|
if (debugServerState == ThreadState::STARTING || debugServerState == ThreadState::READY) {
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(std::make_shared<Events::ShutdownDebugServer>());
|
2022-02-05 15:32:08 +00:00
|
|
|
this->applicationEventListener->waitForEvent<Events::DebugServerThreadStateChanged>(
|
|
|
|
|
std::chrono::milliseconds(5000)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->debugServerThread.joinable()) {
|
|
|
|
|
Logger::debug("Joining DebugServer thread");
|
|
|
|
|
this->debugServerThread.join();
|
|
|
|
|
Logger::debug("DebugServer thread joined");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-09 17:49:25 +00:00
|
|
|
void Application::onShutdownApplicationRequest(const Events::ShutdownApplication&) {
|
|
|
|
|
Logger::debug("ShutdownApplication event received.");
|
|
|
|
|
this->shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::onTargetControllerThreadStateChanged(const Events::TargetControllerThreadStateChanged& event) {
|
|
|
|
|
if (event.getState() == ThreadState::STOPPED || event.getState() == ThreadState::SHUTDOWN_INITIATED) {
|
|
|
|
|
// TargetController has unexpectedly shutdown - it must have encountered a fatal error.
|
|
|
|
|
this->shutdown();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void Application::onDebugServerThreadStateChanged(const Events::DebugServerThreadStateChanged& event) {
|
|
|
|
|
if (event.getState() == ThreadState::STOPPED || event.getState() == ThreadState::SHUTDOWN_INITIATED) {
|
|
|
|
|
// DebugServer has unexpectedly shutdown - it must have encountered a fatal error.
|
|
|
|
|
this->shutdown();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2022-02-09 17:50:32 +00:00
|
|
|
|
|
|
|
|
void Application::onDebugSessionFinished(const Events::DebugSessionFinished& event) {
|
|
|
|
|
if (this->environmentConfig->shutdownPostDebugSession) {
|
|
|
|
|
this->shutdown();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|