Files
shipheart-wasm/dataprovider.cpp
T

138 lines
5.0 KiB
C++

#include "dataprovider.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QUrlQuery>
#ifdef Q_OS_WASM
#include <emscripten/val.h>
#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<N>.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://<IP du CM5>/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<std::string>();
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);
});
}