Support ringtone uploading.

This commit is contained in:
levlam 2022-04-15 14:07:54 +03:00
parent ff6f165551
commit a16a5ec5e3
3 changed files with 208 additions and 3 deletions

View File

@ -31,11 +31,58 @@
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/MimeType.h"
#include "td/utils/PathView.h"
#include "td/utils/Random.h"
#include "td/utils/tl_helpers.h"
namespace td {
class UploadRingtoneQuery final : public Td::ResultHandler {
FileId file_id_;
Promise<telegram_api::object_ptr<telegram_api::Document>> promise_;
public:
explicit UploadRingtoneQuery(Promise<telegram_api::object_ptr<telegram_api::Document>> &&promise)
: promise_(std::move(promise)) {
}
void send(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, const string &file_name,
const string &mime_type) {
CHECK(input_file != nullptr);
file_id_ = file_id;
send_query(G()->net_query_creator().create(
telegram_api::account_uploadRingtone(std::move(input_file), file_name, mime_type)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_uploadRingtone>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->file_manager_->delete_partial_remote_location(file_id_);
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for UploadRingtoneQuery: " << to_string(result);
promise_.set_value(std::move(result));
}
void on_error(Status status) final {
if (FileReferenceManager::is_file_reference_error(status)) {
LOG(ERROR) << "Receive file reference error " << status;
}
if (begins_with(status.message(), "FILE_PART_") && ends_with(status.message(), "_MISSING")) {
// TODO support FILE_PART_*_MISSING
}
td_->file_manager_->delete_partial_remote_location(file_id_);
td_->notification_settings_manager_->reload_saved_ringtones(Auto());
promise_.set_error(std::move(status));
}
};
class SaveRingtoneQuery final : public Td::ResultHandler {
FileId file_id_;
string file_reference_;
@ -394,8 +441,28 @@ class ResetNotifySettingsQuery final : public Td::ResultHandler {
}
};
class NotificationSettingsManager::UploadRingtoneCallback final : public FileManager::UploadCallback {
public:
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
send_closure_later(G()->notification_settings_manager(), &NotificationSettingsManager::on_upload_ringtone, file_id,
std::move(input_file));
}
void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
UNREACHABLE();
}
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
UNREACHABLE();
}
void on_upload_error(FileId file_id, Status error) final {
send_closure_later(G()->notification_settings_manager(), &NotificationSettingsManager::on_upload_ringtone_error,
file_id, std::move(error));
}
};
NotificationSettingsManager::NotificationSettingsManager(Td *td, ActorShared<> parent)
: td_(td), parent_(std::move(parent)) {
upload_ringtone_callback_ = std::make_shared<UploadRingtoneCallback>();
scope_unmute_timeout_.set_callback(on_scope_unmute_timeout_callback);
scope_unmute_timeout_.set_callback_data(static_cast<void *>(this));
}
@ -755,7 +822,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr<td_api::
FileId file_id = r_file_id.ok();
auto file_view = td_->file_manager_->get_file_view(file_id);
CHECK(!file_view.empty());
if (file_view.has_remote_location()) {
if (file_view.has_remote_location() && !file_view.is_encrypted()) {
CHECK(file_view.remote_location().is_document());
if (file_view.main_remote_location().is_web()) {
return promise.set_error(Status::Error(400, "Can't use web document as notification sound"));
@ -798,7 +865,119 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr<td_api::
return;
}
promise.set_error(Status::Error(400, "Unsupported"));
auto download_file_id = td_->file_manager_->dup_file_id(file_id);
file_id = td_->file_manager_
->register_generate(FileType::Ringtone, FileLocationSource::FromServer, file_view.suggested_path(),
PSTRING() << "#file_id#" << download_file_id.get(), DialogId(), file_view.size())
.ok();
upload_ringtone(file_id, false, std::move(promise));
}
void NotificationSettingsManager::upload_ringtone(FileId file_id, bool is_reupload,
Promise<td_api::object_ptr<td_api::notificationSound>> &&promise,
vector<int> bad_parts) {
CHECK(file_id.is_valid());
LOG(INFO) << "Ask to upload ringtone " << file_id;
bool is_inserted =
being_uploaded_ringtones_.emplace(file_id, UploadedRingtone{is_reupload, std::move(promise)}).second;
CHECK(is_inserted);
// TODO use force_reupload if is_reupload
td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_ringtone_callback_, 32, 0);
}
void NotificationSettingsManager::on_upload_ringtone(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file) {
LOG(INFO) << "File " << file_id << " has been uploaded";
auto it = being_uploaded_ringtones_.find(file_id);
if (it == being_uploaded_ringtones_.end()) {
// just in case, as in on_upload_media
return;
}
bool is_reupload = it->second.is_reupload;
auto promise = std::move(it->second.promise);
being_uploaded_ringtones_.erase(it);
FileView file_view = td_->file_manager_->get_file_view(file_id);
CHECK(!file_view.is_encrypted());
CHECK(file_view.get_type() == FileType::Ringtone);
if (input_file == nullptr && file_view.has_remote_location()) {
if (file_view.main_remote_location().is_web()) {
return promise.set_error(Status::Error(400, "Can't use web document as notification sound"));
}
if (is_reupload) {
return promise.set_error(Status::Error(400, "Failed to reupload the file"));
}
send_save_ringtone_query(
file_view.file_id(), false,
PromiseCreator::lambda(
[actor_id = actor_id(this), file_id = file_view.file_id(), promise = std::move(promise)](
Result<telegram_api::object_ptr<telegram_api::account_SavedRingtone>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &NotificationSettingsManager::on_add_saved_ringtone, file_id,
result.move_as_ok(), std::move(promise));
}
}));
return;
}
CHECK(input_file != nullptr);
CHECK(input_file->get_id() == telegram_api::inputFile::ID);
const PathView path_view(static_cast<const telegram_api::inputFile *>(input_file.get())->name_);
auto file_name = path_view.file_name().str();
auto mime_type = MimeType::from_extension(path_view.extension());
auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](
Result<telegram_api::object_ptr<telegram_api::Document>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &NotificationSettingsManager::on_upload_saved_ringtone, result.move_as_ok(),
std::move(promise));
}
});
td_->create_handler<UploadRingtoneQuery>(std::move(query_promise))
->send(file_id, std::move(input_file), file_name, mime_type);
}
void NotificationSettingsManager::on_upload_ringtone_error(FileId file_id, Status status) {
LOG(INFO) << "File " << file_id << " has upload error " << status;
CHECK(status.is_error());
auto it = being_uploaded_ringtones_.find(file_id);
if (it == being_uploaded_ringtones_.end()) {
// just in case
return;
}
auto promise = std::move(it->second.promise);
being_uploaded_ringtones_.erase(it);
promise.set_error(std::move(status));
}
void NotificationSettingsManager::on_upload_saved_ringtone(
telegram_api::object_ptr<telegram_api::Document> &&saved_ringtone,
Promise<td_api::object_ptr<td_api::notificationSound>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, file_id, get_ringtone(std::move(saved_ringtone)));
reload_saved_ringtones(PromiseCreator::lambda([actor_id = actor_id(this), file_id,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &NotificationSettingsManager::on_add_saved_ringtone, file_id, nullptr, std::move(promise));
}
}));
}
void NotificationSettingsManager::on_add_saved_ringtone(

View File

@ -20,6 +20,8 @@
#include "td/utils/FlatHashMap.h"
#include "td/utils/Status.h"
#include <memory>
namespace td {
struct BinlogEvent;
@ -93,6 +95,8 @@ class NotificationSettingsManager final : public Actor {
private:
class UpdateScopeNotificationSettingsOnServerLogEvent;
class UploadRingtoneCallback;
void start_up() final;
void tear_down() final;
@ -105,6 +109,16 @@ class NotificationSettingsManager final : public Actor {
Result<FileId> get_ringtone(telegram_api::object_ptr<telegram_api::Document> &&ringtone) const;
void upload_ringtone(FileId file_id, bool is_reupload,
Promise<td_api::object_ptr<td_api::notificationSound>> &&promise, vector<int> bad_parts = {});
void on_upload_ringtone(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file);
void on_upload_ringtone_error(FileId file_id, Status status);
void on_upload_saved_ringtone(telegram_api::object_ptr<telegram_api::Document> &&saved_ringtone,
Promise<td_api::object_ptr<td_api::notificationSound>> &&promise);
void on_add_saved_ringtone(FileId file_id,
telegram_api::object_ptr<telegram_api::account_SavedRingtone> &&saved_ringtone,
Promise<td_api::object_ptr<td_api::notificationSound>> &&promise);
@ -154,6 +168,18 @@ class NotificationSettingsManager final : public Actor {
int64 saved_ringtone_hash_ = 0;
vector<FileId> saved_ringtone_file_ids_;
std::shared_ptr<UploadRingtoneCallback> upload_ringtone_callback_;
struct UploadedRingtone {
bool is_reupload;
Promise<td_api::object_ptr<td_api::notificationSound>> promise;
UploadedRingtone(bool is_reupload, Promise<td_api::object_ptr<td_api::notificationSound>> promise)
: is_reupload(is_reupload), promise(std::move(promise)) {
}
};
FlatHashMap<FileId, UploadedRingtone, FileIdHash> being_uploaded_ringtones_;
vector<Promise<Unit>> reload_saved_ringtone_queries_;
FlatHashMap<DialogId, vector<Promise<Unit>>, DialogIdHash> get_dialog_notification_settings_queries_;

View File

@ -915,7 +915,7 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
break;
case FileType::Ringtone:
if (extension != "ogg" && extension != "oga" && extension != "mp3" && extension != "mpeg3") {
return fix_file_extension(file_name, "notification_tone", "mp3");
return fix_file_extension(file_name, "notification_sound", "mp3");
}
break;
case FileType::Document: