фух блять, сделал нормальную загрузку чатов, я в такое говно окунулся это пиздец. НАХУЯ НАМ ЗАПРОС КОТОРЫЙ ДАЕТ ТОЛЬКО ИЗБРАННЫЕ НАХУЯ НАМ 3 РАЗНЫХ КОНФЛИКТУЮЩИХ МЕЖДУ СОБОЙ ФУНКЦИИ ДЕЛАЮЩИХ ОДНО И ТОЖЕ НАХУЯ НАМ ПОВТОРНОЕ ПОЛНОЕ ПЕРЕПОДКЛЮЧЕНИЕ ПО СТРИМУ НАХУЯ НАМ ЖДАТЬ ДРУГИЕ ЗАПРОСЫ ЧТОБЫ ПОКАЗАТЬ ЧАТЫ НАХУЯ НАМ КОМЕТА

This commit is contained in:
jganenok
2025-12-01 20:16:01 +07:00
parent 11f974c477
commit f367eb9824
3 changed files with 96 additions and 171 deletions

View File

@@ -326,102 +326,21 @@ extension ApiServiceChats on ApiService {
}
Future<Map<String, dynamic>> getChatsOnly({bool force = false}) async {
if (authToken == null) {
await _loadTokenFromAccountManager();
}
if (authToken == null) throw Exception("Auth token not found");
// Эта функция теперь НЕ делает специальных запросов к серверу
// (вроде opcode 48 с chatIds:[0]) и не "ломает" глобальный кэш чатов.
//
// Использование:
// - без force: просто возвращаем последний снапшот, который уже
// был получен через getChatsAndContacts / кэш;
// - с force: пробрасываем запрос в getChatsAndContacts(force: true),
// чтобы получить полный список чатов.
if (!force && _lastChatsPayload != null && _lastChatsAt != null) {
if (DateTime.now().difference(_lastChatsAt!) < _chatsCacheTtl) {
return _lastChatsPayload!;
}
if (!force && _lastChatsPayload != null) {
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 {
// Используем opcode 48 для запроса конкретных чатов
// chatIds:[0] - это "Избранное" (Saved Messages)
final payload = {
"chatIds": [0],
};
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)));
}
List<dynamic> contactListJson = [];
if (contactIds.isNotEmpty) {
final int contactSeq = _sendMessage(32, {
"contactIds": contactIds.toList(),
});
final contactResponse = await messages.firstWhere(
(msg) => msg['seq'] == contactSeq,
);
contactListJson = contactResponse['payload']?['contacts'] ?? [];
}
final result = {
'chats': chatListJson,
'contacts': contactListJson,
'profile': null,
'presence': null,
};
_lastChatsPayload = result;
final List<Contact> contacts = contactListJson
.map((json) => Contact.fromJson(json as Map<String, dynamic>))
.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('Ошибка получения чатов через opcode 48: $e');
rethrow;
}
// Если нужно именно "обновить" — вызываем полноценную синхронизацию.
return getChatsAndContacts(force: true);
}
Future<Map<String, dynamic>> getChatsAndContacts({bool force = false}) async {

View File

@@ -224,7 +224,14 @@ extension ApiServiceConnection on ApiService {
if (_channel == null) {
throw Exception('WebSocket is not connected. Connect first.');
}
_log('➡️ SEND (raw): $jsonString');
try {
final decoded = jsonDecode(jsonString) as Map<String, dynamic>;
final opcode = decoded['opcode'];
final payload = decoded['payload'];
_log('➡️ SEND: opcode=$opcode, payload=$payload');
} catch (_) {
_log('➡️ SEND (raw): $jsonString');
}
_channel!.sink.add(jsonString);
}
@@ -250,7 +257,7 @@ extension ApiServiceConnection on ApiService {
final encodedMessage = jsonEncode(message);
_log('➡️ SEND (custom): $encodedMessage');
_log('➡️ SEND: opcode=${message['opcode']}, payload=${message['payload']}');
print('Отправляем кастомное сообщение (seq: $currentSeq): $encodedMessage');
_channel!.sink.add(encodedMessage);
@@ -273,19 +280,8 @@ extension ApiServiceConnection on ApiService {
final encodedMessage = jsonEncode(message);
if (opcode == 1) {
_log('➡️ SEND (ping) seq: $_seq');
} else if (opcode == 18 || opcode == 19) {
Map<String, dynamic> loggablePayload = Map.from(payload);
if (loggablePayload.containsKey('token')) {
String token = loggablePayload['token'] as String;
loggablePayload['token'] = token.length > 8
? '${token.substring(0, 4)}...${token.substring(token.length - 4)}'
: '***';
}
final loggableMessage = {...message, 'payload': loggablePayload};
_log('➡️ SEND: ${jsonEncode(loggableMessage)}');
} else {
_log('➡️ SEND: $encodedMessage');
_log('➡️ SEND: opcode=$opcode, payload=$payload');
}
print('Отправляем сообщение (seq: $_seq): $encodedMessage');
_channel!.sink.add(encodedMessage);
@@ -293,47 +289,35 @@ extension ApiServiceConnection on ApiService {
}
void _listen() async {
_streamSubscription?.cancel();
_streamSubscription = _channel?.stream.listen(
if (_channel == null) {
return;
}
// Если уже есть активная подписка на текущий канал, не создаём вторую.
if (_streamSubscription != null) {
return;
}
_streamSubscription = _channel!.stream.listen(
(message) {
if (message == null) return;
if (message is String && message.trim().isEmpty) {
return;
}
String loggableMessage = message;
try {
final decoded = jsonDecode(message) as Map<String, dynamic>;
if (decoded['opcode'] == 2) {
final opcode = decoded['opcode'];
if (opcode == 2) {
_healthMonitor.onPongReceived();
loggableMessage = '⬅️ RECV (pong) seq: ${decoded['seq']}';
_log('⬅️ RECV (pong) seq: ${decoded['seq']}');
} else {
Map<String, dynamic> loggableDecoded = Map.from(decoded);
bool wasModified = false;
if (loggableDecoded.containsKey('payload') &&
loggableDecoded['payload'] is Map) {
Map<String, dynamic> payload = Map.from(
loggableDecoded['payload'],
);
if (payload.containsKey('token')) {
String token = payload['token'] as String;
payload['token'] = token.length > 8
? '${token.substring(0, 4)}...${token.substring(token.length - 4)}'
: '***';
loggableDecoded['payload'] = payload;
wasModified = true;
}
}
if (wasModified) {
loggableMessage = '⬅️ RECV: ${jsonEncode(loggableDecoded)}';
} else {
loggableMessage = '⬅️ RECV: $message';
}
final payload = decoded['payload'];
_log('⬅️ RECV: opcode=$opcode, payload=$payload');
}
} catch (_) {
loggableMessage = '⬅️ RECV (raw): $message';
_log('⬅️ RECV (raw): $message');
}
_log(loggableMessage);
try {
final decodedMessage = message is String