2023-11-24 23:48:01 +00:00
|
|
|
#include "api.h"
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
2023-12-16 01:44:25 +00:00
|
|
|
#include <QUrlQuery>
|
2023-11-24 23:48:01 +00:00
|
|
|
|
|
|
|
constexpr const char* json = "application/json";
|
2023-12-16 01:44:25 +00:00
|
|
|
constexpr const char* urlEncoded = "application/x-www-form-urlencoded";
|
2023-11-24 23:48:01 +00:00
|
|
|
|
|
|
|
struct NetworkReplyDeleter {
|
|
|
|
void operator () (QNetworkReply* reply) {
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
API::API(const QUrl& address, QObject* parent):
|
|
|
|
QObject(parent),
|
|
|
|
address(address),
|
2023-12-16 01:44:25 +00:00
|
|
|
network(),
|
|
|
|
state(NoServer)
|
|
|
|
{}
|
2023-11-24 23:48:01 +00:00
|
|
|
|
2023-12-16 01:44:25 +00:00
|
|
|
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);
|
2023-11-24 23:48:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void API::test(const QString& path, const QJSValue& finished) {
|
|
|
|
qDebug() << "Testing" << path;
|
2023-12-16 01:44:25 +00:00
|
|
|
|
|
|
|
if (state == Offline) {
|
|
|
|
QString err = "Need to be online to test";
|
|
|
|
qDebug() << "Test for" << path << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-24 23:48:01 +00:00
|
|
|
QNetworkRequest request(path + "/info");
|
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, json);
|
|
|
|
|
|
|
|
QNetworkReply* reply = network.get(request);
|
|
|
|
connect(reply, &QNetworkReply::finished,
|
2023-12-16 01:44:25 +00:00
|
|
|
std::bind(&API::onTestFinished, this, reply, finished)
|
2023-11-24 23:48:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-12-16 01:44:25 +00:00
|
|
|
void API::onTestFinished(QNetworkReply* reply, const QJSValue& finished) const {
|
2023-11-24 23:48:01 +00:00
|
|
|
std::unique_ptr<QNetworkReply, NetworkReplyDeleter> rpl(reply);
|
|
|
|
QNetworkReply::NetworkError error = reply->error();
|
|
|
|
if (error != QNetworkReply::NoError) {
|
|
|
|
QString err = reply->errorString();
|
|
|
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader);
|
|
|
|
if (!
|
|
|
|
contentType.isValid() ||
|
|
|
|
!contentType.canConvert<QString>() ||
|
|
|
|
contentType.toString() != json
|
|
|
|
) {
|
|
|
|
QString err("wrong response content type");
|
|
|
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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()) {
|
|
|
|
QString err("malformed json");
|
|
|
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-16 01:44:25 +00:00
|
|
|
if (type.toString() != "pica") {
|
2023-11-24 23:48:01 +00:00
|
|
|
QString err("server of this type (" + type.toString() + ") is not supported");
|
|
|
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version.toString() != "0.0.1") {
|
|
|
|
QString err("server of this version (" + version.toString() + ") is not supported");
|
|
|
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callCallback(finished, QString(), {QJSValue(true)});
|
|
|
|
}
|
|
|
|
|
2023-12-16 01:44:25 +00:00
|
|
|
void API::sendRegister(const QString& login, const QString& password, const QJSValue &finished) {
|
|
|
|
qDebug() << "Registering...";
|
|
|
|
|
|
|
|
if (state != NotAuthenticated) {
|
|
|
|
QString err = "Can not register in current state";
|
|
|
|
qDebug() << "Register failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
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<QNetworkReply, NetworkReplyDeleter> rpl(reply);
|
|
|
|
QNetworkReply::NetworkError error = reply->error();
|
|
|
|
if (error != QNetworkReply::NoError) {
|
|
|
|
QString err = reply->errorString();
|
|
|
|
qDebug() << "Register failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader);
|
|
|
|
if (!
|
|
|
|
contentType.isValid() ||
|
|
|
|
!contentType.canConvert<QString>() ||
|
|
|
|
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()) {
|
|
|
|
QString err("malformed json");
|
|
|
|
qDebug() << "Register failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.toString() != "ok") {
|
|
|
|
QString err("Registration result was not okay");
|
|
|
|
qDebug() << "Register failed:" << err;
|
|
|
|
callCallback(finished, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callCallback(finished, QString(), {QJSValue(true)});
|
|
|
|
}
|
|
|
|
|
2023-11-24 23:48:01 +00:00
|
|
|
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)});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|