|
|
|
@ -1,4 +1,12 @@ |
|
|
|
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 '../model/rtc/rtc_channel_data.dart'; |
|
|
|
import '../network/network_service.dart'; |
|
|
|
import '../network/rtc_api.dart'; |
|
|
|
|
|
|
|
/// 声网 RTM 管理器,聚合常用的客户端与 StreamChannel 操作 |
|
|
|
class RTMManager { |
|
|
|
@ -13,6 +21,7 @@ class RTMManager { |
|
|
|
bool _isLoggedIn = false; |
|
|
|
String? _currentAppId; |
|
|
|
String? _currentUserId; |
|
|
|
late NetworkService _networkService; |
|
|
|
|
|
|
|
final Map<String, StreamChannel> _streamChannels = {}; |
|
|
|
|
|
|
|
@ -52,39 +61,73 @@ class RTMManager { |
|
|
|
_currentUserId == userId) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
_networkService = Get.find<NetworkService>(); |
|
|
|
await dispose(); |
|
|
|
|
|
|
|
final (status, client) = await RTM(appId, userId, config: config); |
|
|
|
print('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<bool> login(String token) async { |
|
|
|
print('RTM TOKEN:$token'); |
|
|
|
_ensureInitialized(); |
|
|
|
final (status, _) = await _client!.login(token); |
|
|
|
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<bool> subscribe(String channelName) async { |
|
|
|
_ensureInitialized(); |
|
|
|
final (status, _) = await _client!.subscribe(channelName); |
|
|
|
print(!status.error ? 'RTM 订阅成功' : 'RTM 订阅失败'); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 取消订阅频道 |
|
|
|
Future<bool> unsubscribe(String channelName) async { |
|
|
|
_ensureInitialized(); |
|
|
|
final (status, _) = await _client!.unsubscribe(channelName); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 登出 RTM |
|
|
|
Future<void> logout() async { |
|
|
|
if (!_isInitialized || _client == null || !_isLoggedIn) return; |
|
|
|
|
|
|
|
await leaveAllStreamChannels(); |
|
|
|
final (status, _) = await _client!.logout(); |
|
|
|
_handleStatus(status); |
|
|
|
_isLoggedIn = false; |
|
|
|
@ -97,13 +140,6 @@ class RTMManager { |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 设置底层参数(JSON) |
|
|
|
Future<bool> setParameters(String paramsJson) async { |
|
|
|
_ensureInitialized(); |
|
|
|
final status = await _client!.setParameters(paramsJson); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 发布频道文本消息 |
|
|
|
Future<bool> publishChannelMessage({ |
|
|
|
required String channelName, |
|
|
|
@ -123,99 +159,8 @@ class RTMManager { |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 创建/加入 StreamChannel |
|
|
|
Future<bool> joinStreamChannel( |
|
|
|
String channelName, { |
|
|
|
String? token, |
|
|
|
bool withMetadata = false, |
|
|
|
bool withPresence = true, |
|
|
|
bool withLock = false, |
|
|
|
bool beQuiet = false, |
|
|
|
}) async { |
|
|
|
_ensureInitialized(); |
|
|
|
|
|
|
|
StreamChannel? channel = _streamChannels[channelName]; |
|
|
|
if (channel == null) { |
|
|
|
final (createStatus, createdChannel) = await _client!.createStreamChannel( |
|
|
|
channelName, |
|
|
|
); |
|
|
|
if (!_handleStatus(createStatus) || createdChannel == null) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
channel = createdChannel; |
|
|
|
_streamChannels[channelName] = channel; |
|
|
|
} |
|
|
|
|
|
|
|
final (status, _) = await channel.join( |
|
|
|
token: token, |
|
|
|
withMetadata: withMetadata, |
|
|
|
withPresence: withPresence, |
|
|
|
withLock: withLock, |
|
|
|
beQuiet: beQuiet, |
|
|
|
); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 离开 StreamChannel |
|
|
|
Future<void> leaveStreamChannel(String channelName) async { |
|
|
|
final channel = _streamChannels[channelName]; |
|
|
|
if (channel == null) return; |
|
|
|
|
|
|
|
final (status, _) = await channel.leave(); |
|
|
|
_handleStatus(status); |
|
|
|
await channel.release(); |
|
|
|
_streamChannels.remove(channelName); |
|
|
|
} |
|
|
|
|
|
|
|
/// 离开全部 StreamChannel |
|
|
|
Future<void> leaveAllStreamChannels() async { |
|
|
|
final names = _streamChannels.keys.toList(); |
|
|
|
for (final name in names) { |
|
|
|
await leaveStreamChannel(name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 加入主题 |
|
|
|
Future<bool> joinTopic({ |
|
|
|
required String channelName, |
|
|
|
required String topic, |
|
|
|
RtmMessageQos qos = RtmMessageQos.unordered, |
|
|
|
RtmMessagePriority priority = RtmMessagePriority.normal, |
|
|
|
String meta = '', |
|
|
|
bool syncWithMedia = false, |
|
|
|
}) async { |
|
|
|
final channel = await _requireChannel(channelName); |
|
|
|
final (status, _) = await channel.joinTopic( |
|
|
|
topic, |
|
|
|
qos: qos, |
|
|
|
priority: priority, |
|
|
|
meta: meta, |
|
|
|
syncWithMedia: syncWithMedia, |
|
|
|
); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 发送主题消息 |
|
|
|
Future<bool> publishTopicMessage({ |
|
|
|
required String channelName, |
|
|
|
required String topic, |
|
|
|
required String message, |
|
|
|
int sendTs = 0, |
|
|
|
String? customType, |
|
|
|
}) async { |
|
|
|
final channel = await _requireChannel(channelName); |
|
|
|
final (status, _) = await channel.publishTextMessage( |
|
|
|
topic, |
|
|
|
message, |
|
|
|
sendTs: sendTs, |
|
|
|
customType: customType, |
|
|
|
); |
|
|
|
return _handleStatus(status); |
|
|
|
} |
|
|
|
|
|
|
|
/// 释放 RTM Client |
|
|
|
Future<void> dispose() async { |
|
|
|
await leaveAllStreamChannels(); |
|
|
|
if (_client != null && _isLoggedIn) { |
|
|
|
final (status, _) = await _client!.logout(); |
|
|
|
_handleStatus(status); |
|
|
|
@ -248,20 +193,6 @@ class RTMManager { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
Future<StreamChannel> _requireChannel(String channelName) async { |
|
|
|
if (!_streamChannels.containsKey(channelName)) { |
|
|
|
final ok = await joinStreamChannel(channelName); |
|
|
|
if (!ok) { |
|
|
|
throw Exception('加入 StreamChannel 失败:$channelName'); |
|
|
|
} |
|
|
|
} |
|
|
|
final channel = _streamChannels[channelName]; |
|
|
|
if (channel == null) { |
|
|
|
throw Exception('StreamChannel 不存在:$channelName'); |
|
|
|
} |
|
|
|
return channel; |
|
|
|
} |
|
|
|
|
|
|
|
bool _handleStatus(RtmStatus status) { |
|
|
|
if (status.error) { |
|
|
|
onOperationError?.call(status); |
|
|
|
|