connection.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import 'dart:async';
  2. import 'package:fis_common/event/event_type.dart';
  3. import 'package:fis_common/logger/logger.dart';
  4. import 'package:web_socket_channel/web_socket_channel.dart';
  5. import 'package:web_socket_channel/status.dart' as statuses;
  6. import 'core/interface/connection.dart';
  7. class WsConnectionException implements Exception {
  8. final dynamic message;
  9. WsConnectionException(this.message);
  10. }
  11. /// WebScoket连接
  12. class WsConnection implements IConnection {
  13. /// 错误断开重试次数
  14. static const C_ERR_RETRY_LIMIT = 5;
  15. /// 连接请求超时时间,10s
  16. static const C_CONNECT_REQ_TIMEOUT = 10 * 1000;
  17. ConnectionStatus _status = ConnectionStatus.connectedClosed;
  18. int _errorRetryCount = 0;
  19. bool _keepAlive = false;
  20. bool _hasError = false;
  21. /// 主机地址
  22. final String host;
  23. WebSocketChannel? _channel;
  24. Timer? _timer;
  25. WsConnection(
  26. this.host, {
  27. this.exceptionOccurred,
  28. this.statusChanged,
  29. }) {
  30. messageReceived = FEventHandler<dynamic>();
  31. }
  32. /// 连接状态
  33. ConnectionStatus get status => _status;
  34. /// 是否已连接
  35. bool get isConnected =>
  36. _channel != null && status == ConnectionStatus.connected;
  37. bool get isKeepAlive => _keepAlive;
  38. @override
  39. FEventHandler<Exception>? exceptionOccurred;
  40. @override
  41. late final FEventHandler<dynamic> messageReceived;
  42. @override
  43. FEventHandler<ConnectionStatus>? statusChanged;
  44. @override
  45. Future<bool> connect() async {
  46. logger.i("WsConnection is trying connect...");
  47. _hasError = false;
  48. _keepAlive = true;
  49. final uri = Uri.parse(host);
  50. _channel = WebSocketChannel.connect(uri);
  51. if (_channel == null) {
  52. logger.i("The ws connect failed.");
  53. return false;
  54. }
  55. final completer = Completer<bool>();
  56. Future.delayed(const Duration(milliseconds: 500), () {
  57. if (completer.isCompleted || _hasError) return;
  58. _updateStatus(ConnectionStatus.connected);
  59. completer.complete(true);
  60. logger.i("The ws connection is connected.");
  61. _startCheckConnection();
  62. });
  63. _channel!.stream.listen(
  64. (data) {
  65. messageReceived.emit(this, data);
  66. },
  67. onError: (error) {
  68. _hasError = true;
  69. _handleCancelOnError(error);
  70. try {
  71. if (!completer.isCompleted) {
  72. completer.complete(false);
  73. }
  74. } catch (e) {}
  75. },
  76. cancelOnError: true,
  77. onDone: () {},
  78. );
  79. return completer.future;
  80. }
  81. @override
  82. Future<bool> close() async {
  83. logger.i("WsConnection is closing...");
  84. _keepAlive = false;
  85. _stopCheckConnection();
  86. if (_channel != null) {
  87. if (_channel!.closeCode == null) {
  88. await _channel!.sink.close(statuses.normalClosure);
  89. }
  90. _channel = null;
  91. }
  92. _updateStatus(ConnectionStatus.connectedClosed);
  93. logger.i("The ws connection is disconnected.");
  94. return true;
  95. }
  96. void _updateStatus(ConnectionStatus value) {
  97. if (value != _status) {
  98. _status = value;
  99. statusChanged?.emit(this, value);
  100. }
  101. }
  102. void _startCheckConnection() {
  103. _timer?.cancel();
  104. _timer = Timer.periodic(
  105. const Duration(milliseconds: 500),
  106. (timer) {
  107. if (isConnected) {
  108. if (_channel!.closeCode != null) {
  109. _onDisconnected();
  110. }
  111. }
  112. },
  113. );
  114. }
  115. void _stopCheckConnection() {
  116. _timer?.cancel();
  117. _timer = null;
  118. }
  119. void _onDisconnected() {
  120. _updateStatus(ConnectionStatus.connectedClosed);
  121. _channel = null;
  122. logger.i("WsConnection done, the ws connection is disconnected.");
  123. _tryReconnect();
  124. }
  125. /// 处理因错误导致的连接中断
  126. void _handleCancelOnError(error) async {
  127. exceptionOccurred?.emit(this, WsConnectionException(error));
  128. _updateStatus(ConnectionStatus.connectedClosed);
  129. logger.e("WsConnection error, the ws connection is disconnected.", error);
  130. _tryReconnect();
  131. }
  132. Future<void> _tryReconnect() async {
  133. _stopCheckConnection();
  134. if (_keepAlive) {
  135. // 延迟1000ms后尝试再次连接
  136. await Future.delayed(const Duration(milliseconds: 1000));
  137. logger.i(
  138. "WsConnection is now keeping alive and trying to reconnect for $_errorRetryCount time.");
  139. connect();
  140. _errorRetryCount++;
  141. }
  142. }
  143. }