tdesktop/Telegram/SourceFiles/support/support_helper.cpp

221 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