import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:common_utils/common_utils.dart'; import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import './Message.pb.dart' as messages; import './ReplyBody.pb.dart' as replybody; import './SentBody.pb.dart' as sentbody; import 'package:fixnum/fixnum.dart'; import 'package:convert/convert.dart'; //PONG // ignore: constant_identifier_names const PONG_TYPE = 0; //发送消息类型 // ignore: constant_identifier_names const Message_TYPE = 2; //强制下线类型 // ignore: constant_identifier_names const ACTION_999 = 999; //响应消息类型 // ignore: constant_identifier_names const REPLY_BODY = 4; //消息发送 // ignore: constant_identifier_names const SEND_BODY = 3; //PING // ignore: constant_identifier_names const PING_TYPE = 1; // ignore: constant_identifier_names const DATA_HEADER_LENGTH = 1; const sOCKETAPPVERSION = '100'; class CIMSocket extends ChangeNotifier { late Socket? socket; late String? uri; late int? port; late int? uid; late String endCode = "0"; final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); late TimerUtil timer = TimerUtil() ..mTotalTime = 10000 ..setOnTimerTickCallback((millisUntilFinished) { if (millisUntilFinished == 0 && uid != null) { connect(); } }); late bool isConnected = false; late messages.Model? _model = null; messages.Model? get model => _model; Future init(String uri, int port, int uid) async { this.uri = uri; this.port = port; this.uid = uid; } //登录 Future connect() async { if (uri == null || port == null || uid == null) { throw IOException; } Socket.connect(uri, port!).then((Socket sock) { sock.listen((data) async { int l = (data[1] & 0xff); int h = (data[2] & 0xff); int length = (l | h << 8); if (data[0] == PING_TYPE) { sendPong(); } else if (data[0] == REPLY_BODY) { var message = data.sublist(3, length + 3); replybody.Model info = replybody.Model(); info.mergeFromBuffer(message); } else if (data[0] == Message_TYPE) { var message = data.sublist(3, length + 3); messages.Model model = messages.Model(); model.mergeFromBuffer(message); switchMessage(model); } }, onError: (error, StackTrace trace) { socket = null; isConnected = false; if (!timer.isActive()) { timer.setTotalTime(12000); timer.startCountDown(); } notifyListeners(); }, onDone: () { socket = null; isConnected = false; notifyListeners(); if (endCode != "999") { timer.setTotalTime(12000); timer.startCountDown(); } }, cancelOnError: true); socket = sock; sendLoginMsg(); }).catchError((e) { socket = null; isConnected = false; notifyListeners(); timer.setTotalTime(12000); timer.startCountDown(); }); } //登出 Future disConnect() async { if (socket != null) { endCode = '999'; await socket!.close(); } } //发送登录消息 Future sendLoginMsg() async { SystemInfo systemInfo = SystemInfo(); await systemInfo.init(); String deviceName = systemInfo.deviceName; // DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); String channel = systemInfo.deviceName; String systemVersion = systemInfo.version; String deviceId = hex.encode( md5.convert(const Utf8Encoder().convert(systemInfo.deviceId)).bytes); Map map = { "uid": uid.toString(), //主id "channel": channel, "appVersion": sOCKETAPPVERSION, "osVersion": systemVersion, "packageName": "cn.asihe.cim", "deviceId": deviceId, // (await PlatformDeviceId.getDeviceId)!.replaceAll("-", ""), //应用id "deviceName": '$deviceName ${systemInfo.model}', "language": "zh-CN", }; int time = DateTime.now().millisecondsSinceEpoch; Int64 timeStamp = Int64.parseInt(time.toString()); var body = sentbody.Model(data: map); body.key = "client_bind"; body.timestamp = timeStamp; var data = body.writeToBuffer(); var protobuf = Uint8List(data.length + 3); protobuf[0] = 3; protobuf[1] = (data.length & 0xff); protobuf[2] = ((data.length >> 8) & 0xff); protobuf.setRange(3, data.length + 3, data); socket!.add(protobuf); await socket!.flush(); isConnected = true; if (timer.isActive()) { timer.cancel(); } notifyListeners(); } /// 发送群组聊天 tag Future sendTag(String tag) async { Map map1 = {"tag": tag}; int time = DateTime.now().millisecondsSinceEpoch; Int64 timeStamp = Int64.parseInt(time.toString()); var body = sentbody.Model(data: map1); body.key = "client_set_tag"; body.timestamp = timeStamp; var data = body.writeToBuffer(); var protobuf = Uint8List(data.length + 3); protobuf[0] = 3; protobuf[1] = (data.length & 0xff); protobuf[2] = ((data.length >> 8) & 0xff); protobuf.setRange(3, data.length + 3, data); socket!.add(protobuf); await socket!.flush(); return 2; } //发送PONG响应 Future sendPong() async { var pONG = Uint8List(7); var pONGBODY = Uint8List(4); pONGBODY[0] = 80; pONGBODY[1] = 79; pONGBODY[2] = 78; pONGBODY[3] = 71; pONG[0] = PONG_TYPE; pONG[1] = (pONGBODY.length & 0xff); pONG[2] = ((pONGBODY.length >> 8) & 0xff); pONG.setRange(3, 6, pONGBODY); socket!.add(pONG); await socket!.flush(); isConnected = true; if (timer.isActive()) { timer.cancel(); } notifyListeners(); } ///消息分发器 Future switchMessage(messages.Model model) async { _model = model; notifyListeners(); } } class SystemInfo { String deviceName = 'cim_entity'; String version = '0.0.1'; String deviceId = 'CIM Entity'; String model = "10"; final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); Future init() async { if (Platform.isAndroid) { // Android相关代码 var value = await deviceInfoPlugin.androidInfo; deviceName = 'android'; version = value.version.release; deviceId = value.id; model = value.model; } else if (Platform.isIOS) { // iOS相关代码 var value = await deviceInfoPlugin.iosInfo; deviceName = 'ios'; version = value.systemVersion!; deviceId = value.identifierForVendor!; model = value.model!; } else if (Platform.isMacOS) { // MacOS相关代码 var value = await deviceInfoPlugin.macOsInfo; deviceName = 'macos'; version = value.kernelVersion; deviceId = value.model; model = value.model; } else if (Platform.isWindows) { // Windows相关代码 var value = await deviceInfoPlugin.windowsInfo; deviceName = 'windows'; version = value.displayVersion; deviceId = value.deviceId; model = value.majorVersion.toString(); } else if (Platform.isLinux) { // Linux相关代码 var value = await deviceInfoPlugin.linuxInfo; deviceName = 'linux'; version = value.version!; deviceId = value.id; model = value.version!; } } }