208 lines
6.0 KiB
C++
208 lines
6.0 KiB
C++
#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<void(const std::string)> toLog)
|
|
: toLog(std::move(toLog))
|
|
{
|
|
// Configuration
|
|
this->configuration = std::make_shared<file::config::Config>();
|
|
this->toLog("Configuration loaded");
|
|
|
|
// Database
|
|
#ifdef XP
|
|
this->loadDatabase(simVersion);
|
|
#endif
|
|
|
|
// WebSocket
|
|
this->connector =
|
|
std::make_unique<websocket::Websocket>(WEBSOCKET_ADDRESS,
|
|
this->configuration->getUser(),
|
|
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<std::mutex> lock(this->mutex);
|
|
|
|
std::memcpy(&this->toSend, &data, sizeof(websocket::data));
|
|
}
|
|
|
|
void Recorder::handleMessages()
|
|
{
|
|
const std::lock_guard<std::mutex> lock(this->mutex);
|
|
|
|
if (!this->messageQueue().empty()) {
|
|
auto op = std::move(this->messageQueue().front());
|
|
this->messageQueue().pop();
|
|
op();
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<file::config::Config> 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<file::simdata::SimDatabase>(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<file::simdata::SimDatabase>(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<std::mutex> 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<std::mutex> lock(this->mutex);
|
|
|
|
std::memcpy(©, &this->toSend, sizeof(websocket::data));
|
|
}
|
|
|
|
file::recording::RecordingEntry currentPath(
|
|
segment,
|
|
static_cast<std::uint16_t>(copy.alt),
|
|
static_cast<std::uint16_t>(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
|