#include "include/recorder.h" namespace germanairlinesva { namespace gaconnector { namespace recorder { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" Recorder::Recorder(int simVersion, std::function toLog) : toLog(std::move(toLog)) { // Configuration this->configuration = std::make_shared(); this->toLog("Configuration loaded"); // Database #ifdef XP this->loadDatabase(simVersion); #endif // WebSocket this->connector = std::make_unique(WEBSOCKET_ADDRESS, this->configuration->getUser(), this->configuration->getToken(), this->toLog); this->toLog("WebSocket started"); // For Testing #ifdef XP this->test(); #endif // Thread for sending data to websocket this->serverThread = std::thread(&Recorder::serverWorker, this); this->recordingThread = std::thread(&Recorder::recordingWorker, this); this->toLog("Workers started"); } #pragma clang diagnostic pop Recorder::~Recorder() { this->wantsExit.store(true); this->serverThread.join(); this->recordingThread.join(); } void Recorder::setData(websocket::data &data) { const std::lock_guard lock(this->mutex); std::memcpy(&this->toSend, &data, sizeof(websocket::data)); } void Recorder::handleMessages() { const std::lock_guard lock(this->mutex); if (!this->messageQueue().empty()) { auto op = std::move(this->messageQueue().front()); this->messageQueue().pop(); op(); } } std::shared_ptr Recorder::getConfiguration() const { return this->configuration; } void Recorder::loadDatabase(int simVersion) { #ifdef XP char hash[2 * MD5LEN + 1] = ""; if (utilities::generateMD5(XPLANE_CUSTOM_SCENERY, hash, this->toLog) == 0) { this->database = std::make_unique(simVersion, hash, this->configuration, this->toLog); } #endif #if defined(IBM) && not defined(XP) if (simVersion == MSFS_VERSION) { this->simSupported = strcmp(BIT, "64") == 0; return; } this->toLog("Loading database for " + SimConnect::resolveVersion(simVersion)); PWSTR folder; HRESULT result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &folder); if (SUCCEEDED(result)) { size_t origsize = wcslen(folder) + 1; size_t convertedChars = 0; char *nstring = new char[origsize * 2]; wcstombs_s(&convertedChars, nstring, origsize * 2, folder, _TRUNCATE); std::string path(nstring); path.append(SimConnect::resolveScenery(simVersion)); this->toLog("Scenery path: " + path); delete[] nstring; CoTaskMemFree(folder); char hash[2 * MD5LEN + 1] = ""; if (utilities::generateMD5(path.c_str(), hash, toLog) == 0) { this->database = std::make_unique(simVersion, hash, this->configuration, this->toLog); } this->test(); } #endif // Only here can we be sure to have a supported sim this->simSupported = true; } bool Recorder::getSupportedState() const { return this->simSupported; } void Recorder::serverWorker() { utilities::setThreadName("GAServerWorker"); while (!wantsExit) { struct websocket::data copy; { const std::lock_guard lock(this->mutex); std::memcpy(©, &this->toSend, sizeof(websocket::data)); } this->connector->sendData(copy); std::this_thread::sleep_for(std::chrono::milliseconds(250)); } this->toLog("Server thread stopped"); } void Recorder::recordingWorker() { utilities::setThreadName("GARecordingWorker"); file::recording::Recording path; file::recording::RecordingEntry lastPath; std::uint32_t segment = 0; while (!wantsExit) { struct websocket::data copy; { const std::lock_guard lock(this->mutex); std::memcpy(©, &this->toSend, sizeof(websocket::data)); } file::recording::RecordingEntry currentPath( segment, static_cast(copy.alt), static_cast(copy.gs), {copy.lat, copy.lon}); if (strcmp(copy.path, "") != 0 && !copy.pause && lastPath != currentPath) { path.addEntry(currentPath); lastPath = currentPath; } segment++; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } path.toFile("flight.rec"); this->toLog("Recording thread stopped"); } void Recorder::test() const { #ifndef MSFS this->toLog("Readback test of sim database using EDDF"); auto ap = (*this->database)["EDDF"]; for (const auto &it : ap.first) { this->toLog(" " + it.to_string()); } for (const auto &it : ap.second) { this->toLog(" " + it.to_string()); } this->toLog("Readback test of sim database using XXXX"); auto ap2 = (*database)["XXXX"]; ap2.first.size() == 0 ? this->toLog(" SUCCESS") : this->toLog(" ERROR"); #endif } } // namespace recorder } // namespace gaconnector } // namespace germanairlinesva