import 'dart:async'; import 'dart:convert'; import 'dart:core'; import 'dart:core'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:huixiang/im/Proto.dart'; import 'package:huixiang/im/database/message.dart'; import 'package:huixiang/im/out/auth.pb.dart'; import 'package:huixiang/im/out/message.pb.dart'; import 'package:huixiang/main.dart'; import 'package:shared_preferences/shared_preferences.dart'; class SocketClient { //47.93.216.24:9090 线上 192.168.10.129:9090 测试 final String ip = kDebugMode ? '192.168.10.129' : '47.93.216.24'; final num port = 9090; Socket _socket; SharedPreferences _shared; connect() async { _shared = await SharedPreferences.getInstance(); if (_socket != null) { reconnect(); return; } showDebugToast("socket-connect .... "); await Socket.connect(ip, port).then((value) { debugPrint("socket-connect-$ip"); _socket = value; _socket.listen((data) { print(data); print("socket-listen"); Proto proto = Proto.fromBytes(data); MsgData dataResult = MsgData.fromBuffer(proto.body); print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} '); Map messageMap = createMessage(userId, utf8.decode(dataResult.data), msgType: dataResult.type.value, userId: dataResult.from); Message message = Message.fromJson(messageMap); callbacks[userId]?.call(message); /// user self conversation list callback if (callbacks[dataResult.from] != null) { messageMap["state"] = 1; message.state = 1; callbacks[dataResult.from].call(message); /// user conversation callback } hxDatabase.insert(messageMap); }, onError: (Object error, StackTrace stackTrace) { debugPrint("socket-listen-error: $error, stackTrace: $stackTrace"); showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace"); reconnect(); }, onDone: () { debugPrint("socket-listen-down: down"); }); authRequest(_shared.getString("token")); heartbeat(); }).catchError((error) { debugPrint("socket-connect-error: $error"); showDebugToast("socket-connect-error: $error"); reconnectTime = 1500; _socket = null; reconnect(); }); } showDebugToast(text) { if (kDebugMode) { SmartDialog.showToast(text, alignment: Alignment.center); } } heartbeat() { Timer.periodic(const Duration(milliseconds: 30000), (timer) { int millisecondsTime = DateTime.now().millisecondsSinceEpoch; debugPrint("heartbeat: $millisecondsTime"); Uint8List data = utf8.encode(jsonEncode({"heartbeat": millisecondsTime})); MsgData msgData = MsgData(from: userId, type: MsgType.TEXT, data: data); final proto2 = Proto(3, 1, msgData.writeToBuffer()); if(!checkSocket()) { timer.cancel(); return; } _socket.add(proto2.toBytes()); }); } int reconnectTime = 1500; reconnect() { Future.delayed(Duration(milliseconds: reconnectTime), () { dispose(); connect(); }); } Map callbacks = {}; addCallback(String userId, callback) { callbacks[userId] = callback; } removeCallback(String userId) { callbacks.remove(userId); } dispose() { if (_socket != null) { _socket.close(); _socket = null; } } authRequest(String token) { if (!checkSocket()) { return; } final authReq = AuthReq() ..uid = userId ..token = token; final authReqBytes = authReq.writeToBuffer(); final proto = Proto(1, 1, authReqBytes); // 假设 operation 和 seqId 为 1 final protoBytes = proto.toBytes(); _socket.add(protoBytes); } Future sendMessage(String toId, String content) async { Map message = createMessage(toId, content, userId: userId); int id = await hxDatabase.insert(message).catchError((error) { debugPrint("insertMessage: $error"); }); if (!checkSocket()) { hxDatabase.update({"id": id, "state": 3}).catchError((error) { debugPrint("insertMessage: ${error.toString()}"); }); message["id"] = id; message["state"] = 3; return Message.fromJson(message); } message["id"] = id; Uint8List data = utf8.encode(content); MsgData msgData = MsgData(to: toId, from: userId, type: MsgType.TEXT, data: data); final proto2 = Proto(5, 1, msgData.writeToBuffer()); _socket.add(proto2.toBytes()); debugPrint("sendMessage: ${message["id"]}"); return Message.fromJson(message); } checkSocket() { if (_socket == null) { reconnectTime = 1000; reconnect(); return false; } return true; } String get userId => _shared.getString("userId"); }