#include "dataprovider.h" #include #include #include #include #include #include #ifdef Q_OS_WASM #include #endif DataProvider::DataProvider(QObject *parent) : QObject(parent) { } // ---------------------------------------------------------------------------- // Adresse de l'API (synthèse §49) : "/api" sur l'ORIGINE de la page qui a chargé le wasm (protocole + hôte + port), // lue dans window.location.origin : // - à distance : https://b.ship2net.fr/api -> Traefik (session Live vérifiée à chaque requête) -> nginx du CM5 // -> API (port 8080). Même origine que la page : le cookie de session est joint automatiquement par le // navigateur, et il n'y a plus de requête entre origines (CORS). // - en local : https:///api -> nginx du CM5 -> API. // Hors navigateur (exécution native pour la mise au point) : variable d'environnement SHIPHEART_API, ou l'API locale. // ---------------------------------------------------------------------------- QString DataProvider::adresseApi() { #ifdef Q_OS_WASM const std::string origine = emscripten::val::global("location")["origin"].as(); return QString::fromStdString(origine) + QStringLiteral("/api"); #else return qEnvironmentVariable("SHIPHEART_API", QStringLiteral("http://127.0.0.1:8080")); #endif } // ---------------------------------------------------------------------------- // Traitement commun d'une réponse en erreur. Une réponse 401 vient du vérificateur du Live (session expirée, ou accès // suspendu/révoqué depuis le portail) : elle est signalée à part (sessionExpiree), car elle ne se résoudra pas seule - // contrairement à une coupure réseau, qui relève du simple "hors ligne". // Retour : true si la réponse est en erreur (déjà signalée : l'appelant n'a plus qu'à sortir). // ---------------------------------------------------------------------------- bool DataProvider::reponseEnErreur(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) return false; const int statut = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statut == 401 && !m_sessionExpiree) { m_sessionExpiree = true; emit sessionExpireeChange(); } signalerEchec(); emit erreur(reply->errorString()); return true; } void DataProvider::signalerSucces() { m_connecte = true; m_derniereConnexionReussie = QDateTime::currentDateTime(); emit etatConnexionChange(); } void DataProvider::signalerEchec() { // Ne touche JAMAIS m_derniereConnexionReussie ici : on veut garder la // trace du dernier succès réel, pas la remplacer par l'instant de l'échec. if (m_connecte) { m_connecte = false; emit etatConnexionChange(); } } void DataProvider::get_familles(const QString &type) { QUrl url(m_baseUrl + "/elements/familles"); QUrlQuery query; query.addQueryItem("type", type); url.setQuery(query); auto reply = m_manager.get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [this, reply, type]() { reply->deleteLater(); if (reponseEnErreur(reply)) return; const auto doc = QJsonDocument::fromJson(reply->readAll()); const auto obj = doc.object(); if (obj["status"].toString() != "ok") { signalerEchec(); emit erreur(obj["message"].toString()); return; } signalerSucces(); emit famillesRecues(type, obj["familles"].toArray()); }); } void DataProvider::get_elements(const QString &type, int famille) { QUrl url(m_baseUrl + "/elements"); QUrlQuery query; query.addQueryItem("type", type); query.addQueryItem("famille", QString::number(famille)); url.setQuery(query); auto reply = m_manager.get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [this, reply, type, famille]() { reply->deleteLater(); if (reponseEnErreur(reply)) return; const auto doc = QJsonDocument::fromJson(reply->readAll()); const auto obj = doc.object(); if (obj["status"].toString() != "ok") { signalerEchec(); emit erreur(obj["message"].toString()); return; } signalerSucces(); emit elementsRecus(type, famille, obj["elements"].toArray()); }); } void DataProvider::set_circuit(int id, int consigne) { QUrl url(m_baseUrl + "/elements/circuit/" + QString::number(id)); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QJsonObject body; body["consigne"] = consigne; const QByteArray data = QJsonDocument(body).toJson(); auto reply = m_manager.sendCustomRequest(request, "PATCH", data); connect(reply, &QNetworkReply::finished, this, [this, reply, id]() { reply->deleteLater(); const bool succes = !reponseEnErreur(reply); if (succes) signalerSucces(); emit circuitModifie(id, succes); }); }