169 lines
4.6 KiB
Dart
169 lines
4.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:web_socket_channel/io.dart';
|
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
|
|
|
class OnlineTimeService {
|
|
static final OnlineTimeService _instance = OnlineTimeService._internal();
|
|
factory OnlineTimeService() => _instance;
|
|
OnlineTimeService._internal();
|
|
|
|
WebSocketChannel? _channel;
|
|
bool _isConnected = false;
|
|
bool _isConnecting = false;
|
|
Timer? _reconnectTimer;
|
|
StreamSubscription? _subscription;
|
|
Timer? _heartbeatTimer; // 定时发送心跳消息
|
|
|
|
// final String _baseWsUrl = 'ws://10.0.0.17:8081/websocket/online/';
|
|
final String _baseWsUrl = 'ws://14.103.162.172:8081/websocket/online/';
|
|
String? _token;
|
|
|
|
Future<String> _getWsUrl() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
_token = prefs.getString('token') ?? '';
|
|
|
|
// 确保返回的是 ws:// 或 wss:// 协议的 WebSocket URL
|
|
// return 'ws://10.0.0.17:8081/websocket/online/$_token';
|
|
return 'ws://14.103.162.172:8081/websocket/online/$_token';
|
|
}
|
|
Future<void> initWebSocket() async {
|
|
if (_isConnected || _isConnecting) return;
|
|
|
|
try {
|
|
_isConnecting = true;
|
|
|
|
final wsUrl = await _getWsUrl();
|
|
print('尝试连接WebSocket: $wsUrl');
|
|
|
|
_channel = IOWebSocketChannel.connect(Uri.parse(wsUrl));
|
|
// final uri = Uri.parse(wsUrl).replace(
|
|
// queryParameters: {'Authorization': 'Bearer $_token'},
|
|
// );
|
|
// print('尝试连接WebSocket: $wsUrl');
|
|
// // print('header: ${uri.queryParameters}');
|
|
|
|
// _channel = IOWebSocketChannel.connect(wsUrl);
|
|
print('_channel: ${_channel}');
|
|
await _channel!.ready;
|
|
|
|
_isConnected = true;
|
|
_isConnecting = false;
|
|
print('WebSocket连接成功');
|
|
|
|
// 发送进入应用消息
|
|
_sendEnterMessage();
|
|
|
|
// 启动心跳定时器
|
|
_startHeartbeat();
|
|
|
|
// 开始监听消息
|
|
_startListening();
|
|
} catch (e, stack) {
|
|
print('WebSocket连接失败: $e\n$stack');
|
|
if (e is WebSocketChannelException) {
|
|
print('WebSocket错误详细信息: ${e.message}');
|
|
}
|
|
_isConnected = false;
|
|
_isConnecting = false;
|
|
// _scheduleReconnect();
|
|
}
|
|
}
|
|
|
|
// 启动心跳定时器,每隔五分钟发送一次消息
|
|
void _startHeartbeat() {
|
|
_heartbeatTimer?.cancel(); // 取消之前的定时器
|
|
_heartbeatTimer = Timer.periodic(Duration(minutes: 5), (timer) {
|
|
if (_isConnected) {
|
|
_sendHeartbeatMessage();
|
|
}
|
|
});
|
|
}
|
|
|
|
void _sendHeartbeatMessage() {
|
|
if (!_isConnected || _channel == null) return;
|
|
|
|
try {
|
|
final data = jsonEncode({
|
|
'duration': '3',
|
|
});
|
|
print('发送心跳消息: $data');
|
|
_channel!.sink.add(data);
|
|
} catch (e) {
|
|
print('发送心跳消息失败: $e');
|
|
}
|
|
}
|
|
|
|
void _sendEnterMessage() {
|
|
if (!_isConnected || _channel == null) return;
|
|
|
|
try {
|
|
final data = jsonEncode({
|
|
'duration': 1,
|
|
});
|
|
print('发送进入应用消息');
|
|
_channel!.sink.add(data);
|
|
} catch (e) {
|
|
print('发送进入消息失败: $e');
|
|
}
|
|
}
|
|
|
|
void _startListening() {
|
|
_subscription?.cancel();
|
|
_channel?.stream.listen(
|
|
(message) {
|
|
print('收到服务器消息: $message');
|
|
// try {
|
|
// final response = jsonDecode(message.toString());
|
|
// if (response['status'] == 'success') {
|
|
// print('服务器确认消息接收成功');
|
|
// }
|
|
// } catch (e) {
|
|
// print('解析服务器消息失败: $e');
|
|
// }
|
|
},
|
|
onError: (error) {
|
|
print('WebSocket错误: $error');
|
|
_isConnected = false;
|
|
_isConnecting = false;
|
|
// _scheduleReconnect();
|
|
},
|
|
onDone: () {
|
|
print('WebSocket连接关闭');
|
|
_isConnected = false;
|
|
_isConnecting = false;
|
|
// _scheduleReconnect();
|
|
},
|
|
cancelOnError: true,
|
|
);
|
|
}
|
|
|
|
// 关闭时发送 { "duration": "close" }
|
|
void dispose() {
|
|
print('正在关闭WebSocket连接...');
|
|
|
|
_subscription?.cancel(); // 取消监听
|
|
_reconnectTimer?.cancel();
|
|
_heartbeatTimer?.cancel(); // 取消心跳定时器
|
|
|
|
if (_isConnected && _channel != null) {
|
|
try {
|
|
final data = jsonEncode({
|
|
'duration': 2,
|
|
});
|
|
_channel!.sink.add(data);
|
|
print('发送关闭应用消息');
|
|
} catch (e) {
|
|
print('发送关闭消息失败: $e');
|
|
}
|
|
}
|
|
|
|
_channel?.sink.close();
|
|
_isConnected = false;
|
|
_isConnecting = false;
|
|
print('WebSocket连接已关闭');
|
|
}
|
|
}
|