elysia/lib/plugin/WebSocketService.dart
2025-11-04 09:53:47 +08:00

199 lines
5.4 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/cupertino.dart';
typedef MessageCallback = void Function(dynamic message);
typedef ErrorCallback = void Function(dynamic error);
typedef DoneCallback = void Function();
typedef ConnectedCallback = void Function();
typedef ReconnectCallback = void Function(ReconnectStatus);
enum ReconnectStatus { start, trying, success }
class WebSocketService with WidgetsBindingObserver {
// 单例
static final WebSocketService _instance = WebSocketService._internal();
static bool doReconnect = false;
factory WebSocketService() => _instance;
WebSocketService._internal();
// 初始化/销毁生命周期
void init() {
WidgetsBinding.instance.addObserver(this);
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_reconnectTimer?.cancel();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
if (doReconnect) {
// 亮屏,主动检测连接
_socket?.close();
_socket = null;
_startReconnect();
doReconnect = false;
}
} else if (state == AppLifecycleState.paused) {
doReconnect = true;
// 锁屏时暂停计时器
_reconnectTimer?.cancel();
_reconnectTimer = null;
}
}
WebSocket? _socket;
String? _url;
bool _isConnecting = false;
bool _manuallyClosed = false;
Timer? _reconnectTimer;
final List<MessageCallback> _messageListeners = [];
final List<ErrorCallback> _errorListeners = [];
final List<DoneCallback> _doneListeners = [];
final List<ConnectedCallback> _connectedListeners = [];
final List<ReconnectCallback> _reconnectListeners = [];
bool _hasTriggeredStart = false;
/// 建立连接
Future<void> connect(String url) async {
_url = url;
_manuallyClosed = false;
_hasTriggeredStart = false;
_triggerReconnectCallback(ReconnectStatus.start);
await _tryConnect();
}
/// 发送消息
void send(String message) {
if (_socket != null && _socket!.readyState == WebSocket.open) {
_socket!.add(message);
} else {
for (var listener in _errorListeners) {
listener("WebSocket 未连接,无法发送: $message");
}
}
}
/// 手动关闭
Future<void> close() async {
_manuallyClosed = true;
_reconnectTimer?.cancel();
_reconnectTimer = null;
await _socket?.close();
_socket = null;
_hasTriggeredStart = false;
}
/// 添加监听
void addMessageListener(MessageCallback listener) =>
_messageListeners.add(listener);
void removeMessageListener(MessageCallback listener) =>
_messageListeners.remove(listener);
void addErrorListener(ErrorCallback listener) =>
_errorListeners.add(listener);
void removeErrorListener(ErrorCallback listener) =>
_errorListeners.remove(listener);
void addDoneListener(DoneCallback listener) => _doneListeners.add(listener);
void removeDoneListener(DoneCallback listener) =>
_doneListeners.remove(listener);
void addConnectedListener(ConnectedCallback listener) =>
_connectedListeners.add(listener);
void removeConnectedListener(ConnectedCallback listener) =>
_connectedListeners.remove(listener);
void addReconnectListener(ReconnectCallback listener) =>
_reconnectListeners.add(listener);
void removeReconnectListener(ReconnectCallback listener) =>
_reconnectListeners.remove(listener);
/// 内部尝试连接
Future<void> _tryConnect() async {
if (_socket != null && _socket!.readyState == WebSocket.open) return;
if (_isConnecting) return;
_isConnecting = true;
_triggerReconnectCallback(ReconnectStatus.trying);
try {
_socket = await WebSocket.connect(_url!);
// 连接成功回调
for (var callback in _connectedListeners) callback();
_triggerReconnectCallback(ReconnectStatus.success);
_hasTriggeredStart = false;
_socket!.listen(
(data) {
dynamic msg;
try {
msg = jsonDecode(data);
} catch (_) {
msg = data.toString();
}
for (var listener in _messageListeners) listener(msg);
},
onError: (error) {
for (var listener in _errorListeners) listener(error);
_startReconnect();
},
onDone: () {
for (var listener in _doneListeners) listener();
_startReconnect();
},
cancelOnError: true,
);
} catch (e) {
for (var listener in _errorListeners) listener(e);
_startReconnect();
} finally {
_isConnecting = false;
}
}
/// 开始重连
void _startReconnect() {
if (_manuallyClosed) return;
if (_reconnectTimer?.isActive ?? false) return;
if (!_hasTriggeredStart) {
_triggerReconnectCallback(ReconnectStatus.start);
_hasTriggeredStart = true;
}
_reconnectTimer = Timer.periodic(const Duration(seconds: 5), (timer) {
if (_socket == null || _socket!.readyState != WebSocket.open) {
_triggerReconnectCallback(ReconnectStatus.trying);
_tryConnect();
} else {
timer.cancel();
_reconnectTimer = null;
}
});
}
/// 触发重连状态回调
void _triggerReconnectCallback(ReconnectStatus status) {
for (var listener in _reconnectListeners) {
listener(status);
}
}
}