Кэширование ID пользователей из чатов (на 24 часа)

This commit is contained in:
needle10
2025-11-22 21:38:48 +03:00
parent bf995d8358
commit 321720cd0a
15 changed files with 669 additions and 238 deletions

View File

@@ -190,7 +190,6 @@ extension ApiServiceAuth on ApiService {
authToken = currentAccount.token;
userId = currentAccount.userId;
_messageCache.clear();
_messageQueue.clear();
_lastChatsPayload = null;
_chatsFetchedInThisSession = false;
@@ -257,4 +256,3 @@ extension ApiServiceAuth on ApiService {
}
}
}

View File

@@ -1,6 +1,119 @@
part of 'api_service.dart';
extension ApiServiceChats on ApiService {
Future<void> _sendAuthRequestAfterHandshake() async {
if (authToken == null) {
print("Токен не найден, пропускаем автоматическую авторизацию");
return;
}
if (_chatsFetchedInThisSession) {
print("Авторизация уже выполнена в этой сессии, пропускаем");
return;
}
try {
await _ensureCacheServicesInitialized();
final prefs = await SharedPreferences.getInstance();
final deviceId =
prefs.getString('spoof_deviceid') ?? generateRandomDeviceId();
if (prefs.getString('spoof_deviceid') == null) {
await prefs.setString('spoof_deviceid', deviceId);
}
final payload = {
"chatsCount": 100,
"chatsSync": 0,
"contactsSync": 0,
"draftsSync": 0,
"interactive": true,
"presenceSync": 0,
"token": authToken,
};
if (userId != null) {
payload["userId"] = userId;
}
print("Автоматически отправляем opcode 19 для авторизации...");
final int chatSeq = _sendMessage(19, payload);
final chatResponse = await messages.firstWhere(
(msg) => msg['seq'] == chatSeq,
);
if (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(
"[_sendAuthRequestAfterHandshake] ✅ Профиль и ID пользователя найдены. ID: ${contactProfile['id']}. ЗАПУСКАЕМ АНАЛИТИКУ.",
);
_userId = contactProfile['id'];
_sessionId = DateTime.now().millisecondsSinceEpoch;
_lastActionTime = _sessionId;
sendNavEvent('COLD_START');
_sendInitialSetupRequests();
}
if (_onlineCompleter != null && !_onlineCompleter!.isCompleted) {
_onlineCompleter!.complete();
}
final chatListJson = chatResponse['payload']?['chats'] ?? [];
final contactListJson = chatResponse['payload']?['contacts'] ?? [];
final presence = chatResponse['payload']?['presence'];
final config = chatResponse['payload']?['config'];
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;
}
} catch (e) {
print("Ошибка при автоматической авторизации: $e");
}
}
void createGroup(String name, List<int> participantIds) {
final payload = {"name": name, "participantIds": participantIds};
_sendMessage(48, payload);
@@ -357,22 +470,29 @@ extension ApiServiceChats on ApiService {
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 =
chatResponse['payload']?['contacts'] ?? [];
if (contactListJson.isEmpty) {
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)));
}
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 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);
}

View File

@@ -363,11 +363,15 @@ extension ApiServiceConnection on ApiService {
);
_startHealthMonitoring();
if (_onlineCompleter != null && !_onlineCompleter!.isCompleted) {
_onlineCompleter!.complete();
}
_startPinging();
_processMessageQueue();
if (authToken != null && !_chatsFetchedInThisSession) {
print(
"Токен найден, автоматически запускаем авторизацию (opcode 19)...",
);
unawaited(_sendAuthRequestAfterHandshake());
}
}
if (decodedMessage is Map && decodedMessage['cmd'] == 3) {
@@ -670,8 +674,6 @@ extension ApiServiceConnection on ApiService {
_onlineCompleter = Completer<void>();
_chatsFetchedInThisSession = false;
clearAllCaches();
_currentUrlIndex = 0;
_reconnectDelaySeconds = (_reconnectDelaySeconds * 2).clamp(1, 30);
@@ -721,7 +723,6 @@ extension ApiServiceConnection on ApiService {
_currentUrlIndex = 0;
_onlineCompleter = Completer<void>();
clearAllCaches();
_messageQueue.clear();
_presenceData.clear();

View File

@@ -105,6 +105,20 @@ extension ApiServiceContacts on ApiService {
return;
}
if (!_isSessionOnline || !_isSessionReady) {
print(
'ApiService: сессия еще не готова для запроса заблокированных контактов, ждем...',
);
await waitUntilOnline();
if (!_isSessionReady) {
print(
'ApiService: сессия все еще не готова после ожидания, отменяем запрос',
);
return;
}
}
_isLoadingBlockedContacts = true;
print('ApiService: запрашиваем заблокированные контакты');
_sendMessage(36, {'status': 'BLOCKED', 'count': 100, 'from': 0});
@@ -278,12 +292,23 @@ extension ApiServiceContacts on ApiService {
Future<List<Contact>> fetchContactsByIds(List<int> contactIds) async {
if (contactIds.isEmpty) {
print(
'⚠️ [fetchContactsByIds] Пустой список contactIds - пропускаем запрос',
);
return [];
}
print('Запрашиваем данные для ${contactIds.length} контактов...');
print(
'📡 [fetchContactsByIds] Запрашиваем данные для ${contactIds.length} контактов...',
);
print(
'📡 [fetchContactsByIds] IDs: ${contactIds.take(10).join(', ')}${contactIds.length > 10 ? '...' : ''}',
);
try {
final int contactSeq = _sendMessage(32, {"contactIds": contactIds});
print(
'📤 [fetchContactsByIds] Отправлен опкод 32 с seq=$contactSeq и ${contactIds.length} ID',
);
final contactResponse = await messages
.firstWhere((msg) => msg['seq'] == contactSeq)
@@ -291,7 +316,7 @@ extension ApiServiceContacts on ApiService {
if (contactResponse['cmd'] == 3) {
print(
"Ошибка при получении контактов по ID: ${contactResponse['payload']}",
"❌ [fetchContactsByIds] Ошибка при получении контактов: ${contactResponse['payload']}",
);
return [];
}
@@ -302,13 +327,29 @@ extension ApiServiceContacts on ApiService {
.map((json) => Contact.fromJson(json))
.toList();
print(
'📦 [fetchContactsByIds] Получено ${contacts.length} контактов из ${contactIds.length} запрошенных',
);
if (contacts.length < contactIds.length) {
final receivedIds = contacts.map((c) => c.id).toSet();
final missingIds = contactIds
.where((id) => !receivedIds.contains(id))
.toList();
print(
'⚠️ [fetchContactsByIds] Отсутствуют ${missingIds.length} контактов: ${missingIds.take(5).join(', ')}${missingIds.length > 5 ? '...' : ''}',
);
}
for (final contact in contacts) {
_contactCache[contact.id] = contact;
}
print("Получены и закэшированы данные для ${contacts.length} контактов.");
print(
"✅ [fetchContactsByIds] Закэшированы данные для ${contacts.length} контактов",
);
return contacts;
} catch (e) {
print('Исключение при получении контактов по ID: $e');
print('❌ [fetchContactsByIds] Исключение при получении контактов: $e');
return [];
}
}