diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 7a84b94c..2f3563c0 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -772,13 +772,16 @@ class SearchDialogsNearbyQuery : public Td::ResultHandler { : promise_(std::move(promise)) { } - void send(const Location &location, bool from_background) { + void send(const Location &location, bool from_background, int32 expire_date) { int32 flags = 0; if (from_background) { flags |= telegram_api::contacts_getLocated::BACKGROUND_MASK; } - send_query(G()->net_query_creator().create( - create_storer(telegram_api::contacts_getLocated(flags, false /*ignored*/, location.get_input_geo_point(), 0)))); + if (expire_date != -1) { + flags |= telegram_api::contacts_getLocated::SELF_EXPIRES_MASK; + } + send_query(G()->net_query_creator().create(create_storer( + telegram_api::contacts_getLocated(flags, false /*ignored*/, location.get_input_geo_point(), expire_date)))); } void on_result(uint64 id, BufferSlice packet) override { @@ -2694,6 +2697,22 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent was_online_local_ = G()->unix_time_cached() - 1; } + location_visibility_expire_date_ = + to_integer(G()->td_db()->get_binlog_pmc()->get("location_visibility_expire_date")); + if (location_visibility_expire_date_ != 0 && location_visibility_expire_date_ <= G()->unix_time()) { + location_visibility_expire_date_ = 0; + G()->td_db()->get_binlog_pmc()->erase("location_visibility_expire_date"); + } + auto pending_location_visibility_expire_date_string = + G()->td_db()->get_binlog_pmc()->get("pending_location_visibility_expire_date"); + if (!pending_location_visibility_expire_date_string.empty()) { + pending_location_visibility_expire_date_ = to_integer(pending_location_visibility_expire_date_string); + try_send_set_location_visibility_query(); + } + update_is_location_visible(); + LOG(INFO) << "Loaded location_visibility_expire_date = " << location_visibility_expire_date_ + << " and pending_location_visibility_expire_date = " << pending_location_visibility_expire_date_; + user_online_timeout_.set_callback(on_user_online_timeout_callback); user_online_timeout_.set_callback_data(static_cast(this)); @@ -4823,12 +4842,14 @@ void ContactsManager::search_dialogs_nearby(const Location &location, if (location.empty()) { return promise.set_error(Status::Error(400, "Invalid location specified")); } + last_user_location_ = location; + try_send_set_location_visibility_query(); auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)]( Result> result) mutable { send_closure(actor_id, &ContactsManager::on_get_dialogs_nearby, std::move(result), std::move(promise)); }); - td_->create_handler(std::move(query_promise))->send(location, false); + td_->create_handler(std::move(query_promise))->send(location, false, -1); } vector> ContactsManager::get_chats_nearby_object( @@ -4867,13 +4888,22 @@ void ContactsManager::on_get_dialogs_nearby(Resultupdates_) { if (update_ptr->get_id() != telegram_api::updatePeerLocated::ID) { LOG(ERROR) << "Receive unexpected " << to_string(update); continue; } - on_update_peer_located(std::move(static_cast(update_ptr.get())->peers_), false); + auto expire_date = on_update_peer_located( + std::move(static_cast(update_ptr.get())->peers_), false); + if (expire_date != -1) { + location_visibility_expire_date = expire_date; + } + } + if (location_visibility_expire_date != location_visibility_expire_date_) { + set_location_visibility_expire_date(location_visibility_expire_date); + update_is_location_visible(); } std::sort(users_nearby_.begin(), users_nearby_.end()); @@ -4884,13 +4914,84 @@ void ContactsManager::on_get_dialogs_nearby(Result> &&peers, - bool from_update) { +void ContactsManager::set_location_visibility() { + bool is_location_visible = G()->shared_config().get_option_boolean("is_location_visible"); + auto pending_location_visibility_expire_date = is_location_visible ? std::numeric_limits::max() : 0; + if (pending_location_visibility_expire_date_ == -1 && + pending_location_visibility_expire_date == location_visibility_expire_date_) { + return; + } + if (pending_location_visibility_expire_date_ != pending_location_visibility_expire_date) { + pending_location_visibility_expire_date_ = pending_location_visibility_expire_date; + G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date", + to_string(pending_location_visibility_expire_date)); + update_is_location_visible(); + } + try_send_set_location_visibility_query(); +} + +void ContactsManager::try_send_set_location_visibility_query() { + if (G()->close_flag()) { + return; + } + if (pending_location_visibility_expire_date_ == -1) { + return; + } + + if (is_set_location_visibility_request_sent_) { + return; + } + if (pending_location_visibility_expire_date_ != 0 && last_user_location_.empty()) { + return; + } + + is_set_location_visibility_request_sent_ = true; + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), set_expire_date = pending_location_visibility_expire_date_]( + Result> result) { + send_closure(actor_id, &ContactsManager::on_set_location_visibility_expire_date, set_expire_date, + result.is_ok() ? 0 : result.error().code()); + }); + td_->create_handler(std::move(query_promise)) + ->send(last_user_location_, true, pending_location_visibility_expire_date_); +} + +void ContactsManager::on_set_location_visibility_expire_date(int32 set_expire_date, int32 error_code) { + bool success = error_code == 0; + is_set_location_visibility_request_sent_ = false; + + if (set_expire_date != pending_location_visibility_expire_date_) { + try_send_set_location_visibility_query(); + return; + } + + if (success) { + set_location_visibility_expire_date(pending_location_visibility_expire_date_); + } else { + if (G()->close_flag()) { + // request will be re-sent after restart + return; + } + if (error_code != 406) { + LOG(ERROR) << "Failed to set location visibility expire date to " << pending_location_visibility_expire_date_; + } + } + G()->td_db()->get_binlog_pmc()->erase("pending_location_visibility_expire_date"); + pending_location_visibility_expire_date_ = -1; + update_is_location_visible(); +} + +int32 ContactsManager::on_update_peer_located(vector> &&peers, + bool from_update) { auto now = G()->unix_time(); bool need_update = false; + int32 location_visibility_expire_date = -1; for (auto &peer_located_ptr : peers) { if (peer_located_ptr->get_id() == telegram_api::peerSelfLocated::ID) { - // auto peer_self_located = telegram_api::move_object_as(peer_located_ptr); + auto peer_self_located = telegram_api::move_object_as(peer_located_ptr); + if (peer_self_located->expires_ == 0 || peer_self_located->expires_ > G()->unix_time()) { + location_visibility_expire_date = peer_self_located->expires_; + } continue; } @@ -4969,6 +5070,27 @@ void ContactsManager::on_update_peer_located(vectortd_db()->get_binlog_pmc()->erase("location_visibility_expire_date"); + } else { + G()->td_db()->get_binlog_pmc()->set("location_visibility_expire_date", to_string(expire_date)); + } +} + +void ContactsManager::update_is_location_visible() { + auto expire_date = pending_location_visibility_expire_date_ != -1 ? pending_location_visibility_expire_date_ + : location_visibility_expire_date_; + G()->shared_config().set_option_boolean("is_location_visible", expire_date != 0); } void ContactsManager::set_profile_photo(const tl_object_ptr &input_photo, Promise &&promise) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index f2b4de18..fa682902 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -196,7 +196,7 @@ class ContactsManager : public Actor { void on_update_channel_default_permissions(ChannelId channel_id, RestrictedRights default_permissions); void on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count); - void on_update_peer_located(vector> &&peers, bool from_update); + int32 on_update_peer_located(vector> &&peers, bool from_update); void on_update_dialog_administrators(DialogId dialog_id, vector &&administrators, bool have_access); @@ -313,6 +313,8 @@ class ContactsManager : public Actor { void search_dialogs_nearby(const Location &location, Promise> &&promise); + void set_location_visibility(); + void set_profile_photo(const tl_object_ptr &input_photo, Promise &&promise); void delete_profile_photo(int64 profile_photo_id, Promise &&promise); @@ -1238,6 +1240,14 @@ class ContactsManager : public Actor { void on_get_dialogs_nearby(Result> result, Promise> &&promise); + void try_send_set_location_visibility_query(); + + void on_set_location_visibility_expire_date(int32 set_expire_date, int32 error_code); + + void set_location_visibility_expire_date(int32 expire_date); + + void update_is_location_visible(); + static bool is_channel_public(const Channel *c); static bool is_valid_invite_link(const string &invite_link); @@ -1427,6 +1437,11 @@ class ContactsManager : public Actor { vector channels_nearby_; std::unordered_set all_users_nearby_; + int32 location_visibility_expire_date_ = 0; + int32 pending_location_visibility_expire_date_ = -1; + bool is_set_location_visibility_request_sent_ = false; + Location last_user_location_; + std::unordered_map linked_channel_ids_; std::unordered_set restricted_user_ids_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 610ca22a..607ac9de 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6758,6 +6758,10 @@ void Td::on_request(uint64 id, td_api::setOption &request) { std::move(promise)); return; } + if (set_boolean_option("is_location_visible")) { + contacts_manager_->set_location_visibility(); + return; + } break; case 'l': if (!is_bot && set_string_option("language_pack_database_path", [](Slice value) { return true; })) {