diff --git a/.current_version b/.current_version new file mode 100644 index 0000000..4a85099 --- /dev/null +++ b/.current_version @@ -0,0 +1 @@ +260924_084534 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 37724e3..5b83f34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,35 @@ set(CMAKE_AUTOMOC ON) find_package(Qt6 REQUIRED COMPONENTS Core HttpServer Sql) +# --------------------------------------------------------------------------- +# Version dynamique, injectée dans _version.h à CHAQUE build - même mécanisme +# que shipheart_qt (cf synthèse, format yymmdd_HHMMSS, ex: 260924_080910) : +# une cible personnalisée sans suivi de fichier est toujours considérée +# périmée par Ninja/Make et se ré-exécute avant chaque build, contrairement à +# string(TIMESTAMP ...) seul qui ne s'évalue qu'à la configuration du projet. +# --------------------------------------------------------------------------- +add_custom_target(generate_version ALL + COMMAND ${CMAKE_COMMAND} + -DOUTPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/_version.h + -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_version.cmake + COMMENT "Régénération de _version.h (horodatage)" + BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/_version.h +) + add_executable(shipheart_api main.cpp + # Header listé pour visibilité dans l'IDE (non obligatoire pour la compilation) : + _version.h +) + +add_dependencies(shipheart_api generate_version) + +add_custom_command(TARGET shipheart_api POST_BUILD + COMMAND ${CMAKE_COMMAND} + -DEXE_PATH=$ + -DSRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/archive_version.cmake + COMMENT "Archivage d'une copie horodatée de l'exécutable" ) target_link_libraries(shipheart_api PRIVATE diff --git a/CMakeLists.txt:Zone.Identifier b/CMakeLists.txt:Zone.Identifier new file mode 100644 index 0000000..35c9e5e Binary files /dev/null and b/CMakeLists.txt:Zone.Identifier differ diff --git a/_version.h b/_version.h new file mode 100644 index 0000000..58fb4a6 --- /dev/null +++ b/_version.h @@ -0,0 +1,6 @@ +#ifndef _VERSION_H +#define _VERSION_H + +#define VERSION "260924_084534" + +#endif // _VERSION_H diff --git a/archive_version.cmake b/archive_version.cmake new file mode 100644 index 0000000..deb8fdb --- /dev/null +++ b/archive_version.cmake @@ -0,0 +1,8 @@ +file(READ "${SRC_DIR}/.current_version" APP_VERSION) +string(STRIP "${APP_VERSION}" APP_VERSION) + +file(MAKE_DIRECTORY "${SRC_DIR}/versions") +file(COPY "${EXE_PATH}" DESTINATION "${SRC_DIR}/versions") +file(RENAME "${SRC_DIR}/versions/shipheart_api" "${SRC_DIR}/versions/shipheart_api_${APP_VERSION}") + +message(STATUS "Exécutable archivé : versions/shipheart_api_${APP_VERSION}") diff --git a/archive_version.cmake:Zone.Identifier b/archive_version.cmake:Zone.Identifier new file mode 100644 index 0000000..35c9e5e Binary files /dev/null and b/archive_version.cmake:Zone.Identifier differ diff --git a/generate_version.cmake b/generate_version.cmake new file mode 100644 index 0000000..ebf66a8 --- /dev/null +++ b/generate_version.cmake @@ -0,0 +1,22 @@ +# Exécuté à CHAQUE build (pas seulement à chaque reconfiguration CMake) via +# la cible "generate_version" dans CMakeLists.txt, qui n'a aucun suivi de +# fichier et est donc toujours considérée périmée par Ninja/Make. +# +# Même mécanisme que shipheart_qt (cf synthèse) : deux exécutables différents +# (même par une modification infime du code) obtiennent systématiquement un +# horodatage différent, garantissant l'unicité recherchée. + +string(TIMESTAMP APP_VERSION "%y%m%d_%H%M%S") + +file(WRITE "${OUTPUT_FILE}" +"#ifndef _VERSION_H +#define _VERSION_H + +#define VERSION \"${APP_VERSION}\" + +#endif // _VERSION_H +") + +file(WRITE "${CMAKE_CURRENT_LIST_DIR}/.current_version" "${APP_VERSION}") + +message(STATUS "Version ShipHeart API régénérée : ${APP_VERSION}") diff --git a/generate_version.cmake:Zone.Identifier b/generate_version.cmake:Zone.Identifier new file mode 100644 index 0000000..35c9e5e Binary files /dev/null and b/generate_version.cmake:Zone.Identifier differ diff --git a/main.cpp b/main.cpp index 027d1aa..26d5b2d 100644 --- a/main.cpp +++ b/main.cpp @@ -15,6 +15,8 @@ #include #include +#include "_version.h" + // ============================================================================ // shipheart_api - Phase 4 : première tranche verticale, domaine "circuit" // ---------------------------------------------------------------------------- @@ -193,6 +195,7 @@ static void assurer_connexion_bdd() int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + qInfo() << "shipheart_api version" << VERSION; // --- Connexion MariaDB locale --- QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); diff --git a/main.cpp:Zone.Identifier b/main.cpp:Zone.Identifier index 80edf1d..35c9e5e 100644 Binary files a/main.cpp:Zone.Identifier and b/main.cpp:Zone.Identifier differ diff --git a/main_OLD.cpp b/main_OLD.cpp index 14f0b75..027d1aa 100644 --- a/main_OLD.cpp +++ b/main_OLD.cpp @@ -164,6 +164,32 @@ static QHttpServerResponse withCors(QHttpServerResponse &&resp) return std::move(resp); } +// ---------------------------------------------------------------------------- +// Vérifie que la connexion MariaDB (ouverte une seule fois au démarrage) est +// toujours active, et la rétablit sinon. isOpen() peut rester vrai même après +// une coupure réseau ou un dépassement de wait_timeout côté serveur - un test +// léger (SELECT 1) confirme que la connexion répond réellement. Sans ce +// contrôle, l'API reste "vivante" indéfiniment mais chaque requête SQL échoue +// silencieusement après une longue période d'inactivité (constaté après +// plusieurs semaines d'exécution continue, cf synthèse). +// À appeler en tout premier dans chaque route qui touche la base. +// ---------------------------------------------------------------------------- +static void assurer_connexion_bdd() +{ + QSqlDatabase db = QSqlDatabase::database(); + if (db.isOpen()) { + QSqlQuery test(db); + if (test.exec("SELECT 1")) return; + } + qWarning() << "Connexion MariaDB perdue, tentative de reconnexion..."; + db.close(); + if (db.open()) { + qInfo() << "Reconnexion MariaDB réussie."; + } else { + qCritical() << "Reconnexion MariaDB échouée :" << db.lastError().text(); + } +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); @@ -196,6 +222,7 @@ int main(int argc, char *argv[]) // requêtes onglets de mise_a_jour_onglets_circuits()). // ------------------------------------------------------------------ server.route("/elements/familles", [](const QHttpServerRequest &request) { + assurer_connexion_bdd(); QUrlQuery query(request.query()); const QString type = query.queryItemValue("type"); @@ -352,6 +379,7 @@ int main(int argc, char *argv[]) // différents, mais un seul, appelé deux fois). // ------------------------------------------------------------------ server.route("/elements", [](const QHttpServerRequest &request) { + assurer_connexion_bdd(); QUrlQuery query(request.query()); const QString type = query.queryItemValue("type"); const QString familleStr = query.queryItemValue("famille"); @@ -610,6 +638,7 @@ int main(int argc, char *argv[]) // ------------------------------------------------------------------ server.route("/elements/circuit/", QHttpServerRequest::Method::Patch, [](int idCircuit, const QHttpServerRequest &request) { + assurer_connexion_bdd(); const QJsonDocument body = QJsonDocument::fromJson(request.body()); if (!body.isObject()) { QJsonObject err; @@ -686,6 +715,7 @@ int main(int argc, char *argv[]) // Circuits/batteries (sélection de variable côté client) à venir. // ------------------------------------------------------------------ server.route("/mesures", [](const QHttpServerRequest &request) { + assurer_connexion_bdd(); QUrlQuery query(request.query()); const QString type = query.queryItemValue("type"); const QString idStr = query.queryItemValue("id"); @@ -1037,6 +1067,7 @@ int main(int argc, char *argv[]) // 90% du temps de traitement natif pour un gain marginal). // ------------------------------------------------------------------ server.route("/energie", [](const QHttpServerRequest &request) { + assurer_connexion_bdd(); QUrlQuery query(request.query()); const QString type = query.queryItemValue("type"); const QString idStr = query.queryItemValue("id"); diff --git a/versions/shipheart_api_260924_084015 b/versions/shipheart_api_260924_084015 new file mode 100755 index 0000000..76e6941 Binary files /dev/null and b/versions/shipheart_api_260924_084015 differ diff --git a/versions/shipheart_api_260924_084355 b/versions/shipheart_api_260924_084355 new file mode 100755 index 0000000..68fdf7f Binary files /dev/null and b/versions/shipheart_api_260924_084355 differ diff --git a/versions/shipheart_api_260924_084403 b/versions/shipheart_api_260924_084403 new file mode 100755 index 0000000..ebf33e8 Binary files /dev/null and b/versions/shipheart_api_260924_084403 differ diff --git a/versions/shipheart_api_260924_084534 b/versions/shipheart_api_260924_084534 new file mode 100755 index 0000000..f1f7b5d Binary files /dev/null and b/versions/shipheart_api_260924_084534 differ