onufitness_mobile/lib/services/agora/agora_chat_service.dart
2026-01-13 11:36:24 +05:30

210 lines
6.1 KiB
Dart

import 'package:get/get.dart';
import 'package:agora_chat_sdk/agora_chat_sdk.dart';
import 'package:onufitness/constants/data_constant.dart';
import 'dart:async';
import 'package:onufitness/controller/get_agora_token_controller.dart';
import 'package:onufitness/services/local_storage_services/shared_services.dart';
import 'package:onufitness/services/logger_service.dart';
class AgoraChatService extends GetxService {
static AgoraChatService get instance => Get.find();
final logger = LoggerService();
final String appKey = agoraChatAppKey;
Timer? _tokenRefreshTimer;
Future<AgoraChatService> init() async {
await initChatSdk();
return this;
}
Future<void> initChatSdk() async {
final options = ChatOptions(
appKey: appKey,
autoLogin: false,
isAutoDownloadThumbnail: false,
requireAck: true,
requireDeliveryAck: true,
);
try {
await ChatClient.getInstance.init(options);
// Critical: Wait for native SDK to fully initialize
await Future.delayed(Duration(milliseconds: 1500));
await ChatClient.getInstance.startCallback();
await addListener();
logger.log("Agora Chat SDK initialized successfully");
} catch (e, stackTrace) {
logger.error(
"Failed to initialize Agora Chat SDK",
error: e,
stackTrace: stackTrace,
);
rethrow;
}
}
addListener() async {
_startTokenRefreshTimer();
ChatClient.getInstance.addConnectionEventHandler(
"TOKEN_REFRESH_HANDLER",
ConnectionEventHandler(
onTokenWillExpire: () async {
await agoraChatTokenAPIcall();
var tokenSuccess = SharedServices.getAgoraUserAndRtmTokens();
var userToken = tokenSuccess!.data!.agoraUserToken.toString();
await ChatClient.getInstance.renewAgoraToken(userToken);
},
onTokenDidExpire: () async {
await agoraChatTokenAPIcall();
},
onDisconnected: () {},
onConnected: () {
_startTokenRefreshTimer();
},
),
);
}
void _startTokenRefreshTimer() {
_tokenRefreshTimer?.cancel();
_tokenRefreshTimer = Timer.periodic(Duration(minutes: 5), (timer) async {
await agoraChatTokenAPIcall();
});
}
Future<void> agoraChatTokenAPIcall() async {
try {
if (!Get.isRegistered<AgoraTokenController>()) {
Get.put(AgoraTokenController());
}
final agoraTokenController = Get.find<AgoraTokenController>();
final success = await agoraTokenController.getAgoraUserAndRrmToken();
if (success) {
await loginToAgora();
}
} catch (e, stackTrace) {
logger.error(
"Failed to get Agora chat token",
error: e,
stackTrace: stackTrace,
);
}
}
String globalUserToken = "";
Future<bool> loginToAgora() async {
globalUserToken = "";
try {
final loginDetails = SharedServices.getLoginDetails();
if (loginDetails?.data?.userId == null) {
logger.error("No login details found");
return false;
}
final tokenSuccess = SharedServices.getAgoraUserAndRtmTokens();
if (tokenSuccess?.data == null ||
tokenSuccess?.data?.agoraUserToken == null) {
logger.error("No Agora token found");
return false;
}
final userToken = tokenSuccess!.data!.agoraUserToken.toString();
globalUserToken = userToken;
final userId = loginDetails!.data!.userId.toString();
final agoraUserId = userId.replaceAll("-", "");
// Check connection state first
final isConnected = await ChatClient.getInstance.isConnected();
final currentUser = ChatClient.getInstance.currentUserId;
if (isConnected && currentUser == agoraUserId) {
logger.log("User already logged in and connected: $agoraUserId");
return true;
}
// If currentUser exists but not connected, logout first
if (currentUser != null && currentUser != agoraUserId) {
logger.log("Different user logged in, logging out first");
await ChatClient.getInstance.logout(false);
}
logger.log("Attempting login to Agora chat: $agoraUserId");
await ChatClient.getInstance.loginWithToken(agoraUserId, userToken);
// Verify login succeeded
await Future.delayed(Duration(milliseconds: 500));
final loginVerified = await ChatClient.getInstance.isConnected();
if (loginVerified) {
logger.log("Successfully logged in to Agora chat: $agoraUserId");
return true;
} else {
logger.error("Login completed but not connected");
return false;
}
} on ChatError catch (e, stackTrace) {
// Handle "already logged in" error gracefully
if (e.code == 200) {
logger.log("User already logged in to Agora chat (code 200)");
return true;
}
logger.error(
"Failed to login to Agora chat",
error: e,
stackTrace: stackTrace,
);
// Try to renew token
if (globalUserToken.isNotEmpty) {
try {
await ChatClient.getInstance.renewAgoraToken(globalUserToken);
} catch (renewError) {
logger.error("Failed to renew token", error: renewError);
}
}
return false;
} catch (e, stackTrace) {
logger.error(
"Unexpected error during Agora login",
error: e,
stackTrace: stackTrace,
);
return false;
}
}
Future<bool> isUserLoggedIn() async {
try {
final isConnected = await ChatClient.getInstance.isConnected();
final currentUser = ChatClient.getInstance.currentUserId;
if (!isConnected || currentUser == null) {
logger.log(
"User not logged in. Connected: $isConnected, User: $currentUser",
);
return false;
}
logger.log("User logged in and connected: $currentUser");
return true;
} catch (e) {
logger.error("Error checking login state", error: e);
return false;
}
}
String? get currentUserId => ChatClient.getInstance.currentUserId;
@override
void onClose() {
_tokenRefreshTimer?.cancel();
super.onClose();
}
}