|
- import 'dart:async';
- import 'dart:convert';
- import 'dart:typed_data';
-
- import 'package:buffer/buffer.dart';
- import 'package:chat/data/UserData.dart';
- import 'package:chat/data/chat_data_mgr.dart';
- import 'package:chat/data/constants.dart';
- import 'package:chat/data/group_data_mgr.dart';
- import 'package:chat/generated/i18n.dart';
- import 'package:chat/proto/all.pbserver.dart';
- import 'package:chat/utils/LoadingDialog.dart';
- import 'package:chat/utils/net_state_util.dart';
- import 'package:chat/utils/upload_util.dart';
- import 'package:oktoast/oktoast.dart';
- import 'package:protobuf/protobuf.dart';
- import 'package:web_socket_channel/io.dart';
-
- import 'HttpUtil.dart';
- import 'MessageMgr.dart';
- import 'TokenMgr.dart';
- import 'msgHandler.dart';
-
- const HeartInverval = 30000;
- const ReconnectCountLimit = 5; //重连次数限制
- const MinMsgmByteLen = 9;
-
- class NetWork {
- //私有构造函数
- NetWork._internal();
- //保存单例
- static NetWork _singleton = new NetWork._internal();
-
- //工厂构造函数
- factory NetWork() => _singleton;
- static IOWebSocketChannel channel;
-
- // enum ChatState {
- // connecting, //连接中
- // connected, //连接成功
- // connectFailed, //连接失败
- // logining, //登录中
- // logined, //登录成功
- // loginFailed //登录失败
- // }
-
- bool isLogin = false; //是否登录聊天服务器
-
- int heartOutCount = 0; //超时次数
- int reconnectCount = 0; //重连次数
-
- bool isConnecting = false; //避免重复连接
- bool isConnect = false;
- bool isNormalClose = false;
-
- NetStateBloc _stateBloc = NetStateBloc(); //监控网络状态
-
- Stream<int> get stream => _stateBloc.stream;
-
- Timer heartTimer;
- Timer sendTimer;
- Timer connectServerTimer; //尝试连接服务器
- Timer loginTimer; //登录计时器
-
- bool isInit = false;
-
- String host;
- int port;
-
- static String serverIp;
-
- initNetWithServerInfo() {
- var data = {
- "userid": UserData().basicInfo.userId.toString(),
- };
- data['sign'] = TokenMgr().getSign(data);
-
- HttpUtil().post('/service/config', data: data).then((res) {
- print('获取聊天服务器地址成功');
- res = json.decode(res.toString());
- if (res == null) {
- return;
- }
- if (res['code'] == 0) {
- var config = res['data'][0];
-
- host = config['ip'];
- port = config['port'];
- print('host : $host port : $port');
-
- // host = '192.168.0.139';
- // port = 9091;
-
- serverIp = 'ws://' + host + ':' + port.toString();
-
- if (host == null || host.length == 0) {
- // showToast('server url error : $host : $port');
- } else {
- createWebSocket();
- _stateBloc.start();
- isInit = true;
- }
- }
- });
- }
-
- checkChatState() {
- print('检查聊天状态');
- if (!isConnect) {
- print('没有连接');
- _stateBloc.addState(ChatState.connectFailed);
- } else if (!isLogin) {
- print('没有登录');
- _stateBloc.addState(ChatState.loginFailed);
- }
- }
-
- onData(dynamic message) {
- //任何一条消息都作为心跳包处理
- receiveHeart();
-
- if (message is String) {
- print(message);
- } else if (message is Uint8List) {
- var buffReader = ByteDataReader(endian: Endian.big);
- buffReader.add(message);
-
- int comId = buffReader.readInt16();
-
- int msgId = buffReader.readInt16();
-
- buffReader.readInt8();
-
- int msgLen = buffReader.readUint32();
- if (message.length < msgLen) {
- print('数据没有接受完毕');
- return;
- }
-
- int pbLen = msgLen - MinMsgmByteLen;
-
- var content;
- if (pbLen > 0) {
- content = buffReader.read(pbLen);
- }
-
- if (comId == ComId.Heart) {
- if (msgId == 3) {
- onConnect();
- }
- } else if (comId == ComId.Login) {
- if (msgId == 2) {
- //登陆成功回应
- var msgContent = LoginAccountRes.fromBuffer(content);
- if (msgContent.errorCode == 0) {
- print('登录成功');
- isLogin = true;
- _stateBloc.addState(ChatState.logined);
- loginTimer?.cancel();
- MsgHandler.flushCacheMsg();
- UploadUtil().setUploadUrl(msgContent.httpAddr);
- GroupInfoMgr().checkGroupValid();
- } else {
- _stateBloc.addState(ChatState.loginFailed);
- print('登录失败${msgContent.errorCode}');
- showToast(I18n.of(LoadingManage.context).fail);
- }
- } else if (msgId == 3) {
- //用户登出,其他设备替换
- isLogin = false;
-
- var msgContent = PushUserOutLogin.fromBuffer(content);
- print('登出原因:${msgContent.errorCode}');
- MessageMgr().emit('Login Out');
- }
- } else {
- MsgHandler.handlerServerMsg(comId, msgId, content);
- }
- } else {
- print("Unknown datatype recieved : " + message.runtimeType.toString());
- }
- }
-
-
- onConnect() {
- print('连接服务器成功');
-
- connectServerTimer?.cancel();
- isNormalClose = false;
- isConnect = true;
- isConnecting = false;
- heartOutCount = 0;
- reconnectCount = 0;
-
- _stateBloc.addState(ChatState.connected);
-
- login();
-
- startHeartTimer();
- }
-
- reLogin() {
- if (isConnect) {
- login();
- } else {
- initNetWithServerInfo();
- }
- }
-
- void sendMsg(int comId, int msgId, [GeneratedMessage pb]) {
- //序列化pb对象
- Uint8List pbBody;
- int pbLen = 0;
- if (pb != null) {
- pbBody = pb.writeToBuffer();
- pbLen = pbBody.length;
- }
-
- //包头部分
- var msgLen = pbLen + MinMsgmByteLen; //整体长度
-
- var buffWriter = ByteDataWriter(bufferLength: msgLen, endian: Endian.big);
-
- buffWriter.writeInt16(comId);
- buffWriter.writeInt16(msgId);
- buffWriter.writeInt8(0x24);
-
- buffWriter.writeUint32(msgLen);
-
- if (pbLen > 0) {
- buffWriter.write(pbBody);
- }
-
- var finalMsg = buffWriter.toBytes();
-
- //给服务器发消息
- try {
- if (channel != null && channel.closeCode == null && isConnect) {
- // print("发送消息");
- channel.sink.add(finalMsg);
- } else {
- reconnect();
- print('channel 为空,无法发送消息');
- }
- } catch (e) {
- print("send捕获异常e=${e.toString()}");
- }
- }
-
- startHeartTimer() {
- heartOutCount = 0;
-
- heartTimer?.cancel();
- print('开始心跳计时器');
- heartTimer = Timer.periodic(Duration(milliseconds: HeartInverval), (t) {
- sendHeart();
- });
- }
-
- receiveHeart() {
- //print('收到心跳${DateTime.now()}');
- heartOutCount = 0;
- sendTimer?.cancel();
- }
-
- sendHeart() {
- if (heartOutCount < 3) {
- // print('发送心跳${DateTime.now()}');
- sendMsg(ComId.Heart, 1);
- sendTimer = Timer(Duration(milliseconds: HeartInverval), () {
- //超时了,次数加1
- heartOutCount += 1;
- print('心跳超时$heartOutCount次');
- });
- } else {
- print('心跳次数大于 $heartOutCount');
- close();
- // createWebSocket();
- }
- }
-
- close() {
- print('清除连接状态');
- if (isConnecting) {
- print('连接状态,返回');
- return;
- }
- isConnecting = false;
- isConnect = false;
- isLogin = false;
- heartOutCount = 0;
- sendTimer?.cancel();
- heartTimer?.cancel();
-
- loginTimer?.cancel();
- print('清除计时器');
- connectServerTimer?.cancel();
-
- if (channel != null) {
- channel.sink.close();
- channel = null;
- }
- }
-
-
- reallySingOut() {
- print('用户登出');
- //清缓存
-
- isNormalClose = true;
- reallyClose();
- }
-
- reallyClose() async{
- print('清除连接状态');
- isNormalClose=true;
- isConnecting = false;
- isConnect = false;
- isLogin = false;
- heartOutCount = 0;
- sendTimer?.cancel();
- heartTimer?.cancel();
-
- loginTimer?.cancel();
- print('清除计时器');
- connectServerTimer?.cancel();
-
- if (channel != null) {
- var result = await channel.sink.close();
- print('result: $result');
- channel = null;
- }
- }
-
-
- checkConnect() {
- if (isInit && !isConnect && !isConnecting) {
- reconnect();
- } else {
- if (!isLogin) {
- login();
- }
- }
- }
-
- createWebSocket() {
- if (isConnecting) {
- return;
- }
- if (channel != null) {
- channel.sink.close();
- channel = null;
- }
-
- connectServerTimer?.cancel();
- print('尝试连接服务器');
- isConnecting = true;
- _stateBloc.addState(ChatState.connecting);
-
- reconnectCount += 1;
- if (reconnectCount > ReconnectCountLimit) {
- print('重连数次超出');
- _stateBloc.addState(ChatState.connectFailed);
- isConnecting = false;
- close();
- return;
- }
-
- try {
- channel = IOWebSocketChannel.connect(serverIp);
- channel.stream.listen(
- onData,
- onDone: onDone,
- onError: onError,
- );
- } catch (e) {
- // showToast('连接错误${e.toString()}');
- isConnecting = false;
- //_stateBloc.addState(ChatState.connectFailed);
- }
- }
-
- login() {
- var myId = UserData().basicInfo.userId;
- if (myId == null) {
- return;
- }
-
- var data = {
- "userid": UserData().basicInfo.userId,
- };
-
- LoginAccountReq req = LoginAccountReq.create();
- req.userId = data['userid'];
- req.sigin = TokenMgr().getSign(data);
-
- print('发送登陆消息');
-
- loginTimer = Timer(Duration(milliseconds: 3000), () {
- _stateBloc.addState(ChatState.loginFailed);
- });
- sendMsg(ComId.Login, 1, req);
- _stateBloc.addState(ChatState.logining);
- }
-
- singOut() {
- print('用户登出');
- //清缓存
- ChatDataMgr().logout();
- MsgHandler.clear();
-
- isNormalClose = true;
- close();
- }
-
- onError(error) {
- isConnecting = false;
- print('ws error $error');
- }
-
- reconnect() {
- close();
- reconnectCount = 0;
-
- if (host == null || host.length == 0) {
- initNetWithServerInfo();
- } else {
- createWebSocket();
- }
- }
-
- onDone() {
- print('ws channel closed${DateTime.now()}');
- close();
- if (!isNormalClose ) {
- print('无法连接聊天服务器,5秒后重新连接');
- connectServerTimer = Timer(Duration(seconds: 5), () {
- createWebSocket();
- });
- }
- }
- }
|