24#include <nlohmann/json.hpp>
39 const std::lock_guard<std::mutex> lock(m_threadMutex);
42 LOG_INFO(
"ISS Tracker: Already tracking, skipping");
50 const std::lock_guard<std::mutex> callbackLock(m_callbackMutex);
51 m_callback = callback;
56 m_trackingThread = std::jthread([
this](
const std::stop_token& stopToken) { TrackingLoop(stopToken); });
58 LOG_INFO(
"ISS Tracker: Started tracking");
62 const std::lock_guard<std::mutex> lock(m_threadMutex);
69 m_trackingThread.request_stop();
72 LOG_INFO(
"ISS Tracker: Stopped tracking");
80 const std::lock_guard<std::mutex> lock(m_dataMutex);
81 return m_currentPosition;
85 const std::lock_guard<std::mutex> lock(m_dataMutex);
89 latitudes.reserve(m_positionHistory.size());
90 longitudes.reserve(m_positionHistory.size());
92 for (
const auto& pos : m_positionHistory) {
94 latitudes.push_back(pos.latitude);
95 longitudes.push_back(pos.longitude);
101 return FetchPositionImpl(std::stop_token{});
104void ISSTracker::TrackingLoop(
const std::stop_token& stopToken) {
105 while (!stopToken.stop_requested()) {
107 const ISSPosition position = FetchPositionImpl(stopToken);
110 if (stopToken.stop_requested()) {
111 LOG_INFO(
"ISS Tracker: Stop requested, discarding fetched data");
115 if (position.
valid) {
118 const std::lock_guard<std::mutex> lock(m_dataMutex);
119 m_currentPosition = position;
120 AddToHistory(position);
124 std::function<void(
const ISSPosition&)> callback;
126 const std::lock_guard<std::mutex> lock(m_callbackMutex);
127 callback = m_callback;
133 }
catch (
const std::exception& e) {
134 LOG_ERROR(
"ISS Tracker: Callback threw exception: {}", e.what());
136 LOG_ERROR(
"ISS Tracker: Callback threw unknown exception");
140 LOG_INFO(
"ISS Tracker: Position updated - Lat: {}, Long: {}, Alt: {} km, Vel: {} km/h",
143 }
catch (
const std::exception& e) {
144 LOG_ERROR(
"ISS Tracker: Error fetching position: {}", e.what());
146 LOG_ERROR(
"ISS Tracker: Unknown error fetching position");
150 auto start = std::chrono::steady_clock::now();
151 while (!stopToken.stop_requested()) {
152 auto now = std::chrono::steady_clock::now();
153 auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - start).count();
157 std::this_thread::sleep_for(std::chrono::milliseconds(100));
161 LOG_INFO(
"ISS Tracker: Tracking loop exited");
164ISSPosition ISSTracker::FetchPositionImpl(
const std::stop_token& stopToken) {
165 ISSPosition position;
166 position.
valid =
false;
169 const HttpClient http;
172 const HttpRequest request{.url = ISS_API_URL,
173 .userAgent =
"MetaImGUI-ISSTracker/1.0",
174 .timeout = std::chrono::seconds{30},
176 const HttpResponse response = http.Get(request, stopToken);
182 LOG_ERROR(
"ISS Tracker: HTTP fetch failed (status={})",
static_cast<int>(response.status));
185 if (response.body.empty()) {
186 LOG_ERROR(
"ISS Tracker: Empty response from server");
190 position = ParseJSON(response.body);
191 }
catch (
const std::bad_alloc& e) {
192 LOG_ERROR(
"ISS Tracker: Memory allocation failed: {}", e.what());
193 }
catch (
const std::exception& e) {
194 LOG_ERROR(
"ISS Tracker: Fetch failed: {}", e.what());
196 LOG_ERROR(
"ISS Tracker: Unknown error during fetch");
202ISSPosition ISSTracker::ParseJSON(
const std::string& jsonResponse) {
203 ISSPosition position;
204 position.valid =
false;
207 auto json = nlohmann::json::parse(jsonResponse);
210 if (
json.contains(
"latitude") &&
json.contains(
"longitude")) {
211 position.latitude =
json[
"latitude"].get<
double>();
212 position.longitude =
json[
"longitude"].get<
double>();
215 if (
json.contains(
"altitude")) {
216 position.altitude =
json[
"altitude"].get<
double>();
218 if (
json.contains(
"velocity")) {
219 position.velocity =
json[
"velocity"].get<
double>();
221 if (
json.contains(
"timestamp")) {
222 position.timestamp =
json[
"timestamp"].get<
long>();
225 position.valid =
true;
227 LOG_ERROR(
"ISS Tracker: Missing required fields in JSON response");
229 }
catch (
const nlohmann::json::parse_error& e) {
230 LOG_ERROR(
"ISS Tracker: JSON parse error: {}", e.what());
231 }
catch (
const nlohmann::json::type_error& e) {
232 LOG_ERROR(
"ISS Tracker: JSON type error: {}", e.what());
233 }
catch (
const std::exception& e) {
234 LOG_ERROR(
"ISS Tracker: Error parsing JSON: {}", e.what());
240void ISSTracker::AddToHistory(
const ISSPosition& position) {
243 if (!position.valid) {
248 m_positionHistory.push_back(position);
251 while (m_positionHistory.size() > m_maxHistorySize) {
252 m_positionHistory.pop_front();