Browse Source

socketclient remove reconnect time

wr_202303
zsw 4 months ago
parent
commit
db76f9e15f
  1. 11
      assets/svg/shequn.svg
  2. 1
      lib/home/home_page.dart
  3. 73
      lib/im/SocketClient.dart
  4. 62
      lib/im/chat_details_page.dart
  5. 10
      lib/im/database/hx_database.dart
  6. 2
      lib/im/database/message.dart
  7. 72
      lib/im/im_view/im_page.dart
  8. 1
      lib/main_page.dart

11
assets/svg/shequn.svg

@ -1,14 +1,13 @@
<svg width="22.000000" height="22.000000" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <svg width="30.000000" height="30.000000" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc> <desc>
Created with Pixso. Created with Pixso.
</desc> </desc>
<defs> <defs>
<clipPath id="clip114_923"> <clipPath id="clip244_618">
<rect id="shequn" width="22.000000" height="22.000000" fill="white" fill-opacity="0"/> <rect id="shequn-2" width="23.000000" height="23.000000" transform="translate(4.000000 4.000000)" fill="white" fill-opacity="0"/>
</clipPath> </clipPath>
</defs> </defs>
<g clip-path="url(#clip114_923)"> <g clip-path="url(#clip244_618)">
<path id="path" d="M13.69 14.75C12.4 15.71 11.05 16.56 9.63 17.32C8.21 18.07 6.75 18.72 5.24 19.26C5.45 19.41 5.67 19.55 5.89 19.68C6.11 19.81 6.34 19.93 6.57 20.04C6.8 20.16 7.04 20.26 7.28 20.36C7.52 20.45 7.77 20.54 8.01 20.61C8.26 20.69 8.51 20.76 8.76 20.82C9.01 20.87 9.27 20.92 9.52 20.96C9.78 21 10.03 21.02 10.29 21.04C10.55 21.06 10.81 21.07 11.07 21.07C11.33 21.06 11.58 21.05 11.84 21.03C12.1 21.01 12.35 20.98 12.61 20.94C12.87 20.89 13.12 20.84 13.37 20.78C13.62 20.72 13.87 20.65 14.11 20.57C14.36 20.49 14.6 20.4 14.84 20.3C15.08 20.2 15.32 20.1 15.55 19.98C15.78 19.86 16 19.74 16.22 19.6C16.44 19.47 16.66 19.33 16.87 19.18C17.08 19.02 17.28 18.87 17.48 18.7C17.68 18.53 17.87 18.36 18.05 18.18C18.24 18 18.42 17.81 18.59 17.61C18.76 17.42 18.92 17.22 19.07 17.01C19.23 16.8 19.37 16.59 19.51 16.37C19.65 16.16 19.78 15.93 19.9 15.7C20.02 15.47 20.13 15.24 20.24 15.01C20.34 14.77 20.43 14.53 20.52 14.28C20.6 14.04 20.68 13.79 20.74 13.54C20.81 13.29 20.87 13.04 20.91 12.79C20.96 12.53 20.99 12.28 21.02 12.02C21.05 11.76 21.06 11.5 21.07 11.24C21.08 10.99 21.07 10.73 21.06 10.47C21.05 10.21 21.02 9.95 20.99 9.7C20.96 9.44 20.92 9.19 20.86 8.93C20.81 8.68 20.75 8.43 20.68 8.18C19.68 9.44 18.59 10.62 17.42 11.72C16.25 12.82 15.01 13.83 13.69 14.75Z" fill="#32A060" fill-opacity="1.000000" fill-rule="nonzero"/> <path id="path" d="M25.61 12.46C26.85 16.9 25.25 21.67 21.64 24.34C18 27.04 13.15 27.07 9.48 24.44C12.63 23.27 15.61 21.63 18.31 19.56C21.06 17.57 23.52 15.18 25.61 12.46ZM9.36 6.64C13.29 3.73 18.61 3.95 22.3 7.18C24.55 6.38 26.21 6.27 26.78 7.12C28 8.88 23.93 14.03 17.7 18.67C11.46 23.3 5.43 25.62 4.21 23.87C3.63 23.04 4.24 21.45 5.7 19.5C3.93 14.84 5.45 9.53 9.36 6.64ZM13.38 9.61C12.11 9.61 11.08 10.69 11.08 12.01C11.08 13.33 12.11 14.41 13.38 14.41C14.64 14.41 15.67 13.33 15.67 12.01C15.67 10.69 14.64 9.61 13.38 9.61Z" fill="#D8D8D8" fill-opacity="1.000000" fill-rule="nonzero"/>
<path id="path" d="M21.79 3.25C21.24 2.46 19.65 2.56 17.51 3.31C17.3 3.13 17.08 2.96 16.85 2.8C16.63 2.64 16.39 2.49 16.15 2.34C15.91 2.2 15.67 2.07 15.42 1.95C15.17 1.82 14.92 1.71 14.66 1.61C14.4 1.51 14.13 1.42 13.87 1.34C13.6 1.26 13.33 1.19 13.06 1.14C12.79 1.08 12.51 1.03 12.24 1C11.96 0.97 11.68 0.94 11.41 0.93C11.13 0.92 10.85 0.92 10.57 0.93C10.29 0.95 10.02 0.97 9.74 1C9.47 1.04 9.19 1.08 8.92 1.14C8.65 1.2 8.38 1.27 8.11 1.35C7.84 1.43 7.58 1.52 7.32 1.62C7.06 1.72 6.81 1.83 6.56 1.96C6.31 2.08 6.07 2.21 5.83 2.35C5.59 2.5 5.36 2.65 5.13 2.81C4.9 2.97 4.69 3.14 4.47 3.32C4.26 3.5 4.06 3.69 3.86 3.89C3.66 4.09 3.48 4.29 3.3 4.51C3.12 4.72 2.95 4.94 2.79 5.16C2.63 5.39 2.47 5.62 2.33 5.86C2.19 6.1 2.06 6.35 1.94 6.6C1.82 6.85 1.71 7.1 1.61 7.36C1.51 7.62 1.42 7.88 1.34 8.15C1.26 8.42 1.19 8.69 1.13 8.96C1.08 9.23 1.03 9.51 1 9.78C0.97 10.06 0.94 10.34 0.93 10.61C0.92 10.89 0.92 11.17 0.94 11.45C0.95 11.73 0.97 12 1.01 12.28C1.04 12.55 1.09 12.83 1.15 13.1C1.21 13.37 1.28 13.64 1.36 13.91C1.44 14.17 1.53 14.44 1.63 14.7C0.23 16.5 -0.35 17.97 0.2 18.73C1.36 20.36 7.14 18.21 13.1 13.93C19.07 9.64 22.95 4.87 21.79 3.25ZM10.15 9.83L9.18 11.07L8.64 9.6L7.44 8.64L8.91 8.12L9.87 6.89L10.39 8.36L11.62 9.33L10.15 9.83Z" fill="#32A060" fill-opacity="1.000000" fill-rule="nonzero"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

1
lib/home/home_page.dart

@ -855,4 +855,5 @@ class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
} }

73
lib/im/SocketClient.dart

@ -20,6 +20,8 @@ class SocketClient {
final num port = 9090; final num port = 9090;
Socket _socket; Socket _socket;
SharedPreferences _shared; SharedPreferences _shared;
Timer timer;
bool get heartbeatActive => timer != null && timer.isActive;
connect() async { connect() async {
_shared = await SharedPreferences.getInstance(); _shared = await SharedPreferences.getInstance();
@ -41,17 +43,17 @@ class SocketClient {
print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} '); print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} ');
Map<String, dynamic> messageMap = createMessage(userId, utf8.decode(dataResult.data), msgType: dataResult.type.value, userId: dataResult.from); Map<String, dynamic> 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) { if (callbacks[dataResult.from] != null) {
messageMap["state"] = 1; messageMap["state"] = 1;
message.state = 1;
callbacks[dataResult.from].call(message); /// user conversation callback
} }
hxDatabase.insert(messageMap).then((value) {
hxDatabase.insert(messageMap); messageMap["id"] = value;
Message message = Message.fromJson(messageMap);
if (callbacks[dataResult.from] != null) {
callbacks[dataResult.from].call(message); /// user conversation callback
}
callbacks[userId]?.call(message); /// user self conversation list callback
});
}, onError: (Object error, StackTrace stackTrace) { }, onError: (Object error, StackTrace stackTrace) {
debugPrint("socket-listen-error: $error, stackTrace: $stackTrace"); debugPrint("socket-listen-error: $error, stackTrace: $stackTrace");
showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace"); showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace");
@ -69,9 +71,6 @@ class SocketClient {
_socket = null; _socket = null;
reconnect(); reconnect();
}); });
// checkConnect();
} }
showDebugToast(text) { showDebugToast(text) {
@ -80,27 +79,53 @@ class SocketClient {
} }
} }
Proto heartbeatData() {
DateTime dateTime = DateTime.now();
int millisecondsTime = dateTime.millisecondsSinceEpoch;
Uint8List data = utf8.encode(jsonEncode({"heartbeat": millisecondsTime}));
MsgData msgData = MsgData(from: userId, type: MsgType.TEXT, data: data);
final proto2 = Proto(3, 1, msgData.writeToBuffer());
debugPrint("heartbeat: ${dateTime.toString()}");
return proto2;
}
heartbeat() { heartbeat() {
Timer.periodic(const Duration(milliseconds: 30000), (timer) { cancelTimer();
int millisecondsTime = DateTime.now().millisecondsSinceEpoch; timer = Timer.periodic(const Duration(milliseconds: 30000), (timer) {
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()) { if(!checkSocket()) {
timer.cancel(); timer.cancel();
return; return;
} }
try { sendHeartBeatAndCheckSocket();
_socket.add(proto2.toBytes());
} catch (e) {
debugPrint("socket-send-error: ${e.toString()}");
showDebugToast("socket-send-error: ${e.toString()}");
reconnect();
}
}); });
} }
/// send heartBeat and check socket is connected
/// send error: reconnect,
/// else check Timer.periodic isActive ,
/// if not active: Timer.periodic send heartBeat
sendHeartBeatAndCheckSocket() {
final proto2 = heartbeatData();
try {
_socket.add(proto2.toBytes());
if (!socketClient.heartbeatActive) {
heartbeat();
debugPrint("socket-periodic-send-heart-beat");
}
} catch (e) {
debugPrint("socket-send-error: ${e.toString()}");
showDebugToast("socket-send-error: ${e.toString()}");
reconnect();
}
}
cancelTimer() {
if (timer != null && timer.isActive) {
timer.cancel();
timer = null;
}
}
reconnect() { reconnect() {
dispose(); dispose();
connect(); connect();

62
lib/im/chat_details_page.dart

@ -89,8 +89,10 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
socketClient.addCallback(_toUser.mid, (Message message) { socketClient.addCallback(_toUser.mid, (Message message) {
messages.insert(0, message); messages.insert(0, message);
refreshState(); messageShowTime().then((value) {
jumpToBottom(); refreshState();
jumpToBottom();
});
}); });
refreshState(); refreshState();
jumpToBottom(); jumpToBottom();
@ -105,6 +107,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
} else { } else {
messages.addAll(messagePage); messages.addAll(messagePage);
} }
await messageShowTime();
if (messagePage.isEmpty) { if (messagePage.isEmpty) {
refreshController.loadNoData(); refreshController.loadNoData();
return; return;
@ -114,6 +117,14 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
return Future.value(); return Future.value();
} }
Future messageShowTime() async {
List<Message> messagePages = await hxDatabase.queryTList(_toUser.mid);
for (var value in messages) {
Message message = messagePages.firstWhere((element) => value.id == element.id, orElse: () => null);
value.showTime = message != null;
}
}
/// ///
queryUser() async { queryUser() async {
final SharedPreferences value = await SharedPreferences.getInstance(); final SharedPreferences value = await SharedPreferences.getInstance();
@ -123,10 +134,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
userInfo = UserInfo.fromJson(jsonDecode(value.getString('user'))); userInfo = UserInfo.fromJson(jsonDecode(value.getString('user')));
} }
if (apiService == null) if (apiService == null)
apiService = apiService = ApiService(Dio(), context: context, token: value.getString("token"));
ApiService(Dio(), context: context, token: value.getString("token")); BaseData<UserInfo> baseData = await apiService.queryInfo().catchError((onError) {});
BaseData<UserInfo> baseData =
await apiService.queryInfo().catchError((onError) {});
if (baseData != null && baseData.isSuccess) { if (baseData != null && baseData.isSuccess) {
setState(() { setState(() {
userInfo = baseData.data; userInfo = baseData.data;
@ -374,7 +383,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
child: SingleChildScrollView( child: SingleChildScrollView(
physics: BouncingScrollPhysics(), physics: BouncingScrollPhysics(),
controller: scrollController, controller: scrollController,
child: chatDetailsList()), child: chatDetailsList(),
),
), ),
flex: 1, flex: 1,
), ),
@ -382,7 +392,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
], ],
), ),
), ),
)); ),
);
} }
/// ///
@ -419,24 +430,25 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
), ),
child: Column( child: Column(
children: [ children: [
Text( if (messages[position].showTime)
// position == messages.length-1 Text(
// ? // position == messages.length-1
AppUtils.milliTimeFormatter(DateTime.fromMillisecondsSinceEpoch( // ?
int.parse(messages[position].time))) AppUtils.milliTimeFormatter(DateTime.fromMillisecondsSinceEpoch(
// : AppUtils.getTimeDisplay( int.parse(messages[position].time)))
// DateTime.fromMillisecondsSinceEpoch( // : AppUtils.getTimeDisplay(
// int.parse(messages[position].time)), // DateTime.fromMillisecondsSinceEpoch(
// DateTime.fromMillisecondsSinceEpoch( // int.parse(messages[position].time)),
// int.parse(messages[position+1].time))) // DateTime.fromMillisecondsSinceEpoch(
, // int.parse(messages[position+1].time)))
textAlign: TextAlign.center, ,
style: TextStyle( textAlign: TextAlign.center,
color: Color(0xFFA29E9E), style: TextStyle(
fontSize: 10.sp, color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular, fontSize: 10.sp,
fontWeight: MyFontWeight.regular,
),
), ),
),
// if (messages.indexOf(message) == (messages.length - 1)) // if (messages.indexOf(message) == (messages.length - 1))
// Padding( // Padding(
// padding: EdgeInsets.only(top: 10.h, bottom: 24.h), // padding: EdgeInsets.only(top: 10.h, bottom: 24.h),

10
lib/im/database/hx_database.dart

@ -106,6 +106,16 @@ class HxDatabase {
}); });
} }
Future<List<Message>> queryTList(userId) async{
await _dbIsOpen();
String sql = 'SELECT *, time / 300000 * 300000 AS time_interval FROM Message WHERE toId = ? OR fromId = ? GROUP BY time_interval ORDER BY time DESC';
return db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) => Message.fromJson(e)).toList();
}, onError: (error) {
debugPrint("Messageerror: $error");
});
}
Future<Map<String, int>> messageUnreadCount(List<String> userIds, String selfUserId) async { Future<Map<String, int>> messageUnreadCount(List<String> userIds, String selfUserId) async {
await _dbIsOpen(); await _dbIsOpen();
String userStr = userIds.join(","); String userStr = userIds.join(",");

2
lib/im/database/message.dart

@ -21,6 +21,8 @@ class Message {
int isDelete; int isDelete;
bool showTime = false;
Message(this.id, this.fromId, this.toId, this.replyId, this.content, this.attach, this.msgType, this.time, this.state, this.isDelete); Message(this.id, this.fromId, this.toId, this.replyId, this.content, this.attach, this.msgType, this.time, this.state, this.isDelete);
factory Message.fromJson(Map<String, dynamic> json) => Message( factory Message.fromJson(Map<String, dynamic> json) => Message(

72
lib/im/im_view/im_page.dart

@ -197,72 +197,6 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
if (mounted) setState(() {}); if (mounted) setState(() {});
} }
// queryMessage() async {
// BaseData<PageInfo<Message>> baseData = await apiService.msgList({
// "pageNum": pageNum,
// "pageSize": 10,
// "searchKey": "",
// "state": "",
// "typed": ""
// }).catchError((onError) {
// _refreshController.loadFailed();
// _refreshController.refreshFailed();
// });
//
// if (baseData != null && baseData.isSuccess) {
// if (pageNum == 1) {
// messages.clear();
// }
// List<Message> message = [];
// message.addAll(baseData.data.list);
// message.forEach((element) {
// if (element.typed == 2 || element.typed == 3) {
// messages.add(element);
// }
// });
// _refreshController.loadComplete();
// _refreshController.refreshCompleted();
// if (mounted) setState(() {});
// if (pageNum * 10 > int.tryParse(baseData.data.total)) {
// _refreshController.loadNoData();
// } else {
// pageNum += 1;
// }
// } else {
// _refreshController.loadFailed();
// _refreshController.refreshFailed();
// }
// }
// queryMsgStats() async {
// if (apiService == null) {
// SharedPreferences value = await SharedPreferences.getInstance();
// apiService = ApiService(
// Dio(),
// context: context,
// token: value.getString("token"),
// );
// }
// BaseData<List<MsgStats>> baseData = await apiService.stats().catchError((onError) {
// debugPrint("stats.error: $onError");
// });
// if (baseData != null && baseData.isSuccess) {
// setState(() {
// msgNumber.forEach((key, value) {
// msgNumber[key] = 0;
// });
// baseData.data.forEach((element) {
// if (msgNumber.containsKey(element.name)) {
// msgNumber[element.name] = element.number;
// }
// });
// });
// _refreshController.loadComplete();
// _refreshController.refreshCompleted();
// }
// EasyLoading.dismiss();
// }
/// ///
queryMemberInfo(List<String> mids) async { queryMemberInfo(List<String> mids) async {
if (mids.isEmpty) { if (mids.isEmpty) {
@ -271,8 +205,10 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
BaseData<List<ImUser>> baseData = await apiService.memberInfoByIds({ BaseData<List<ImUser>> baseData = await apiService.memberInfoByIds({
"mids": mids, "mids": mids,
}).catchError((error) { }).catchError((error) {
SmartDialog.showToast(AppUtils.dioErrorTypeToString(error.type), SmartDialog.showToast(
alignment: Alignment.center); AppUtils.dioErrorTypeToString(error.type),
alignment: Alignment.center,
);
}); });
if (baseData != null && baseData.isSuccess) { if (baseData != null && baseData.isSuccess) {
if (baseData.data.isNotEmpty) { if (baseData.data.isNotEmpty) {

1
lib/main_page.dart

@ -82,6 +82,7 @@ class _MainPage extends State<MainPage> with WidgetsBindingObserver {
break; break;
case AppLifecycleState.resumed: // case AppLifecycleState.resumed: //
pushRoute(); pushRoute();
socketClient.sendHeartBeatAndCheckSocket();
if (DateTime.now().millisecondsSinceEpoch - lastTime > 420000) if (DateTime.now().millisecondsSinceEpoch - lastTime > 420000)
//** //**
// Navigator.of(context).popAndPushNamed('/router/start_page'); // Navigator.of(context).popAndPushNamed('/router/start_page');

Loading…
Cancel
Save