Слияние с tdesktop от 64ca5475f2 до тега v7.3.1 (7.2.10 beta, 7.3, 7.3.1).
- Версия 7.3.1 (7003001), BetaChannel 0, комментарий ZaStoGram сохранён.
- Обновлятор: оригинал убрал пакеты v1 (RSA), а наш Packer и Forgejo
выпускают именно их. v1 оставлен как UnpackUpdateV1 рядом с v2 и
использует новые проверенные распаковку и извлечение файлов.
- mtproto: исправления импорта авторизации из оригинала перенесены в нашу
структуру RequestRegistry; пути include новых файлов кошелька
приведены к нашей раскладке mtproto/.
- prepare.py: стадии оригинала (ucrt64, ffmpeg 8, openssl 3.5, libheif,
Rust, wallet-engine) с нашими skip-debug и patches_extra.
- lib_ui, lib_lottie: форки слиты с версиями из v7.3.1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
148 lines
5.2 KiB
C++
148 lines
5.2 KiB
C++
/*
|
|
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
|
|
*/
|
|
#pragma once
|
|
|
|
#include "base/flat_map.h"
|
|
#include "base/flat_set.h"
|
|
#include "data/data_peer_id.h"
|
|
#include "mtproto/instance/sender.h"
|
|
#include "rpl/variable.h"
|
|
|
|
namespace Main {
|
|
class Session;
|
|
} // namespace Main
|
|
|
|
namespace Wallet {
|
|
|
|
enum class UserAddressState : uchar {
|
|
Unknown,
|
|
Absent,
|
|
Known,
|
|
};
|
|
|
|
struct UserAddress {
|
|
UserAddressState state = UserAddressState::Unknown;
|
|
QString address;
|
|
|
|
friend bool operator==(const UserAddress &, const UserAddress &) = default;
|
|
};
|
|
|
|
struct ForceResolveError {
|
|
QString type;
|
|
bool silent = false;
|
|
};
|
|
|
|
// The Telegram user an address belongs to. An empty |userId| means the
|
|
// address belongs to no user this account may be told about.
|
|
struct AddressOwner {
|
|
UserId userId = UserId();
|
|
QString address;
|
|
QByteArray publicKey;
|
|
};
|
|
|
|
class UserAddresses final {
|
|
public:
|
|
explicit UserAddresses(not_null<Main::Session*> session);
|
|
|
|
// Asks Telegram for the addresses of |ids| this session has no answer
|
|
// for yet, in calls of at most 100, and runs |done| once when the last
|
|
// of them settles. |done| runs exactly once for any input, including an
|
|
// empty one and one every id of which is already answered or cannot be
|
|
// turned into an InputUser — and in those cases it runs before
|
|
// resolve() returns, so a caller must tolerate a synchronous
|
|
// completion. It does not run at all if the session is destroyed first,
|
|
// which retires the requests with it. Read the answer back with
|
|
// known(); |done| carries no payload because the store is the answer.
|
|
void resolve(std::vector<UserId> ids, Fn<void()> done);
|
|
|
|
// Explicitly asks Telegram for one eligible user's address, even when
|
|
// known() already has an answer. The sender must be Ready with positive
|
|
// balance. Local refusal is synchronous: WALLET_UNAVAILABLE,
|
|
// WALLET_USER_INVALID, WALLET_USER_INELIGIBLE, WALLET_NOT_READY or
|
|
// WALLET_BALANCE_EMPTY. Invalid replies fail with WALLET_ADDRESS_INVALID;
|
|
// RPC failures retain their type and silent disposition and are terminal.
|
|
// Only a validated nonempty canonical address reaches |done|, after it
|
|
// is published through known(); no older reply overwrites a newer one.
|
|
// Failure preserves the store and carries no destination.
|
|
// Destruction retires pending requests without running either callback.
|
|
void forceResolve(
|
|
UserId id,
|
|
Fn<void(QString)> done,
|
|
Fn<void(ForceResolveError)> fail);
|
|
[[nodiscard]] QString forceResolveError(UserId id) const;
|
|
[[nodiscard]] QString recipientError(UserId id) const;
|
|
|
|
// WHY: Telegram may withhold the owner while returning usable metadata.
|
|
// Successful replies, even empty ones, are cached and may answer |done|
|
|
// synchronously; an unavailable API answers no owner, a failure |fail|.
|
|
|
|
// Destruction retires pending requests without running either.
|
|
void resolveOwner(
|
|
QString address,
|
|
Fn<void(AddressOwner)> done,
|
|
Fn<void(bool silent)> fail);
|
|
|
|
// The Ed25519 public key Telegram named for |address|, empty when no
|
|
// answer carried one. A comment encrypts for a key from here without the
|
|
// recipient's `get_public_key`, so it works for a wallet that was never
|
|
// deployed, and for any Telegram user's address.
|
|
[[nodiscard]] QByteArray publicKey(const QString &address) const;
|
|
|
|
// Unknown for an id no source has answered for, including one
|
|
// Data::Session cannot hand back, which is never sent. A chunk already
|
|
// in flight never overwrites an answer that landed after it was sent.
|
|
[[nodiscard]] UserAddress known(UserId id) const;
|
|
|
|
// True once the API refused this account. That is a fact about the
|
|
// account, not an answer about any user, so no id is recorded Absent
|
|
// because of it and nothing is asked again until resetUnavailable().
|
|
[[nodiscard]] bool unavailable() const;
|
|
[[nodiscard]] rpl::producer<bool> unavailableValue() const;
|
|
void resetUnavailable();
|
|
|
|
private:
|
|
struct Job {
|
|
Fn<void()> done;
|
|
int chunks = 0;
|
|
};
|
|
|
|
void sendChunk(const std::shared_ptr<Job> &job, std::vector<UserId> ids);
|
|
void applyChunk(
|
|
const std::vector<UserId> &asked,
|
|
const QVector<MTPWalletUserAddress> &reply,
|
|
uint64 serial);
|
|
const QVector<MTPWalletUserAddress> &processReply(
|
|
const MTPwallet_UserAddresses &result);
|
|
void rememberKeys(const QVector<MTPWalletUserAddress> &reply);
|
|
void finishChunk(const std::shared_ptr<Job> &job);
|
|
[[nodiscard]] bool answerIsNewest(UserId id, uint64 serial) const;
|
|
void noteAnswer(UserId id, uint64 serial);
|
|
void finish(const std::shared_ptr<Job> &job);
|
|
void finishOwner(
|
|
const QString &address,
|
|
std::optional<AddressOwner> owner,
|
|
bool cache,
|
|
bool silent);
|
|
|
|
const not_null<Main::Session*> _session;
|
|
MTP::Sender _api;
|
|
rpl::variable<bool> _unavailable = false;
|
|
base::flat_map<QString, QByteArray> _publicKeys;
|
|
base::flat_map<QString, AddressOwner> _owners;
|
|
struct OwnerWaiter {
|
|
Fn<void(AddressOwner)> done;
|
|
Fn<void(bool silent)> fail;
|
|
};
|
|
base::flat_map<QString, std::vector<OwnerWaiter>> _ownerWaiting;
|
|
base::flat_set<QString> _ownerRequested;
|
|
base::flat_map<UserId, uint64> _answeredBy; // newest request that wrote
|
|
uint64 _requestSerial = 0;
|
|
|
|
};
|
|
|
|
} // namespace Wallet
|