| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "smartglocal/smartglocal_api_client.h"
- #include "smartglocal/smartglocal_error.h"
- #include "smartglocal/smartglocal_token.h"
- #include <QtCore/QJsonObject>
- #include <QtCore/QJsonDocument>
- #include <QtNetwork/QNetworkRequest>
- #include <QtNetwork/QNetworkReply>
- #include <crl/crl_on_main.h>
- namespace SmartGlocal {
- namespace {
- [[nodiscard]] QString APIURLBase(bool isTest) {
- return isTest
- ? "tgb-playground.smart-glocal.com/cds/v1"
- : "tgb.smart-glocal.com/cds/v1";
- }
- [[nodiscard]] QString TokenEndpoint() {
- return "tokenize/card";
- }
- [[nodiscard]] QByteArray ToJson(const Stripe::CardParams &card) {
- const auto zero = QChar('0');
- const auto month = QString("%1").arg(card.expMonth, 2, 10, zero);
- const auto year = QString("%1").arg(card.expYear % 100, 2, 10, zero);
- return QJsonDocument(QJsonObject{
- { "card", QJsonObject{
- { "number", card.number },
- { "expiration_month", month },
- { "expiration_year", year },
- { "security_code", card.cvc },
- } },
- }).toJson(QJsonDocument::Compact);
- }
- [[nodiscard]] QString ComputeApiUrl(PaymentConfiguration configuration) {
- const auto url = configuration.tokenizeUrl;
- if (url.startsWith("https://")
- && url.endsWith(".smart-glocal.com/cds/v1/tokenize/card")) {
- return url;
- }
- return QString("https://%1/%2")
- .arg(APIURLBase(configuration.isTest))
- .arg(TokenEndpoint());
- }
- } // namespace
- APIClient::APIClient(PaymentConfiguration configuration)
- : _apiUrl(ComputeApiUrl(configuration))
- , _configuration(configuration) {
- _additionalHttpHeaders = {
- { "X-PUBLIC-TOKEN", _configuration.publicToken },
- };
- }
- APIClient::~APIClient() {
- const auto destroy = std::move(_old);
- }
- void APIClient::createTokenWithCard(
- Stripe::CardParams card,
- TokenCompletionCallback completion) {
- createTokenWithData(ToJson(card), std::move(completion));
- }
- void APIClient::createTokenWithData(
- QByteArray data,
- TokenCompletionCallback completion) {
- const auto url = QUrl(_apiUrl);
- auto request = QNetworkRequest(url);
- request.setHeader(
- QNetworkRequest::ContentTypeHeader,
- "application/json");
- for (const auto &[name, value] : _additionalHttpHeaders) {
- request.setRawHeader(name.toUtf8(), value.toUtf8());
- }
- destroyReplyDelayed(std::move(_reply));
- _reply.reset(_manager.post(request, data));
- const auto finish = [=](Token token, Error error) {
- crl::on_main([
- completion,
- token = std::move(token),
- error = std::move(error)
- ] {
- completion(std::move(token), std::move(error));
- });
- };
- const auto finishWithError = [=](Error error) {
- finish(Token::Empty(), std::move(error));
- };
- const auto finishWithToken = [=](Token token) {
- finish(std::move(token), Error::None());
- };
- QObject::connect(_reply.get(), &QNetworkReply::finished, [=] {
- const auto replyError = int(_reply->error());
- const auto replyErrorString = _reply->errorString();
- const auto bytes = _reply->readAll();
- destroyReplyDelayed(std::move(_reply));
- auto parseError = QJsonParseError();
- const auto document = QJsonDocument::fromJson(bytes, &parseError);
- if (!bytes.isEmpty()) {
- if (parseError.error != QJsonParseError::NoError) {
- const auto code = int(parseError.error);
- finishWithError({
- Error::Code::JsonParse,
- QString("InvalidJson%1").arg(code),
- parseError.errorString(),
- });
- return;
- } else if (!document.isObject()) {
- finishWithError({
- Error::Code::JsonFormat,
- "InvalidJsonRoot",
- "Not an object in JSON reply.",
- });
- return;
- }
- const auto object = document.object();
- if (auto error = Error::DecodedObjectFromResponse(object)) {
- finishWithError(std::move(error));
- return;
- }
- }
- if (replyError != QNetworkReply::NoError) {
- finishWithError({
- Error::Code::Network,
- QString("RequestError%1").arg(replyError),
- replyErrorString,
- });
- return;
- }
- auto token = Token::DecodedObjectFromAPIResponse(
- document.object().value("data").toObject());
- if (!token) {
- finishWithError({
- Error::Code::JsonFormat,
- "InvalidTokenJson",
- "Could not parse token.",
- });
- }
- finishWithToken(std::move(token));
- });
- }
- void APIClient::destroyReplyDelayed(std::unique_ptr<QNetworkReply> reply) {
- if (!reply) {
- return;
- }
- const auto raw = reply.get();
- _old.push_back(std::move(reply));
- QObject::disconnect(raw, &QNetworkReply::finished, nullptr, nullptr);
- raw->deleteLater();
- QObject::connect(raw, &QObject::destroyed, [=] {
- for (auto i = begin(_old); i != end(_old); ++i) {
- if (i->get() == raw) {
- i->release();
- _old.erase(i);
- break;
- }
- }
- });
- }
- } // namespace SmartGlocal
|