import 'package:agora_rtm/agora_rtm.dart'; import 'package:agora_token_generator/agora_token_generator.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../network/network_service.dart'; /// 声网 RTM 管理器,聚合常用的客户端与 StreamChannel 操作 class RTMManager { RTMManager._internal(); static final RTMManager _instance = RTMManager._internal(); factory RTMManager() => _instance; static RTMManager get instance => _instance; RtmClient? _client; bool _isInitialized = false; bool _isLoggedIn = false; String? _currentAppId; String? _currentUserId; late NetworkService _networkService; final Map _streamChannels = {}; /// 监听 link state void Function(LinkStateEvent event)? onLinkStateEvent; /// 监听消息事件(频道 / 主题) void Function(MessageEvent event)? onMessageEvent; /// 监听 presence 事件 void Function(PresenceEvent event)? onPresenceEvent; /// 监听 topic 事件 void Function(TopicEvent event)? onTopicEvent; /// 监听 lock 事件 void Function(LockEvent event)? onLockEvent; /// 监听 storage 事件 void Function(StorageEvent event)? onStorageEvent; /// 监听 token 事件 void Function(TokenEvent event)? onTokenEvent; /// 统一错误通知 void Function(RtmStatus status)? onOperationError; /// 创建/初始化 RTM Client Future initialize({ required String appId, required String userId, RtmConfig? config, }) async { if (_isInitialized && _client != null && _currentAppId == appId && _currentUserId == userId) { return true; } _networkService = Get.find(); await dispose(); final (status, client) = await RTM(appId, userId, config: config); print(status.error ? '❌ RTM 初始化失败' : '✅ RTM 初始化成功'); if (status.error) { onOperationError?.call(status); return false; } _client = client; _currentAppId = appId; _currentUserId = userId; _isInitialized = true; _registerClientListeners(); final response = await _networkService.rtcApi.getSwRtmToken(); // 处理响应 if (response.data.isSuccess) { await login(response.data.data!.token); } else { SmartDialog.showToast(response.data.message); } return true; } /// 登录 RTM Future login(String token) async { print('RTM TOKEN:$token'); _ensureInitialized(); GetStorage storage = GetStorage(); String userId = storage.read('userId') ?? ''; print('RTM userId:$userId'); String tokens = RtmTokenBuilder.buildToken( appId: '4c2ea9dcb4c5440593a418df0fdd512d', appCertificate: '16f34b45181a4fae8acdb1a28762fcfa', userId: userId, tokenExpireSeconds: 3600, ); print('RTM TOKEN:$tokens'); final (status, _) = await _client!.login(tokens); final ok = _handleStatus(status); print(ok ? 'RTM 登录成功' : 'RTM 登录失败'); if (ok) { _isLoggedIn = true; } return ok; } /// 创建频道 Future subscribe(String channelName) async { _ensureInitialized(); final (status, _) = await _client!.subscribe(channelName); print(!status.error ? 'RTM 订阅成功' : 'RTM 订阅失败'); return _handleStatus(status); } /// 取消订阅频道 Future unsubscribe(String channelName) async { _ensureInitialized(); final (status, _) = await _client!.unsubscribe(channelName); return _handleStatus(status); } /// 登出 RTM Future logout() async { if (!_isInitialized || _client == null || !_isLoggedIn) return; final (status, _) = await _client!.logout(); _handleStatus(status); _isLoggedIn = false; } /// 刷新 Token Future renewToken(String token) async { _ensureInitialized(); final (status, _) = await _client!.renewToken(token); return _handleStatus(status); } /// 发布频道文本消息 Future publishChannelMessage({ required String channelName, required String message, RtmChannelType channelType = RtmChannelType.message, String? customType, bool storeInHistory = false, }) async { try { _ensureInitialized(); if (!_isLoggedIn) { print('❌ RTM 未登录,无法发布消息'); return false; } print('📤 RTM 发布消息到频道: $channelName'); print('📤 RTM 消息内容: $message'); print('📤 RTM 开始调用 publish 方法...'); final (status, _) = await _client!.publish( channelName, message, channelType: channelType, customType: customType, storeInHistory: storeInHistory, ); print('📤 RTM publish 方法返回,状态码: ${status.errorCode}'); print('📤 RTM publish 错误状态: ${status.error}'); final success = _handleStatus(status); if (success) { print('✅ RTM 消息发布成功'); } else { print('❌ RTM 消息发布失败: ${status.errorCode}'); if (onOperationError != null) { onOperationError!(status); } } return success; } catch (e, stackTrace) { print('❌ RTM publishChannelMessage 异常: $e'); print('❌ 堆栈信息: $stackTrace'); return false; } } /// 释放 RTM Client Future dispose() async { if (_client != null && _isLoggedIn) { final (status, _) = await _client!.logout(); _handleStatus(status); } await _client?.release(); _client = null; _isInitialized = false; _isLoggedIn = false; _currentAppId = null; _currentUserId = null; _streamChannels.clear(); } bool get isInitialized => _isInitialized; bool get isLoggedIn => _isLoggedIn; String? get currentUserId => _currentUserId; Iterable get joinedStreamChannels => _streamChannels.keys; void _registerClientListeners() { if (_client == null) return; _client!.addListener( linkState: (event) => onLinkStateEvent?.call(event), message: (event) => onMessageEvent?.call(event), presence: (event) => onPresenceEvent?.call(event), topic: (event) => onTopicEvent?.call(event), lock: (event) => onLockEvent?.call(event), storage: (event) => onStorageEvent?.call(event), token: (event) => onTokenEvent?.call(event), ); } bool _handleStatus(RtmStatus status) { if (status.error) { onOperationError?.call(status); return false; } return true; } void _ensureInitialized() { if (!_isInitialized || _client == null) { throw Exception('RTM Client 未初始化,请先调用 initialize'); } } }