#include "api.h" #include #include #include #include constexpr const char* json = "application/json"; constexpr const char* urlEncoded = "application/x-www-form-urlencoded"; struct NetworkReplyDeleter { void operator () (QNetworkReply* reply) { reply->deleteLater(); } }; API::API(const QUrl& address, QObject* parent): QObject(parent), address(address), network(), state(NoServer) {} QUrl API::getAddress() const { return address; } API::State API::getState() const { return state; } void API::setAddress(const QUrl& path) { if (address == path) return; if (state == Authenticated) { //do something } address = path; state = address.isEmpty() ? NoServer : NotAuthenticated; emit addressChanged(address); emit stateChanged(state); } void API::test(const QString& path, const QJSValue& finished) { qDebug() << "Testing" << path; if (state == Offline) return callCallback(finished, "Need to be online to test"); QUrl address(path); QNetworkRequest request(path + "/info"); request.setHeader(QNetworkRequest::ContentTypeHeader, json); QNetworkReply* reply = network.get(request); connect(reply, &QNetworkReply::finished, std::bind(&API::onTestFinished, this, reply, address, finished) ); } void API::onTestFinished(QNetworkReply* reply, const QUrl& addr, const QJSValue& finished) { std::unique_ptr rpl(reply); QNetworkReply::NetworkError error = reply->error(); if (error != QNetworkReply::NoError) return callCallback(finished, reply->errorString()); QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader); if (! contentType.isValid() || !contentType.canConvert() || contentType.toString() != json ) { return callCallback(finished, "wrong response content type"); } QByteArray data = reply->readAll(); QJsonDocument document = QJsonDocument::fromJson(data); QJsonObject rootObj = document.object(); QJsonValue type = rootObj.value("type"); QJsonValue version = rootObj.value("version"); if (!type.isString() || !version.isString()) return callCallback(finished, "malformed json"); if (type.toString() != "pica") return callCallback(finished, "server of this type (" + type.toString() + ") is not supported"); if (version.toString() != "0.0.1") return callCallback(finished, "server of this version (" + version.toString() + ") is not supported"); callCallback(finished, QString(), {QJSValue(true)}); address = ""; //to provoke singal change even if it's the same server setAddress(addr); } void API::sendRegister(const QString& login, const QString& password, const QJSValue &finished) { qDebug() << "Registering..."; if (state != NotAuthenticated) callCallback(finished, "Can not register in current state"); return; QUrlQuery params({ {"login", login}, {"password", password} }); QNetworkRequest request(address.path() + "/register"); request.setHeader(QNetworkRequest::ContentTypeHeader, urlEncoded); QNetworkReply* reply = network.post(request, params.toString(QUrl::FullyEncoded).toUtf8()); connect(reply, &QNetworkReply::finished, std::bind(&API::onRegisterFinished, this, reply, finished) ); } void API::onRegisterFinished(QNetworkReply *reply, const QJSValue &finished) const { std::unique_ptr rpl(reply); QNetworkReply::NetworkError error = reply->error(); if (error != QNetworkReply::NoError) return callCallback(finished, reply->errorString()); QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader); if (! contentType.isValid() || !contentType.canConvert() || contentType.toString() != json ) { QString err("wrong response content type"); qDebug() << "Register failed:" << err; callCallback(finished, err); return; } QByteArray data = reply->readAll(); QJsonDocument document = QJsonDocument::fromJson(data); QJsonObject rootObj = document.object(); QJsonValue result = rootObj.value("result"); if (!result.isString()) return callCallback(finished, "malformed json"); if (result.toString() != "ok") return callCallback(finished, "Registration result was not okay"); callCallback(finished, QString(), {QJSValue(true)}); } void API::callCallback(const QJSValue& callback, const QString& error, const QJSValueList& arguments) const { if (callback.isCallable()) { if (error.isEmpty()) callback.call(QJSValueList({QJSValue(QJSValue::NullValue)}) + arguments); else callback.call({QJSValue(error)}); } }