| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /*
- 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/variant.h"
- #include "api/api_common.h"
- namespace Ui {
- struct PreparedFileInformation;
- } // namespace Ui
- namespace Main {
- class Session;
- } // namespace Main
- // Load files up to 2'000 MB.
- constexpr auto kFileSizeLimit = 2'000 * int64(1024 * 1024);
- // Load files up to 4'000 MB.
- constexpr auto kFileSizePremiumLimit = 4'000 * int64(1024 * 1024);
- extern const char kOptionSendLargePhotos[];
- [[nodiscard]] int PhotoSideLimit();
- enum class SendMediaType {
- Photo,
- Audio,
- Round,
- File,
- ThemeFile,
- Secure,
- };
- using TaskId = void*; // no interface, just id
- inline constexpr auto kEmptyTaskId = TaskId();
- class Task {
- public:
- virtual void process() = 0; // is executed in a separate thread
- virtual void finish() = 0; // is executed in the same as TaskQueue thread
- virtual ~Task() = default;
- TaskId id() const {
- return static_cast<TaskId>(const_cast<Task*>(this));
- }
- };
- class TaskQueueWorker;
- class TaskQueue : public QObject {
- Q_OBJECT
- public:
- explicit TaskQueue(crl::time stopTimeoutMs = 0); // <= 0 - never stop worker
- TaskId addTask(std::unique_ptr<Task> &&task);
- void addTasks(std::vector<std::unique_ptr<Task>> &&tasks);
- void cancelTask(TaskId id); // this task finish() won't be called
- ~TaskQueue();
- Q_SIGNALS:
- void taskAdded();
- public Q_SLOTS:
- void onTaskProcessed();
- void stop();
- private:
- friend class TaskQueueWorker;
- void wakeThread();
- std::deque<std::unique_ptr<Task>> _tasksToProcess;
- std::deque<std::unique_ptr<Task>> _tasksToFinish;
- TaskId _taskInProcessId = TaskId();
- QMutex _tasksToProcessMutex, _tasksToFinishMutex;
- QThread *_thread = nullptr;
- TaskQueueWorker *_worker = nullptr;
- QTimer *_stopTimer = nullptr;
- };
- class TaskQueueWorker : public QObject {
- Q_OBJECT
- public:
- TaskQueueWorker(TaskQueue *queue) : _queue(queue) {
- }
- Q_SIGNALS:
- void taskProcessed();
- public Q_SLOTS:
- void onTaskAdded();
- private:
- TaskQueue *_queue;
- bool _inTaskAdded = false;
- };
- struct SendingAlbum {
- struct Item {
- explicit Item(TaskId taskId);
- TaskId taskId = kEmptyTaskId;
- uint64 randomId = 0;
- FullMsgId msgId;
- std::optional<MTPInputSingleMedia> media;
- };
- SendingAlbum();
- void fillMedia(
- not_null<HistoryItem*> item,
- const MTPInputMedia &media,
- uint64 randomId);
- void refreshMediaCaption(not_null<HistoryItem*> item);
- void removeItem(not_null<HistoryItem*> item);
- uint64 groupId = 0;
- std::vector<Item> items;
- Api::SendOptions options;
- bool sent = false;
- };
- struct FileLoadTo {
- FileLoadTo(
- PeerId peer,
- Api::SendOptions options,
- FullReplyTo replyTo,
- MsgId replaceMediaOf)
- : peer(peer)
- , options(options)
- , replyTo(replyTo)
- , replaceMediaOf(replaceMediaOf) {
- }
- PeerId peer;
- Api::SendOptions options;
- FullReplyTo replyTo;
- MsgId replaceMediaOf;
- };
- using UploadFileParts = std::vector<QByteArray>;
- struct FilePrepareDescriptor {
- TaskId taskId = kEmptyTaskId;
- base::required<uint64> id;
- SendMediaType type = SendMediaType::File;
- FileLoadTo to = { PeerId(), Api::SendOptions(), FullReplyTo(), MsgId() };
- TextWithTags caption;
- bool spoiler = false;
- std::shared_ptr<SendingAlbum> album;
- };
- struct FilePrepareResult {
- explicit FilePrepareResult(FilePrepareDescriptor &&descriptor);
- TaskId taskId = kEmptyTaskId;
- uint64 id = 0;
- FileLoadTo to;
- std::shared_ptr<SendingAlbum> album;
- SendMediaType type = SendMediaType::File;
- QString filepath;
- QByteArray content;
- QString filename;
- QString filemime;
- int64 filesize = 0;
- UploadFileParts fileparts;
- QByteArray filemd5;
- int64 partssize = 0;
- uint64 thumbId = 0; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos)
- QString thumbname;
- UploadFileParts thumbparts;
- QByteArray thumbbytes;
- QByteArray thumbmd5;
- QImage thumb;
- QImage goodThumbnail;
- QByteArray goodThumbnailBytes;
- MTPPhoto photo = MTP_photoEmpty(MTP_long(0));
- MTPDocument document = MTP_documentEmpty(MTP_long(0));
- PreparedPhotoThumbs photoThumbs;
- TextWithTags caption;
- bool spoiler = false;
- std::vector<MTPInputDocument> attachedStickers;
- std::shared_ptr<FilePrepareResult> videoCover;
- void setFileData(const QByteArray &filedata);
- void setThumbData(const QByteArray &thumbdata);
- };
- [[nodiscard]] std::shared_ptr<FilePrepareResult> MakePreparedFile(
- FilePrepareDescriptor &&descriptor);
- class FileLoadTask final : public Task {
- public:
- static std::unique_ptr<Ui::PreparedFileInformation> ReadMediaInformation(
- const QString &filepath,
- const QByteArray &content,
- const QString &filemime);
- static bool FillImageInformation(
- QImage &&image,
- bool animated,
- std::unique_ptr<Ui::PreparedFileInformation> &result,
- QByteArray content = {},
- QByteArray format = {});
- FileLoadTask(
- not_null<Main::Session*> session,
- const QString &filepath,
- const QByteArray &content,
- std::unique_ptr<Ui::PreparedFileInformation> information,
- std::unique_ptr<FileLoadTask> videoCover,
- SendMediaType type,
- const FileLoadTo &to,
- const TextWithTags &caption,
- bool spoiler,
- std::shared_ptr<SendingAlbum> album = nullptr,
- uint64 idOverride = 0);
- FileLoadTask(
- not_null<Main::Session*> session,
- const QByteArray &voice,
- crl::time duration,
- const VoiceWaveform &waveform,
- bool video,
- const FileLoadTo &to,
- const TextWithTags &caption);
- ~FileLoadTask();
- uint64 fileid() const {
- return _id;
- }
- struct Args {
- bool generateGoodThumbnail = true;
- };
- void process(Args &&args);
- void process() override {
- process({});
- }
- void finish() override;
- [[nodiscard]] auto peekResult() const
- -> const std::shared_ptr<FilePrepareResult> &;
- private:
- static bool CheckForSong(
- const QString &filepath,
- const QByteArray &content,
- std::unique_ptr<Ui::PreparedFileInformation> &result);
- static bool CheckForVideo(
- const QString &filepath,
- const QByteArray &content,
- std::unique_ptr<Ui::PreparedFileInformation> &result);
- static bool CheckForImage(
- const QString &filepath,
- const QByteArray &content,
- std::unique_ptr<Ui::PreparedFileInformation> &result);
- template <typename Mimes, typename Extensions>
- static bool CheckMimeOrExtensions(const QString &filepath, const QString &filemime, Mimes &mimes, Extensions &extensions);
- std::unique_ptr<Ui::PreparedFileInformation> readMediaInformation(const QString &filemime) const;
- void removeFromAlbum();
- uint64 _id = 0;
- base::weak_ptr<Main::Session> _session;
- MTP::DcId _dcId = 0;
- FileLoadTo _to;
- const std::shared_ptr<SendingAlbum> _album;
- QString _filepath;
- QByteArray _content;
- std::unique_ptr<FileLoadTask> _videoCover;
- std::unique_ptr<Ui::PreparedFileInformation> _information;
- crl::time _duration = 0;
- VoiceWaveform _waveform;
- SendMediaType _type;
- TextWithTags _caption;
- bool _spoiler = false;
- std::shared_ptr<FilePrepareResult> _result;
- };
|