2023-06-14 09:36:31 +08:00

269 lines
7.6 KiB
Dart

// ignore: file_names
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 Message;
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 SOCKET_APP_VERSION = '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) {
connect();
});
late bool isConnected = false;
late Message.Model? model = null;
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);
Message.Model model = Message.Model();
model.mergeFromBuffer(message);
switchMessage(model);
}
}, onError: (error, StackTrace trace) {
print('CIMSocket error');
socket = null;
isConnected = false;
if (!timer.isActive()) {
timer.startTimer();
}
notifyListeners();
}, onDone: () {
print('CIMSocket done');
socket = null;
isConnected = false;
notifyListeners();
if (endCode != "999") {
if (!timer.isActive()) {
timer.startTimer();
}
}
}, cancelOnError: true);
socket = sock;
sendLoginMsg();
}).catchError((e) {
print('CIMSocket catcherror');
print('Unable to connect: $e');
socket = null;
isConnected = false;
notifyListeners();
// Future.delayed(Duration(milliseconds: 3000), () {
// connect();
// });
if (!timer.isActive()) {
timer.startTimer();
}
});
}
//登出
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<String, String> map = {
"uid": uid.toString(), //主id
"channel": channel,
"appVersion": SOCKET_APP_VERSION,
"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();
print('CIMSocket login finished');
isConnected = true;
if (timer.isActive()) {
timer.cancel();
}
notifyListeners();
}
/// 发送群组聊天 tag
Future<int> sendTag(String tag) async {
Map<String, String> 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();
print('CIMSocket bind chattingTag Success!');
return 2;
}
//发送PONG响应
Future sendPong() async {
var PONG = Uint8List(7);
var PONG_BODY = Uint8List(4);
PONG_BODY[0] = 80;
PONG_BODY[1] = 79;
PONG_BODY[2] = 78;
PONG_BODY[3] = 71;
PONG[0] = PONG_TYPE;
PONG[1] = (PONG_BODY.length & 0xff);
PONG[2] = ((PONG_BODY.length >> 8) & 0xff);
PONG.setRange(3, 6, PONG_BODY);
socket!.add(PONG);
await socket!.flush();
isConnected = true;
if (timer.isActive()) {
timer.cancel();
}
notifyListeners();
}
///消息分发器
Future switchMessage(Message.Model model, {bool isHistory = false}) async {
print(model.toProto3Json());
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!;
}
}
}