Files
fuckKomet/lib/api/api_service_chats.dart

1015 lines
30 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

part of 'api_service.dart';
extension ApiServiceChats on ApiService {
void createGroup(String name, List<int> participantIds) {
final payload = {"name": name, "participantIds": participantIds};
_sendMessage(48, payload);
print('Создаем группу: $name с участниками: $participantIds');
}
void updateGroup(int chatId, {String? name, List<int>? participantIds}) {
final payload = {
"chatId": chatId,
if (name != null) "name": name,
if (participantIds != null) "participantIds": participantIds,
};
_sendMessage(272, payload);
print('Обновляем группу $chatId: $payload');
}
void createGroupWithMessage(String name, List<int> participantIds) {
final cid = DateTime.now().millisecondsSinceEpoch;
final payload = {
"message": {
"cid": cid,
"attaches": [
{
"_type": "CONTROL",
"event": "new",
"chatType": "CHAT",
"title": name,
"userIds": participantIds,
},
],
},
"notify": true,
};
_sendMessage(64, payload);
print('Создаем группу: $name с участниками: $participantIds');
}
void renameGroup(int chatId, String newName) {
final payload = {"chatId": chatId, "theme": newName};
_sendMessage(55, payload);
print('Переименовываем группу $chatId в: $newName');
}
void addGroupMember(
int chatId,
List<int> userIds, {
bool showHistory = true,
}) {
final payload = {
"chatId": chatId,
"userIds": userIds,
"showHistory": showHistory,
"operation": "add",
};
_sendMessage(77, payload);
print('Добавляем участников $userIds в группу $chatId');
}
void removeGroupMember(
int chatId,
List<int> userIds, {
int cleanMsgPeriod = 0,
}) {
final payload = {
"chatId": chatId,
"userIds": userIds,
"operation": "remove",
"cleanMsgPeriod": cleanMsgPeriod,
};
_sendMessage(77, payload);
print('Удаляем участников $userIds из группы $chatId');
}
void leaveGroup(int chatId) {
final payload = {"chatId": chatId};
_sendMessage(58, payload);
print('Выходим из группы $chatId');
}
void getGroupMembers(int chatId, {int marker = 0, int count = 50}) {
final payload = {
"type": "MEMBER",
"marker": marker,
"chatId": chatId,
"count": count,
};
_sendMessage(59, payload);
print(
'Запрашиваем участников группы $chatId (marker: $marker, count: $count)',
);
}
Future<Map<String, dynamic>> getChatsOnly({bool force = false}) async {
if (authToken == null) {
await _loadTokenFromAccountManager();
}
if (authToken == null) throw Exception("Auth token not found");
if (!force && _lastChatsPayload != null && _lastChatsAt != null) {
if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) {
return _lastChatsPayload!;
}
}
await _ensureCacheServicesInitialized();
if (!force && _lastChatsPayload == null) {
final cachedChats = await _chatCacheService.getCachedChats();
final cachedContacts = await _chatCacheService.getCachedContacts();
if (cachedChats != null &&
cachedContacts != null &&
cachedChats.isNotEmpty) {
final result = {
'chats': cachedChats,
'contacts': cachedContacts.map(_contactToMap).toList(),
'profile': null,
'presence': null,
};
_lastChatsPayload = result;
_lastChatsAt = DateTime.now();
updateContactCache(cachedContacts);
_preloadContactAvatars(cachedContacts);
return result;
}
}
try {
final payload = {"chatsCount": 100};
final int chatSeq = _sendMessage(48, payload);
final chatResponse = await messages.firstWhere(
(msg) => msg['seq'] == chatSeq,
);
final List<dynamic> chatListJson =
chatResponse['payload']?['chats'] ?? [];
if (chatListJson.isEmpty) {
final result = {'chats': [], 'contacts': [], 'profile': null};
_lastChatsPayload = result;
_lastChatsAt = DateTime.now();
return result;
}
final contactIds = <int>{};
for (var chatJson in chatListJson) {
final participants =
chatJson['participants'] as Map<String, dynamic>? ?? {};
contactIds.addAll(participants.keys.map((id) => int.parse(id)));
}
final int contactSeq = _sendMessage(32, {
"contactIds": contactIds.toList(),
});
final contactResponse = await messages.firstWhere(
(msg) => msg['seq'] == contactSeq,
);
final List<dynamic> contactListJson =
contactResponse['payload']?['contacts'] ?? [];
final result = {
'chats': chatListJson,
'contacts': contactListJson,
'profile': null,
'presence': null,
};
_lastChatsPayload = result;
final contacts = contactListJson
.map((json) => Contact.fromJson(json))
.toList();
updateContactCache(contacts);
_lastChatsAt = DateTime.now();
_preloadContactAvatars(contacts);
unawaited(
_chatCacheService.cacheChats(chatListJson.cast<Map<String, dynamic>>()),
);
unawaited(_chatCacheService.cacheContacts(contacts));
return result;
} catch (e) {
print('Ошибка получения чатов: $e');
rethrow;
}
}
Future<Map<String, dynamic>> getChatsAndContacts({bool force = false}) async {
await waitUntilOnline();
if (authToken == null) {
print("Токен авторизации не найден, требуется повторная авторизация");
throw Exception("Auth token not found - please re-authenticate");
}
await _ensureCacheServicesInitialized();
if (!force && _lastChatsPayload != null && _lastChatsAt != null) {
if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) {
return _lastChatsPayload!;
}
}
if (!force && !_chatsFetchedInThisSession && _lastChatsPayload == null) {
final cachedChats = await _chatCacheService.getCachedChats();
final cachedContacts = await _chatCacheService.getCachedContacts();
if (cachedChats != null &&
cachedContacts != null &&
cachedChats.isNotEmpty) {
final cachedResult = {
'chats': cachedChats,
'contacts': cachedContacts.map(_contactToMap).toList(),
'profile': null,
'presence': null,
};
_lastChatsPayload = cachedResult;
_lastChatsAt = DateTime.now();
updateContactCache(cachedContacts);
_preloadContactAvatars(cachedContacts);
return cachedResult;
}
}
if (_chatsFetchedInThisSession && _lastChatsPayload != null && !force) {
return _lastChatsPayload!;
}
if (_inflightChatsCompleter != null) {
return _inflightChatsCompleter!.future;
}
_inflightChatsCompleter = Completer<Map<String, dynamic>>();
if (_isSessionOnline &&
_isSessionReady &&
_lastChatsPayload != null &&
!force) {
_inflightChatsCompleter!.complete(_lastChatsPayload!);
_inflightChatsCompleter = null;
return _lastChatsPayload!;
}
try {
Map<String, dynamic> chatResponse;
final int opcode;
final Map<String, dynamic> payload;
final prefs = await SharedPreferences.getInstance();
final deviceId =
prefs.getString('spoof_deviceid') ?? generateRandomDeviceId();
if (prefs.getString('spoof_deviceid') == null) {
await prefs.setString('spoof_deviceid', deviceId);
}
if (!_chatsFetchedInThisSession) {
opcode = 19;
payload = {
"chatsCount": 100,
"chatsSync": 0,
"contactsSync": 0,
"draftsSync": 0,
"interactive": true,
"presenceSync": 0,
"token": authToken,
};
if (userId != null) {
payload["userId"] = userId;
}
} else {
return await getChatsOnly(force: force);
}
final int chatSeq = _sendMessage(opcode, payload);
chatResponse = await messages.firstWhere((msg) => msg['seq'] == chatSeq);
if (opcode == 19 && chatResponse['cmd'] == 1) {
print("✅ Авторизация (opcode 19) успешна. Сессия ГОТОВА.");
_isSessionReady = true;
_connectionStatusController.add("ready");
_updateConnectionState(
conn_state.ConnectionState.ready,
message: 'Авторизация успешна',
);
final profile = chatResponse['payload']?['profile'];
final contactProfile = profile?['contact'];
if (contactProfile != null && contactProfile['id'] != null) {
print(
"[getChatsAndContacts] ✅ Профиль и ID пользователя найдены. ID: ${contactProfile['id']}. ЗАПУСКАЕМ АНАЛИТИКУ.",
);
_userId = contactProfile['id'];
_sessionId = DateTime.now().millisecondsSinceEpoch;
_lastActionTime = _sessionId;
sendNavEvent('COLD_START');
_sendInitialSetupRequests();
} else {
print(
"[getChatsAndContacts] ❌ ВНИМАНИЕ: Профиль или ID в ответе пустой, аналитика не будет отправлена.",
);
}
if (_onlineCompleter != null && !_onlineCompleter!.isCompleted) {
_onlineCompleter!.complete();
}
_startPinging();
_processMessageQueue();
}
final profile = chatResponse['payload']?['profile'];
final presence = chatResponse['payload']?['presence'];
final config = chatResponse['payload']?['config'];
final List<dynamic> chatListJson =
chatResponse['payload']?['chats'] ?? [];
if (profile != null && authToken != null) {
try {
final accountManager = AccountManager();
await accountManager.initialize();
final currentAccount = accountManager.currentAccount;
if (currentAccount != null && currentAccount.token == authToken) {
final profileObj = Profile.fromJson(profile);
await accountManager.updateAccountProfile(
currentAccount.id,
profileObj,
);
}
} catch (e) {
print('Ошибка сохранения профиля в AccountManager: $e');
}
}
if (chatListJson.isEmpty) {
if (config != null) {
_processServerPrivacyConfig(config);
}
final result = {
'chats': [],
'contacts': [],
'profile': profile,
'config': config,
};
_lastChatsPayload = result;
_lastChatsAt = DateTime.now();
_chatsFetchedInThisSession = true;
_inflightChatsCompleter!.complete(_lastChatsPayload!);
_inflightChatsCompleter = null;
return result;
}
final contactIds = <int>{};
for (var chatJson in chatListJson) {
final participants = chatJson['participants'] as Map<String, dynamic>;
contactIds.addAll(participants.keys.map((id) => int.parse(id)));
}
final int contactSeq = _sendMessage(32, {
"contactIds": contactIds.toList(),
});
final contactResponse = await messages.firstWhere(
(msg) => msg['seq'] == contactSeq,
);
final List<dynamic> contactListJson =
contactResponse['payload']?['contacts'] ?? [];
if (presence != null) {
updatePresenceData(presence);
}
if (config != null) {
_processServerPrivacyConfig(config);
}
final result = {
'chats': chatListJson,
'contacts': contactListJson,
'profile': profile,
'presence': presence,
'config': config,
};
_lastChatsPayload = result;
final contacts = contactListJson
.map((json) => Contact.fromJson(json))
.toList();
updateContactCache(contacts);
_lastChatsAt = DateTime.now();
_preloadContactAvatars(contacts);
unawaited(
_chatCacheService.cacheChats(chatListJson.cast<Map<String, dynamic>>()),
);
unawaited(_chatCacheService.cacheContacts(contacts));
_chatsFetchedInThisSession = true;
_inflightChatsCompleter!.complete(result);
_inflightChatsCompleter = null;
return result;
} catch (e) {
final error = e;
_inflightChatsCompleter?.completeError(error);
_inflightChatsCompleter = null;
rethrow;
}
}
Future<void> _sendInitialSetupRequests() async {
print("Запускаем отправку единичных запросов при старте...");
if (!_isSessionOnline || !_isSessionReady) {
print("Сессия еще не готова, ждем...");
await waitUntilOnline();
}
await Future.delayed(const Duration(seconds: 2));
if (!_isSessionOnline || !_isSessionReady) {
print("Сессия не готова для отправки запросов, пропускаем");
return;
}
_sendMessage(272, {"folderSync": 0});
await Future.delayed(const Duration(milliseconds: 500));
_sendMessage(27, {"sync": 0, "type": "STICKER"});
await Future.delayed(const Duration(milliseconds: 500));
_sendMessage(27, {"sync": 0, "type": "FAVORITE_STICKER"});
await Future.delayed(const Duration(milliseconds: 500));
_sendMessage(79, {"forward": false, "count": 100});
await Future.delayed(const Duration(seconds: 5));
_sendMessage(26, {
"sectionId": "NEW_STICKER_SETS",
"from": 5,
"count": 100,
});
print("Единичные запросы отправлены.");
}
Future<List<Message>> getMessageHistory(
int chatId, {
bool force = false,
}) async {
await _ensureCacheServicesInitialized();
if (!force && _messageCache.containsKey(chatId)) {
print("Загружаем сообщения для чата $chatId из кэша.");
return _messageCache[chatId]!;
}
if (!force) {
final cachedMessages = await _chatCacheService.getCachedChatMessages(
chatId,
);
if (cachedMessages != null && cachedMessages.isNotEmpty) {
print(
"История сообщений для чата $chatId загружена из ChatCacheService.",
);
_messageCache[chatId] = cachedMessages;
return cachedMessages;
}
}
print("Запрашиваем историю для чата $chatId с сервера.");
final payload = {
"chatId": chatId,
"from": DateTime.now()
.add(const Duration(days: 1))
.millisecondsSinceEpoch,
"forward": 0,
"backward": 1000,
"getMessages": true,
};
try {
final int seq = _sendMessage(49, payload);
final response = await messages
.firstWhere((msg) => msg['seq'] == seq)
.timeout(const Duration(seconds: 15));
if (response['cmd'] == 3) {
final error = response['payload'];
print('Ошибка получения истории сообщений: $error');
if (error['error'] == 'proto.state') {
print(
'Ошибка состояния сессии при получении истории, переподключаемся...',
);
await reconnect();
await waitUntilOnline();
return getMessageHistory(chatId, force: true);
}
throw Exception('Ошибка получения истории: ${error['message']}');
}
final List<dynamic> messagesJson = response['payload']?['messages'] ?? [];
final messagesList =
messagesJson.map((json) => Message.fromJson(json)).toList()
..sort((a, b) => a.time.compareTo(b.time));
_messageCache[chatId] = messagesList;
_preloadMessageImages(messagesList);
unawaited(_chatCacheService.cacheChatMessages(chatId, messagesList));
return messagesList;
} catch (e) {
print('Ошибка при получении истории сообщений: $e');
return [];
}
}
Future<Map<String, dynamic>?> loadOldMessages(
int chatId,
String fromMessageId,
int count,
) async {
print(
"Запрашиваем старые сообщения для чата $chatId начиная с $fromMessageId",
);
final payload = {
"chatId": chatId,
"from": int.parse(fromMessageId),
"forward": 0,
"backward": count,
"getMessages": true,
};
try {
final int seq = _sendMessage(49, payload);
final response = await messages
.firstWhere((msg) => msg['seq'] == seq)
.timeout(const Duration(seconds: 15));
if (response['cmd'] == 3) {
final error = response['payload'];
print('Ошибка получения старых сообщений: $error');
return null;
}
return response['payload'];
} catch (e) {
print('Ошибка при получении старых сообщений: $e');
return null;
}
}
void sendNavEvent(String event, {int? screenTo, int? screenFrom}) {
if (_userId == null) return;
final now = DateTime.now().millisecondsSinceEpoch;
final Map<String, dynamic> params = {
'session_id': _sessionId,
'action_id': _actionId++,
};
switch (event) {
case 'COLD_START':
if (_isColdStartSent) return;
params['screen_to'] = 150;
params['source_id'] = 1;
_isColdStartSent = true;
break;
case 'WARM_START':
params['screen_to'] = 150;
params['screen_from'] = 1;
params['prev_time'] = _lastActionTime;
break;
case 'GO':
params['screen_to'] = screenTo;
params['screen_from'] = screenFrom;
params['prev_time'] = _lastActionTime;
break;
}
_lastActionTime = now;
_sendMessage(5, {
"events": [
{
"type": "NAV",
"event": event,
"userId": _userId,
"time": now,
"params": params,
},
],
});
}
void createFolder(
String title, {
List<int>? include,
List<dynamic>? filters,
}) {
final folderId = const Uuid().v4();
final payload = {
"id": folderId,
"title": title,
"include": include ?? [],
"filters": filters ?? [],
};
_sendMessage(274, payload);
print('Создаем папку: $title (ID: $folderId)');
}
void updateFolder(
String folderId, {
String? title,
List<int>? include,
List<dynamic>? filters,
}) {
final payload = {
"id": folderId,
if (title != null) "title": title,
if (include != null) "include": include,
if (filters != null) "filters": filters,
};
_sendMessage(274, payload);
print('Обновляем папку: $folderId');
}
void deleteFolder(String folderId) {
final payload = {
"folderIds": [folderId],
};
_sendMessage(276, payload);
print('Удаляем папку: $folderId');
}
void requestFolderSync() {
_sendMessage(272, {"folderSync": 0});
print('Запрос на обновление папок отправлен');
}
void clearCacheForChat(int chatId) {
_messageCache.remove(chatId);
if (_cacheServicesInitialized) {
unawaited(_chatCacheService.clearChatCache(chatId));
}
print("Кэш для чата $chatId очищен.");
}
void clearChatsCache() {
_lastChatsPayload = null;
_lastChatsAt = null;
print("Кэш чатов очищен.");
}
Contact? getCachedContact(int contactId) {
if (_contactCache.containsKey(contactId)) {
final contact = _contactCache[contactId]!;
print('Контакт $contactId получен из кэша: ${contact.name}');
return contact;
}
return null;
}
Future<Map<String, dynamic>> getNetworkStatistics() async {
final prefs = await SharedPreferences.getInstance();
final totalTraffic =
prefs.getDouble('network_total_traffic') ?? (150.0 * 1024 * 1024);
final messagesTraffic =
prefs.getDouble('network_messages_traffic') ?? (totalTraffic * 0.15);
final mediaTraffic =
prefs.getDouble('network_media_traffic') ?? (totalTraffic * 0.6);
final syncTraffic =
prefs.getDouble('network_sync_traffic') ?? (totalTraffic * 0.1);
final currentSpeed = _isSessionOnline ? 512.0 * 1024 : 0.0;
final ping = 25;
return {
'totalTraffic': totalTraffic,
'messagesTraffic': messagesTraffic,
'mediaTraffic': mediaTraffic,
'syncTraffic': syncTraffic,
'otherTraffic': totalTraffic * 0.15,
'currentSpeed': currentSpeed,
'isConnected': _isSessionOnline,
'connectionType': 'Wi-Fi',
'signalStrength': 85,
'ping': ping,
'jitter': 2.5,
'packetLoss': 0.01,
'hourlyStats': [],
};
}
bool isContactCacheValid() {
if (_lastContactsUpdate == null) return false;
return DateTime.now().difference(_lastContactsUpdate!) <
ApiService._contactCacheExpiry;
}
void updateContactCache(List<Contact> contacts) {
_contactCache.clear();
for (final contact in contacts) {
_contactCache[contact.id] = contact;
}
_lastContactsUpdate = DateTime.now();
print('Кэш контактов обновлен: ${contacts.length} контактов');
}
void updateCachedContact(Contact contact) {
_contactCache[contact.id] = contact;
print('Контакт ${contact.id} обновлен в кэше: ${contact.name}');
}
void clearContactCache() {
_contactCache.clear();
_lastContactsUpdate = null;
print("Кэш контактов очищен.");
}
void clearAllCaches() {
clearContactCache();
clearChatsCache();
_messageCache.clear();
clearPasswordAuthData();
if (_cacheServicesInitialized) {
unawaited(_cacheService.clear());
unawaited(_chatCacheService.clearAllChatCache());
unawaited(_avatarCacheService.clearAvatarCache());
unawaited(ImageCacheService.instance.clearCache());
}
print("Все кэши очищены из-за ошибки подключения.");
}
Future<Map<String, dynamic>> getStatistics() async {
await _ensureCacheServicesInitialized();
final cacheStats = await _cacheService.getCacheStats();
final chatCacheStats = await _chatCacheService.getChatCacheStats();
final avatarStats = await _avatarCacheService.getAvatarCacheStats();
final imageStats = await ImageCacheService.instance.getCacheStats();
return {
'api_service': {
'is_online': _isSessionOnline,
'is_ready': _isSessionReady,
'cached_chats': (_lastChatsPayload?['chats'] as List?)?.length ?? 0,
'contacts_in_memory': _contactCache.length,
'message_cache_entries': _messageCache.length,
'message_queue_length': _messageQueue.length,
},
'connection': {
'current_url': _currentUrlIndex < _wsUrls.length
? _wsUrls[_currentUrlIndex]
: null,
'reconnect_attempts': _reconnectAttempts,
'last_action_time': _lastActionTime,
},
'cache_service': cacheStats,
'chat_cache': chatCacheStats,
'avatar_cache': avatarStats,
'image_cache': imageStats,
};
}
void _preloadContactAvatars(List<Contact> contacts) {
if (!_cacheServicesInitialized || contacts.isEmpty) return;
final photoUrls = contacts.map((c) => c.photoBaseUrl).toList();
if (photoUrls.isEmpty) return;
unawaited(ImageCacheService.instance.preloadContactAvatars(photoUrls));
}
void _preloadMessageImages(List<Message> messages) {
if (!_cacheServicesInitialized || messages.isEmpty) return;
final urls = <String>{};
for (final message in messages) {
for (final attach in message.attaches) {
final url = attach['url'] ?? attach['baseUrl'];
if (url is String && url.isNotEmpty) {
urls.add(url);
}
}
}
for (final url in urls) {
unawaited(ImageCacheService.instance.preloadImage(url));
}
}
Map<String, dynamic> _contactToMap(Contact contact) {
return {
'id': contact.id,
'name': contact.name,
'firstName': contact.firstName,
'lastName': contact.lastName,
'description': contact.description,
'photoBaseUrl': contact.photoBaseUrl,
'isBlocked': contact.isBlocked,
'isBlockedByMe': contact.isBlockedByMe,
'accountStatus': contact.accountStatus,
'status': contact.status,
'options': contact.options,
};
}
void sendMessage(
int chatId,
String text, {
String? replyToMessageId,
int? cid,
}) {
final int clientMessageId = cid ?? DateTime.now().millisecondsSinceEpoch;
final payload = {
"chatId": chatId,
"message": {
"text": text,
"cid": clientMessageId,
"elements": [],
"attaches": [],
if (replyToMessageId != null)
"link": {"type": "REPLY", "messageId": replyToMessageId},
},
"notify": true,
};
clearChatsCache();
if (_isSessionOnline) {
_sendMessage(64, payload);
} else {
print("Сессия не онлайн. Сообщение добавлено в очередь.");
_messageQueue.add({'opcode': 64, 'payload': payload});
}
}
void forwardMessage(int targetChatId, String messageId, int sourceChatId) {
final int clientMessageId = DateTime.now().millisecondsSinceEpoch;
final payload = {
"chatId": targetChatId,
"message": {
"cid": clientMessageId,
"link": {
"type": "FORWARD",
"messageId": messageId,
"chatId": sourceChatId,
},
"attaches": [],
},
"notify": true,
};
if (_isSessionOnline) {
_sendMessage(64, payload);
} else {
_messageQueue.add({'opcode': 64, 'payload': payload});
}
}
Future<void> editMessage(int chatId, String messageId, String newText) async {
final payload = {
"chatId": chatId,
"messageId": messageId,
"text": newText,
"elements": [],
"attachments": [],
};
clearChatsCache();
await waitUntilOnline();
if (!_isSessionOnline) {
print('Сессия не онлайн, пытаемся переподключиться...');
await reconnect();
await waitUntilOnline();
}
Future<bool> sendOnce() async {
try {
final int seq = _sendMessage(67, payload);
final response = await messages
.firstWhere((msg) => msg['seq'] == seq)
.timeout(const Duration(seconds: 10));
if (response['cmd'] == 3) {
final error = response['payload'];
print('Ошибка редактирования сообщения: $error');
if (error['error'] == 'proto.state') {
print('Ошибка состояния сессии, переподключаемся...');
await reconnect();
await waitUntilOnline();
return false;
}
if (error['error'] == 'error.edit.invalid.message') {
print(
'Сообщение не может быть отредактировано: ${error['localizedMessage']}',
);
throw Exception(
'Сообщение не может быть отредактировано: ${error['localizedMessage']}',
);
}
return false;
}
return response['cmd'] == 1;
} catch (e) {
print('Ошибка при редактировании сообщения: $e');
return false;
}
}
for (int attempt = 0; attempt < 3; attempt++) {
print(
'Попытка редактирования сообщения $messageId (попытка ${attempt + 1}/3)',
);
bool ok = await sendOnce();
if (ok) {
print('Сообщение $messageId успешно отредактировано');
return;
}
if (attempt < 2) {
print(
'Повторяем запрос редактирования для сообщения $messageId через 2 секунды...',
);
await Future.delayed(const Duration(seconds: 2));
}
}
print('Не удалось отредактировать сообщение $messageId после 3 попыток');
}
Future<void> deleteMessage(
int chatId,
String messageId, {
bool forMe = false,
}) async {
final payload = {
"chatId": chatId,
"messageIds": [messageId],
"forMe": forMe,
};
clearChatsCache();
await waitUntilOnline();
if (!_isSessionOnline) {
print('Сессия не онлайн, пытаемся переподключиться...');
await reconnect();
await waitUntilOnline();
}
Future<bool> sendOnce() async {
try {
final int seq = _sendMessage(66, payload);
final response = await messages
.firstWhere((msg) => msg['seq'] == seq)
.timeout(const Duration(seconds: 10));
if (response['cmd'] == 3) {
final error = response['payload'];
print('Ошибка удаления сообщения: $error');
if (error['error'] == 'proto.state') {
print('Ошибка состояния сессии, переподключаемся...');
await reconnect();
await waitUntilOnline();
return false;
}
return false;
}
return response['cmd'] == 1;
} catch (e) {
print('Ошибка при удалении сообщения: $e');
return false;
}
}
for (int attempt = 0; attempt < 3; attempt++) {
print('Попытка удаления сообщения $messageId (попытка ${attempt + 1}/3)');
bool ok = await sendOnce();
if (ok) {
print('Сообщение $messageId успешно удалено');
return;
}
if (attempt < 2) {
print(
'Повторяем запрос удаления для сообщения $messageId через 2 секунды...',
);
await Future.delayed(const Duration(seconds: 2));
}
}
print('Не удалось удалить сообщение $messageId после 3 попыток');
}
void sendTyping(int chatId, {String type = "TEXT"}) {
final payload = {"chatId": chatId, "type": type};
if (_isSessionOnline) {
_sendMessage(65, payload);
}
}
}