mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
220 lines
5.2 KiB
C++
220 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
|
|
*/
|
|
#include "support/support_helper.h"
|
|
|
|
#include "dialogs/dialogs_key.h"
|
|
#include "data/data_drafts.h"
|
|
#include "history/history.h"
|
|
#include "window/window_controller.h"
|
|
#include "auth_session.h"
|
|
#include "observer_peer.h"
|
|
#include "apiwrap.h"
|
|
|
|
namespace Support {
|
|
namespace {
|
|
|
|
constexpr auto kOccupyFor = TimeId(60);
|
|
constexpr auto kReoccupyEach = 30 * TimeMs(1000);
|
|
|
|
uint32 OccupationTag() {
|
|
return uint32(Sandbox::UserTag() & 0xFFFFFFFFU);
|
|
}
|
|
|
|
Data::Draft OccupiedDraft() {
|
|
const auto now = unixtime(), till = now + kOccupyFor;
|
|
return {
|
|
TextWithTags{ "t:"
|
|
+ QString::number(till)
|
|
+ ";u:"
|
|
+ QString::number(OccupationTag()) },
|
|
MsgId(0),
|
|
MessageCursor(),
|
|
false
|
|
};
|
|
}
|
|
|
|
uint32 ParseOccupationTag(History *history) {
|
|
if (!history) {
|
|
return 0;
|
|
}
|
|
const auto draft = history->cloudDraft();
|
|
if (!draft) {
|
|
return 0;
|
|
}
|
|
const auto &text = draft->textWithTags.text;
|
|
#ifndef OS_MAC_OLD
|
|
const auto parts = text.splitRef(';');
|
|
#else // OS_MAC_OLD
|
|
const auto parts = text.split(';');
|
|
#endif // OS_MAC_OLD
|
|
auto valid = false;
|
|
auto result = uint32();
|
|
for (const auto &part : parts) {
|
|
if (part.startsWith(qstr("t:"))) {
|
|
if (part.mid(2).toInt() >= unixtime()) {
|
|
valid = true;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else if (part.startsWith(qstr("u:"))) {
|
|
result = part.mid(2).toUInt();
|
|
}
|
|
}
|
|
return valid ? result : 0;
|
|
}
|
|
|
|
TimeId OccupiedBySomeoneTill(History *history) {
|
|
if (!history) {
|
|
return 0;
|
|
}
|
|
const auto draft = history->cloudDraft();
|
|
if (!draft) {
|
|
return 0;
|
|
}
|
|
const auto &text = draft->textWithTags.text;
|
|
#ifndef OS_MAC_OLD
|
|
const auto parts = text.splitRef(';');
|
|
#else // OS_MAC_OLD
|
|
const auto parts = text.split(';');
|
|
#endif // OS_MAC_OLD
|
|
auto valid = false;
|
|
auto result = TimeId();
|
|
for (const auto &part : parts) {
|
|
if (part.startsWith(qstr("t:"))) {
|
|
if (part.mid(2).toInt() >= unixtime()) {
|
|
result = part.mid(2).toInt();
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else if (part.startsWith(qstr("u:"))) {
|
|
if (part.mid(2).toUInt() != OccupationTag()) {
|
|
valid = true;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return valid ? result : 0;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Helper::Helper(not_null<AuthSession*> session)
|
|
: _session(session)
|
|
, _templates(_session)
|
|
, _reoccupyTimer([=] { reoccupy(); })
|
|
, _checkOccupiedTimer([=] { checkOccupiedChats(); }) {
|
|
}
|
|
|
|
void Helper::registerWindow(not_null<Window::Controller*> controller) {
|
|
controller->activeChatValue(
|
|
) | rpl::map([](Dialogs::Key key) {
|
|
return key.history();
|
|
}) | rpl::distinct_until_changed(
|
|
) | rpl::start_with_next([=](History *history) {
|
|
updateOccupiedHistory(controller, history);
|
|
}, controller->lifetime());
|
|
}
|
|
|
|
void Helper::cloudDraftChanged(not_null<History*> history) {
|
|
chatOccupiedUpdated(history);
|
|
if (history != _occupiedHistory) {
|
|
return;
|
|
}
|
|
if (!IsOccupiedByMe(_occupiedHistory)) {
|
|
occupyInDraft();
|
|
}
|
|
}
|
|
|
|
void Helper::chatOccupiedUpdated(not_null<History*> history) {
|
|
if (const auto till = OccupiedBySomeoneTill(history)) {
|
|
_occupiedChats[history] = till + 2;
|
|
Notify::peerUpdatedDelayed(
|
|
history->peer,
|
|
Notify::PeerUpdate::Flag::OccupiedChanged);
|
|
checkOccupiedChats();
|
|
} else if (_occupiedChats.take(history)) {
|
|
Notify::peerUpdatedDelayed(
|
|
history->peer,
|
|
Notify::PeerUpdate::Flag::OccupiedChanged);
|
|
}
|
|
}
|
|
|
|
void Helper::checkOccupiedChats() {
|
|
const auto now = unixtime();
|
|
while (!_occupiedChats.empty()) {
|
|
const auto nearest = ranges::min_element(
|
|
_occupiedChats,
|
|
std::less<>(),
|
|
[](const auto &pair) { return pair.second; });
|
|
if (nearest->second <= now) {
|
|
const auto history = nearest->first;
|
|
_occupiedChats.erase(nearest);
|
|
Notify::peerUpdatedDelayed(
|
|
history->peer,
|
|
Notify::PeerUpdate::Flag::OccupiedChanged);
|
|
} else {
|
|
_checkOccupiedTimer.callOnce(
|
|
(nearest->second - now) * TimeMs(1000));
|
|
return;
|
|
}
|
|
}
|
|
_checkOccupiedTimer.cancel();
|
|
}
|
|
|
|
void Helper::updateOccupiedHistory(
|
|
not_null<Window::Controller*> controller,
|
|
History *history) {
|
|
if (IsOccupiedByMe(_occupiedHistory)) {
|
|
_occupiedHistory->clearCloudDraft();
|
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
|
}
|
|
_occupiedHistory = history;
|
|
occupyInDraft();
|
|
}
|
|
|
|
void Helper::occupyInDraft() {
|
|
if (_occupiedHistory && !IsOccupiedBySomeone(_occupiedHistory)) {
|
|
const auto draft = OccupiedDraft();
|
|
_occupiedHistory->createCloudDraft(&draft);
|
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
|
_reoccupyTimer.callEach(kReoccupyEach);
|
|
}
|
|
}
|
|
|
|
void Helper::reoccupy() {
|
|
if (IsOccupiedByMe(_occupiedHistory)) {
|
|
const auto draft = OccupiedDraft();
|
|
_occupiedHistory->createCloudDraft(&draft);
|
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
|
}
|
|
}
|
|
|
|
Templates &Helper::templates() {
|
|
return _templates;
|
|
}
|
|
|
|
bool IsOccupiedByMe(History *history) {
|
|
if (const auto tag = ParseOccupationTag(history)) {
|
|
return (tag == OccupationTag());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsOccupiedBySomeone(History *history) {
|
|
if (const auto tag = ParseOccupationTag(history)) {
|
|
return (tag != OccupationTag());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QString ChatOccupiedString() {
|
|
return QString::fromUtf8("\xe2\x9c\x8b\xef\xb8\x8f chat taken");
|
|
}
|
|
|
|
} // namespace Support
|