Branch data Line data Source code
1 : : #include "RestApiProvider.h"
2 : : #include "Logger.h"
3 : : #include <iostream>
4 : : #include <regex>
5 : :
6 : : #ifdef _WIN32
7 : : #include <windows.h>
8 : : #include <wininet.h>
9 : : #pragma comment(lib, "wininet.lib")
10 : : #endif
11 : :
12 : 617 : RestApiProvider& RestApiProvider::Get() {
13 [ + + + - ]: 617 : static RestApiProvider instance;
14 : 617 : return instance;
15 : : }
16 : :
17 : 1 : RestApiProvider::~RestApiProvider() {
18 : 1 : std::lock_guard<std::mutex> lock(m_threadMutex);
19 [ + - ]: 1 : if (m_requestThread.joinable()) {
20 : 1 : m_requestThread.join();
21 : : }
22 : 1 : }
23 : :
24 : 4 : void RestApiProvider::RequestSteeringRange(int port) {
25 [ - + ]: 4 : if (m_isRequesting.load()) return;
26 : :
27 [ + - ]: 4 : std::lock_guard<std::mutex> lock(m_threadMutex);
28 [ + + ]: 4 : if (m_requestThread.joinable()) {
29 [ + - ]: 3 : m_requestThread.join();
30 : : }
31 : :
32 : 4 : m_isRequesting = true;
33 [ + - ]: 8 : m_requestThread = std::thread([this, port]() {
34 : : try {
35 [ + - ]: 4 : this->PerformRequest(port);
36 : 0 : } catch (...) {
37 [ - - - - ]: 0 : Logger::Get().LogFile("RestApiProvider: Unexpected exception in request thread");
38 : 0 : }
39 : 4 : this->m_isRequesting = false;
40 : 8 : });
41 : 4 : }
42 : :
43 : 488 : float RestApiProvider::GetFallbackRangeDeg() const {
44 : 488 : return m_fallbackRangeDeg.load();
45 : : }
46 : :
47 : 0 : bool RestApiProvider::IsRequesting() const {
48 : 0 : return m_isRequesting.load();
49 : : }
50 : :
51 : 4 : void RestApiProvider::PerformRequest(int port) {
52 : 4 : std::string response;
53 : 4 : bool success = false;
54 : :
55 : : #ifdef _WIN32
56 : : HINTERNET hInternet = InternetOpenA("lmuFFB", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
57 : : if (hInternet) {
58 : : std::string url = "http://localhost:" + std::to_string(port) + "/rest/garage/getPlayerGarageData";
59 : : HINTERNET hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0);
60 : : if (hConnect) {
61 : : char buffer[4096];
62 : : DWORD bytesRead;
63 : : while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
64 : : response.append(buffer, bytesRead);
65 : : }
66 : : InternetCloseHandle(hConnect);
67 : : success = true;
68 : : } else {
69 : : Logger::Get().LogFile("RestApiProvider: Failed to open URL (Port %d)", port);
70 : : }
71 : : InternetCloseHandle(hInternet);
72 : : } else {
73 : : Logger::Get().LogFile("RestApiProvider: Failed to initialize WinINet");
74 : : }
75 : : #else
76 [ + - + - ]: 4 : Logger::Get().LogFile("RestApiProvider: Mock request on Linux (Port %d)", port);
77 : : #endif
78 : :
79 [ - + - - : 4 : if (success && !response.empty()) {
- + ]
80 [ # # ]: 0 : float range = ParseSteeringLock(response);
81 [ # # ]: 0 : if (range > 0.0f) {
82 : 0 : m_fallbackRangeDeg = range;
83 [ # # # # ]: 0 : Logger::Get().LogFile("RestApiProvider: Retrieved steering range: %.1f deg", range);
84 : : } else {
85 [ # # # # ]: 0 : Logger::Get().LogFile("RestApiProvider: Could not parse VM_STEER_LOCK from response");
86 : : }
87 : : }
88 : 4 : }
89 : :
90 : 5 : float RestApiProvider::ParseSteeringLock(const std::string& json) {
91 : : // Look for "VM_STEER_LOCK" and then "stringValue"
92 : : // Example: "VM_STEER_LOCK" : { ... "stringValue" : "540 deg" ... }
93 : :
94 : : // 1. Find the property
95 : 5 : size_t propPos = json.find("\"VM_STEER_LOCK\"");
96 [ + + ]: 5 : if (propPos == std::string::npos) return 0.0f;
97 : :
98 : : // 2. Find "stringValue" within the next few hundred characters
99 : 3 : size_t searchLimit = 512;
100 [ + - ]: 3 : std::string sub = json.substr(propPos, searchLimit);
101 : 3 : size_t valPos = sub.find("\"stringValue\"");
102 [ - + ]: 3 : if (valPos == std::string::npos) return 0.0f;
103 : :
104 : : // 3. Extract the value string
105 : 3 : size_t colonPos = sub.find(':', valPos);
106 [ - + ]: 3 : if (colonPos == std::string::npos) return 0.0f;
107 : :
108 : 3 : size_t startQuote = sub.find('\"', colonPos);
109 [ - + ]: 3 : if (startQuote == std::string::npos) return 0.0f;
110 : :
111 : 3 : size_t endQuote = sub.find('\"', startQuote + 1);
112 [ - + ]: 3 : if (endQuote == std::string::npos) return 0.0f;
113 : :
114 [ + - ]: 3 : std::string valueStr = sub.substr(startQuote + 1, endQuote - startQuote - 1);
115 : :
116 : : // 4. Extract numeric value using regex
117 [ + - ]: 3 : std::regex re(R"(\d*\.?\d+)");
118 : 3 : std::smatch match;
119 [ + - + - ]: 3 : if (std::regex_search(valueStr, match, re)) {
120 : : try {
121 [ + - + - ]: 3 : return std::stof(match.str());
122 : 0 : } catch (...) {
123 : 0 : return 0.0f;
124 [ - - ]: 0 : }
125 : : }
126 : :
127 : 0 : return 0.0f;
128 : 3 : }
|