#include "tle_handler.h" #include "core/config.h" #include "db/db_handler.h" #include "logger.h" #include "nlohmann/json_utils.h" #include "utils/string.h" #include namespace satdump { TleDBHandler::TleDBHandler(std::shared_ptr h) : DBHandlerBase(h) {} void TleDBHandler::init() { // Create TLE Table std::string sql_create_tle = "CREATE TABLE IF NOT EXISTS tle(" "norad INT PRIMARY KEY NOT NULL," "time INT NOT NULL," "name TEXT NOT NULL," "line1 TEXT NOT NULL," "line2 TEXT NOT NULL);"; if (h->run_sql(sql_create_tle)) throw satdump_exception("Failed creating TLE database!"); // Start auto-update (or update now?) autoUpdateTLE(); all = get_all_tles(); // TODOREWORK REMOVE } void TleDBHandler::autoUpdateTLE() { std::string update_setting = satdump_cfg.getValueFromSatDumpGeneral("tle_update_interval"); time_t last_update = std::stoull(h->get_meta("tles_last_updated", "0")); bool honor_setting = true; time_t update_interval; if (update_setting == "Never") honor_setting = false; else if (update_setting == "4 hours") update_interval = 14400; else if (update_setting == "1 day") update_interval = 86400; else if (update_setting == "3 days") update_interval = 259200; else if (update_setting == "7 days") update_interval = 604800; else if (update_setting == "14 days") update_interval = 1209600; else { logger->error("Invalid TLE Auto-update interval: %s", update_setting.c_str()); honor_setting = false; } #if 0 // Update now, if needed time_t now = time(NULL); if (/*(honor_setting && now > last_update + update_interval) ||*/ h->get_table_size("tle") <= 0) { updateTLEDatabase(); last_update = now; } #endif // Schedule updates while running if (honor_setting) { eventBus->register_handler([this](AutoUpdateTLEsEvent evt) { updateTLEDatabase(); }); std::shared_ptr evt = std::make_shared(); taskScheduler->add_task("auto_tle_update_todorework", evt, last_update, update_interval); } } void TleDBHandler::updateTLEDatabase() { logger->info("Updating TLEs..."); std::vector norads_to_fetch = satdump_cfg.main_cfg["tle_settings"]["tles_to_fetch"].get>(); std::vector urls_to_fetch = satdump_cfg.main_cfg["tle_settings"]["urls_to_fetch"].get>(); for (auto &url_str : urls_to_fetch) { auto tles = tryFetchTLEsFromFileURL(url_str); h->tr_begin(); for (auto &t : tles) putTLE(t); h->tr_end(); } for (int norad : norads_to_fetch) { auto tles = tryFetchSingleTLEwithNorad(norad); if (tles.size() == 1) putTLE(tles[0]); else logger->error("There should only be one TLE per norad! %d", norad); } { time_t tt = time(0); std::vector norads; for (auto &t : get_all_tles()) if (tt - t.time > (3600 * 24 * 2)) // TODOREWORK respect update interval! norads.push_back(t.norad); if (norads.size()) logger->error("%d TLEs are too old in database, even after attempting an update. Pulling from space-track. This is NOT optimal!", norads.size()); while (norads.size() > 0) { std::vector cnorads = norads; cnorads.resize(std::min(2000, cnorads.size())); norads.erase(norads.begin(), norads.begin() + cnorads.size()); auto tles = get_from_spacetrack_latest_list(cnorads); // tryFetchTLEsFromFileURL(url_str); h->tr_begin(); for (auto &t : tles) putTLE(t); h->tr_end(); } } // Update last update timestamp & other stuff h->set_meta("tles_last_updated", std::to_string(time(0))); logger->info("%d TLEs in database!", h->get_table_size("tle")); eventBus->fire_event(TLEsUpdatedEvent()); all = get_all_tles(); // TODOREWORK REMOVE } void TleDBHandler::putTLE(TLE tle) // TODOREWORK put actual time of TLE!!!!! { replaceAllStr(tle.name, "'", "''"); std::string sql = "INSERT INTO tle (norad, name, time, line1, line2) VALUES (" + std::to_string(tle.norad) + // ", '" + tle.name + "', '" + std::to_string(time(0)) + "', '" + tle.line1 + "', '" + // tle.line2 + "') ON CONFLICT(norad) DO UPDATE SET name='" + tle.name + // "', time='" + std::to_string(time(0)) + "', line1='" + tle.line1 + "', line2='" + tle.line2 + "';"; char *err = NULL; if (sqlite3_exec(h->db, sql.c_str(), NULL, 0, &err)) { logger->error("Error inserting TLE in database! %s (%s)", err, sql.c_str()); sqlite3_free(err); } } std::optional TleDBHandler::get_from_norad(int norad) { TLE r; sqlite3_stmt *res; if (sqlite3_prepare_v2(h->db, ("SELECT name,line1,line2,time from tle where norad=" + std::to_string(norad)).c_str(), -1, &res, 0)) logger->error("Couldn't fetch TLE from DB! " + std::string(sqlite3_errmsg(h->db))); else if (sqlite3_step(res) == SQLITE_ROW) { r.norad = norad; r.name = (char *)sqlite3_column_text(res, 0); r.line1 = (char *)sqlite3_column_text(res, 1); r.line2 = (char *)sqlite3_column_text(res, 2); r.time = sqlite3_column_int64(res, 3); } sqlite3_finalize(res); return r; } std::optional TleDBHandler::get_from_norad_time(int norad, time_t timestamp) { auto t = get_from_spacetrack_time(norad, timestamp); if (t.has_value()) return t; else return get_from_norad(norad); } std::vector TleDBHandler::get_all_tles() { std::vector rr; sqlite3_stmt *res; if (sqlite3_prepare_v2(h->db, "select norad,name,line1,line2,time from tle;", -1, &res, 0)) logger->error("Couldn't fetch TLE from DB! " + std::string(sqlite3_errmsg(h->db))); else { while (sqlite3_step(res) == SQLITE_ROW) { TLE r; r.norad = sqlite3_column_int(res, 0); r.name = (char *)sqlite3_column_text(res, 1); r.line1 = (char *)sqlite3_column_text(res, 2); r.line2 = (char *)sqlite3_column_text(res, 3); r.time = sqlite3_column_int64(res, 4); rr.push_back(r); } } sqlite3_finalize(res); return rr; } } // namespace satdump