You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:async';
import 'package:aku_new_community_manager/tools/user_tool.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:power_logger/power_logger.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
enum SOCKETSTATUS {
CONNECTED, //已连接
BREAKOFF, //已断开
CLOSED, //已关闭
}
class WebSocketUtil {
static final WebSocketUtil _socket = WebSocketUtil._();
//内部构造函数
WebSocketUtil._();
//单例模式
factory WebSocketUtil() => _socket;
IOWebSocketChannel? _webSocket;
///用户设置不同的服务器地址
static const String baseUri = 'wss://saas.kaidalai.cn/websocket/butlerApp';
String get urlAddress =>
'$baseUri/${UserTool.userProvider.userInfoModel?.communityName}/${UserTool.userProvider.userInfoModel?.nickName}';
///连接状态
SOCKETSTATUS _socketStatus = SOCKETSTATUS.CLOSED;
///心跳计时器;
Timer? _heartTimer;
///心跳间隔
Duration _heartDuration = Duration(seconds: 30);
///重连计数器
int _reconnectCount = 0;
///重连最大次数
int _reconnectTimes = 30;
///重连计时器
Timer? _reconnectTimer;
///连接错误回调
Function(dynamic e)? onError;
///开启回调
Function? onStart;
///接收消息回调
Function(String message)? onReceiveMes;
///关闭连接回调;
Function? onClosed;
///控制台输出
bool _consolePrint = true;
///注册websocket
void initWebSocket(
{Duration? heartDuration,
bool? consolePrint,
Function? onStart,
Function(String message)? onReceiveMes,
Function? onClosed,
Function(dynamic e)? onError}) {
this.onStart = onStart;
this.onReceiveMes = onReceiveMes;
this.onClosed = onClosed;
this.onError = onError;
if (consolePrint != null) {
this._consolePrint = consolePrint;
}
if (heartDuration != null) {
this._heartDuration = heartDuration;
}
print('——————————webSocket init ——————————');
}
///开启websocket
void startWebSocket() {
closeWebSocket();
try {
_webSocket = IOWebSocketChannel.connect(Uri.parse(urlAddress));
print('webSocket已连接服务器$urlAddress');
_socketStatus = SOCKETSTATUS.CONNECTED;
endReconnect();
onStart?.call();
_webSocket!.stream.listen(
(event) => webSocketReceiveMessage(event as String),
onError: webSocketOnError,
);
initHeartBeat();
} catch (e) {
BotToast.showText(text: 'webSocket连接失败');
print('webSocket连接失败');
onError?.call(e);
LoggerData.addData(e);
}
}
//接收消息回调
webSocketReceiveMessage(message) {
if (message == '心跳正常') {
_dPrint('心跳正常————————${DateTime.now()}');
} else {
onReceiveMes?.call(message);
}
}
//关闭连接回调
webSocketClosed() {
closeWebSocket();
onClosed?.call();
}
//连接出错回调
webSocketOnError(e) {
WebSocketChannelException ex = e;
_socketStatus = SOCKETSTATUS.BREAKOFF;
onError?.call(ex.message);
print('——————连接断开,开始重连');
startReconnect();
}
//启动重连计时
void startReconnect() {
endReconnect();
_reconnectTimer = Timer.periodic(Duration(milliseconds: 5000), (timer) {
_reconnectCount++;
print('——————第${_reconnectCount}次重连');
startWebSocket();
if (_reconnectCount >= _reconnectTimes) {
print('——————重连失败');
closeWebSocket();
}
});
}
//重置重连计时
void endReconnect() {
_reconnectTimer?.cancel();
_reconnectTimer = null;
_reconnectCount = 0;
}
///初始化心跳
void initHeartBeat() {
destoryHeart();
_heartTimer = Timer.periodic(_heartDuration, (timer) {
sentHeart();
});
}
//发送心跳
void sentHeart() {
sendMessage('heartbeat');
}
///销毁心跳
void destoryHeart() {
_heartTimer?.cancel();
_heartTimer = null;
}
///关闭websocket
void closeWebSocket() {
if (_webSocket != null) {
_webSocket!.sink.close();
print('——————websocket连接已关闭');
}
endReconnect();
destoryHeart();
_socketStatus = SOCKETSTATUS.CLOSED;
}
///向websocket服务器发送消息
void sendMessage(message) {
if (_webSocket != null) {
switch (_socketStatus) {
case SOCKETSTATUS.CONNECTED:
_dPrint('发送中:' + message);
_webSocket!.sink.add(message);
break;
case SOCKETSTATUS.CLOSED:
print('连接已关闭');
break;
case SOCKETSTATUS.BREAKOFF:
print('发送失败');
break;
default:
break;
}
}
}
//封装print
void _dPrint(dynamic data) {
if (this._consolePrint) {
print(data);
}
}
}