From 1cc084627c27b84e6dcc4316822cae770a3748f4 Mon Sep 17 00:00:00 2001 From: Sun Date: Wed, 26 May 2021 22:44:59 +0800 Subject: [PATCH] apply new session online design --- lib/apps/chat/detail.dart | 60 +++++++----- lib/apps/chat/list.dart | 8 +- lib/apps/device/page.dart | 4 +- lib/apps/file/page.dart | 2 +- lib/apps/group_chat/page.dart | 7 +- lib/apps/service/list.dart | 4 +- lib/apps/service/models.dart | 6 +- lib/pages/home.dart | 10 +- lib/provider.dart | 131 +++++++++++++++++++------- lib/session.dart | 23 +++-- lib/widgets/default_home_show.dart | 51 +++++++--- lib/widgets/list_service.dart | 84 ----------------- src/apps/chat/layer.rs | 86 ++++++++++++----- src/apps/group_chat/layer.rs | 32 ++++++- src/event.rs | 10 -- src/layer.rs | 144 +++++++++++++++++++++-------- src/migrate/session.rs | 5 +- src/rpc.rs | 112 ++++++++++++++++------ src/session.rs | 19 ++-- 19 files changed, 507 insertions(+), 291 deletions(-) delete mode 100644 lib/widgets/list_service.dart diff --git a/lib/apps/chat/detail.dart b/lib/apps/chat/detail.dart index 31ba5f9..3ca90a1 100644 --- a/lib/apps/chat/detail.dart +++ b/lib/apps/chat/detail.dart @@ -13,6 +13,7 @@ import 'package:esse/widgets/user_info.dart'; import 'package:esse/widgets/chat_message.dart'; import 'package:esse/global.dart'; import 'package:esse/provider.dart'; +import 'package:esse/session.dart'; import 'package:esse/apps/primitives.dart'; import 'package:esse/apps/chat/models.dart'; @@ -46,7 +47,9 @@ class _ChatDetailState extends State { bool recordShow = false; String _recordName; - Friend friend; + int _actived; + Friend _friend; + String _meName; @override initState() { @@ -60,12 +63,21 @@ class _ChatDetailState extends State { }); } }); + new Future.delayed(Duration.zero, () { + final accountProvider = context.read(); + final chatProvider = context.read(); + this._actived = accountProvider.activedSession.fid; + this._meName = accountProvider.activedAccount.name; + this._friend = chatProvider.friends[this._actived]; + chatProvider.updateActivedFriend(this._actived); + setState(() {}); + }); } _generateRecordPath() { this._recordName = DateTime.now().millisecondsSinceEpoch.toString() + '_' + - this.friend.id.toString() + + this._actived.toString() + '.m4a'; } @@ -74,7 +86,7 @@ class _ChatDetailState extends State { return; } - context.read().messageCreate(Message(friend.id, MessageType.String, textController.text)); + context.read().messageCreate(Message(_actived, MessageType.String, textController.text)); setState(() { textController.text = ''; textFocus.requestFocus(); @@ -93,7 +105,7 @@ class _ChatDetailState extends State { void _sendImage() async { final image = await pickImage(); if (image != null) { - context.read().messageCreate(Message(friend.id, MessageType.Image, image)); + context.read().messageCreate(Message(_actived, MessageType.Image, image)); } setState(() { textFocus.requestFocus(); @@ -107,7 +119,7 @@ class _ChatDetailState extends State { void _sendFile() async { final file = await pickFile(); if (file != null) { - context.read().messageCreate(Message(friend.id, MessageType.File, file)); + context.read().messageCreate(Message(_actived, MessageType.File, file)); } setState(() { textFocus.requestFocus(); @@ -120,7 +132,7 @@ class _ChatDetailState extends State { void _sendRecord(int time) async { final raw = BaseMessage.rawRecordName(time, _recordName); - context.read().messageCreate(Message(friend.id, MessageType.Record, raw)); + context.read().messageCreate(Message(_actived, MessageType.Record, raw)); setState(() { textFocus.requestFocus(); @@ -165,7 +177,7 @@ class _ChatDetailState extends State { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () async { - context.read().messageCreate(Message(friend.id, MessageType.Contact, "${contact.id}")); + context.read().messageCreate(Message(_actived, MessageType.Contact, "${contact.id}")); Navigator.of(context).pop(); setState(() { textFocus.requestFocus(); @@ -201,16 +213,16 @@ class _ChatDetailState extends State { final recentMessages = provider.activedMessages; final recentMessageKeys = recentMessages.keys.toList().reversed.toList(); - final meName = context.read().activedAccount.name; - this.friend = provider.activedFriend; + final session = context.watch().activedSession; - if (this.friend == null) { + if (this._friend == null) { return Container( padding: EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0, bottom: 10.0), child: Text('Waiting...') ); } - final isOnline = this.friend.online; + + final isOnline = session.online == OnlineType.Active; return Column( children: [ @@ -235,11 +247,11 @@ class _ChatDetailState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - this.friend.name, + this._friend.name, style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 6.0), - Text(this.friend.isClosed + Text(this._friend.isClosed ? lang.unfriended : (isOnline ? lang.online : lang.offline), style: TextStyle( @@ -278,9 +290,9 @@ class _ChatDetailState extends State { Icons.info, lang.friendInfo, UserInfo( - id: 'EH' + this.friend.gid.toUpperCase(), - name: this.friend.name, - addr: '0x' + this.friend.addr) + id: 'EH' + this._friend.gid.toUpperCase(), + name: this._friend.name, + addr: '0x' + this._friend.addr) ); } else if (value == 3) { print('TODO remark'); @@ -290,7 +302,7 @@ class _ChatDetailState extends State { builder: (BuildContext context) { return AlertDialog( title: Text(lang.unfriend), - content: Text(this.friend.name, + content: Text(this._friend.name, style: TextStyle(color: color.primary)), actions: [ TextButton( @@ -302,7 +314,7 @@ class _ChatDetailState extends State { onPressed: () { Navigator.pop(context); Provider.of( - context, listen: false).friendClose(this.friend.id); + context, listen: false).friendClose(this._friend.id); if (!isDesktop) { Navigator.pop(context); } @@ -314,14 +326,14 @@ class _ChatDetailState extends State { ); } else if (value == 5) { Provider.of(context, listen: false).requestCreate( - Request(this.friend.gid, this.friend.addr, this.friend.name, lang.fromContactCard(meName))); + Request(this._friend.gid, this._friend.addr, this._friend.name, lang.fromContactCard(this._meName))); } else if (value == 6) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(lang.delete + " " + lang.friend), - content: Text(this.friend.name, + content: Text(this._friend.name, style: TextStyle(color: Colors.red)), actions: [ TextButton( @@ -333,7 +345,7 @@ class _ChatDetailState extends State { onPressed: () { Navigator.pop(context); Provider.of( - context, listen: false).friendDelete(this.friend.id); + context, listen: false).friendDelete(this._friend.id); if (!isDesktop) { Navigator.pop(context); } @@ -349,7 +361,7 @@ class _ChatDetailState extends State { return >[ _menuItem(Color(0xFF6174FF), 2, Icons.qr_code_rounded, lang.friendInfo), //_menuItem(color.primary, 3, Icons.turned_in_rounded, lang.remark), - this.friend.isClosed + this._friend.isClosed ? _menuItem(Color(0xFF6174FF), 5, Icons.send_rounded, lang.addFriend) : _menuItem(Color(0xFF6174FF), 4, Icons.block_rounded, lang.unfriend), _menuItem(Colors.red, 6, Icons.delete_rounded, lang.delete), @@ -366,11 +378,11 @@ class _ChatDetailState extends State { itemCount: recentMessageKeys.length, reverse: true, itemBuilder: (BuildContext context, index) => ChatMessage( - name: this.friend.name, + name: this._friend.name, message: recentMessages[recentMessageKeys[index]], ) )), - if (!this.friend.isClosed) + if (!this._friend.isClosed) Container( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), child: Row( diff --git a/lib/apps/chat/list.dart b/lib/apps/chat/list.dart index 04803aa..0ce3741 100644 --- a/lib/apps/chat/list.dart +++ b/lib/apps/chat/list.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:esse/utils/adaptive.dart'; import 'package:esse/l10n/localizations.dart'; import 'package:esse/provider.dart'; +import 'package:esse/session.dart'; import 'package:esse/apps/chat/provider.dart'; import 'package:esse/apps/chat/models.dart'; @@ -34,7 +35,7 @@ class _ChatListState extends State { onPressed: () { final widget = ChatAddPage(); if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widget); + Provider.of(context, listen: false).updateActivedSession(0, widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } @@ -60,7 +61,6 @@ class ListChat extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { - context.read().updateActivedFriend(friend.id); if (!isDesktop) { Navigator.push( context, @@ -69,7 +69,9 @@ class ListChat extends StatelessWidget { ), ); } else { - context.read().updateActivedApp(ChatDetail()); + context.read().updateActivedSessionFromList( + friend.id, SessionType.Chat, ChatDetail() + ); } }, child: Container( diff --git a/lib/apps/device/page.dart b/lib/apps/device/page.dart index d7475b2..cbbaf70 100644 --- a/lib/apps/device/page.dart +++ b/lib/apps/device/page.dart @@ -152,7 +152,7 @@ class _DevicesPageState extends State { Provider.of(context, listen: false).updateActivedDevice(device.id); final widget = DeviceListenPage(); if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widget); + Provider.of(context, listen: false).updateActivedSession(0, widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } @@ -355,7 +355,7 @@ class _DeviceListenPageState extends State { onTap: () { Provider.of(context, listen: false).clear(); if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(DevicesPage()); + Provider.of(context, listen: false).updateActivedSession(0, DevicesPage()); } else { Navigator.pop(context); } diff --git a/lib/apps/file/page.dart b/lib/apps/file/page.dart index e06e839..fb2f78d 100644 --- a/lib/apps/file/page.dart +++ b/lib/apps/file/page.dart @@ -39,7 +39,7 @@ class _FolderListState extends State { loadFolder(bool isDesktop, int index) async { final widget = FilePage(title: FILE_DIRECTORY[index][0]); if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widget); + Provider.of(context, listen: false).updateActivedSession(0, widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } diff --git a/lib/apps/group_chat/page.dart b/lib/apps/group_chat/page.dart index 7b17083..d71263e 100644 --- a/lib/apps/group_chat/page.dart +++ b/lib/apps/group_chat/page.dart @@ -5,6 +5,7 @@ import 'package:esse/utils/adaptive.dart'; import 'package:esse/utils/file_image.dart'; import 'package:esse/l10n/localizations.dart'; import 'package:esse/provider.dart'; +import 'package:esse/session.dart'; import 'package:esse/apps/group_chat/add.dart'; import 'package:esse/apps/group_chat/detail.dart'; @@ -34,7 +35,7 @@ class _GroupChatListState extends State { onPressed: () { final widget = GroupAddPage(); if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widget); + Provider.of(context, listen: false).updateActivedSession(0, widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } @@ -68,7 +69,9 @@ class ListChat extends StatelessWidget { ), ); } else { - context.read().updateActivedApp(GroupChatDetail()); + context.read().updateActivedSessionFromList( + group.id, SessionType.Group, GroupChatDetail() + ); } }, child: Container( diff --git a/lib/apps/service/list.dart b/lib/apps/service/list.dart index 6f92bca..31660ac 100644 --- a/lib/apps/service/list.dart +++ b/lib/apps/service/list.dart @@ -73,10 +73,10 @@ class ListInnerService extends StatelessWidget { final widgets = this.callback(); if (widgets != null) { if (this.isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widgets[0], widgets[1], widgets[2]); + Provider.of(context, listen: false).updateActivedSession(0, widgets[0], widgets[1], widgets[2]); } else { if (widgets[2] != null) { - Provider.of(context, listen: false).updateActivedApp(null, widgets[1], widgets[2]); + Provider.of(context, listen: false).updateActivedSession(0, null, widgets[1], widgets[2]); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widgets[0])); } diff --git a/lib/apps/service/models.dart b/lib/apps/service/models.dart index 3e95f05..4f8488e 100644 --- a/lib/apps/service/models.dart +++ b/lib/apps/service/models.dart @@ -46,17 +46,17 @@ extension InnerServiceExtension on InnerService { listHome = GroupChatList(); break; } - Provider.of(context, listen: false).updateActivedApp(coreWidget, listTitle, listHome); + Provider.of(context, listen: false).updateActivedSession(0, coreWidget, listTitle, listHome); } else { switch (this) { case InnerService.Files: - Provider.of(context, listen: false).updateActivedApp(null, lang.files, FolderList()); + Provider.of(context, listen: false).updateActivedSession(0, null, lang.files, FolderList()); break; case InnerService.Assistant: Navigator.push(context, MaterialPageRoute(builder: (_) => AssistantPage())); break; case InnerService.GroupChat: - Provider.of(context, listen: false).updateActivedApp(null, lang.groupChat, GroupChatList()); + Provider.of(context, listen: false).updateActivedSession(0, null, lang.groupChat, GroupChatList()); break; } } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 2c95545..1cc6465 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -135,7 +135,7 @@ class _HomeListState extends State with SingleTickerProviderStateMixin .systemAppFriendAddNew = false; if (isDesktop) { Provider.of(context, listen: false) - .updateActivedApp(widget); + .updateActivedSession(0, widget); } else { Navigator.push( context, MaterialPageRoute(builder: (_) => widget)); @@ -199,7 +199,7 @@ class _HomeListState extends State with SingleTickerProviderStateMixin } else if (value == 1) { final widget = ChatAddPage(); if (isDesktop) { - provider.updateActivedApp(widget); + provider.updateActivedSession(0, widget); } else { provider.systemAppFriendAddNew = false; setState(() {}); @@ -319,7 +319,7 @@ class DrawerWidget extends StatelessWidget { final widget = DevicesPage(); if (isDesktop) { Provider.of(context, listen: false) - .updateActivedApp(widget); + .updateActivedSession(0, widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } @@ -387,7 +387,7 @@ class DrawerWidget extends StatelessWidget { style: TextStyle(fontSize: 16.0)), onTap: () { Navigator.pop(context); - Provider.of(context, listen: false).updateActivedApp( + Provider.of(context, listen: false).updateActivedSession(0, null, lang.contact, ChatList() ); }), @@ -397,7 +397,7 @@ class DrawerWidget extends StatelessWidget { style: TextStyle(fontSize: 16.0)), onTap: () { Navigator.pop(context); - Provider.of(context, listen: false).updateActivedApp( + Provider.of(context, listen: false).updateActivedSession(0, null, lang.groups, ServiceList() ); }), diff --git a/lib/provider.dart b/lib/provider.dart index a4f28ab..0500edf 100644 --- a/lib/provider.dart +++ b/lib/provider.dart @@ -20,22 +20,30 @@ class AccountProvider extends ChangeNotifier { String activedAccountId; // actived account gid. Account get activedAccount => this.accounts[activedAccountId]; + /// current user's did. + String get id => this.activedAccount.id; + + bool systemAppFriendAddNew = false; + + /// home sessions. sorded by last_time. Map sessions = {}; List topKeys = []; List orderKeys = []; - /// current user's did. - String get id => this.activedAccount.id; + /// actived session. + int actived = 0; + Session get activedSession => this.sessions[actived]; + /// left home list sessions widget. String homeShowTitle = ''; Widget defaultListShow = DefaultHomeShow(); Widget currentListShow = null; - Widget coreShowWidget = DefaultCoreShow(); - bool systemAppFriendAddNew = false; - Widget get homeShowWidget => this.currentListShow ?? this.defaultListShow; + /// right main screen show session details. + Widget coreShowWidget = DefaultCoreShow(); + void orderSessions(int id) { if (this.orderKeys.length == 0 || this.orderKeys[0] != id) { this.orderKeys.remove(id); @@ -56,7 +64,10 @@ class AccountProvider extends ChangeNotifier { rpc.addListener('session-last', _sessionLast, true); rpc.addListener('session-create', _sessionCreate, true); rpc.addListener('session-update', _sessionUpdate, false); - rpc.addListener('session-delete', _sessionDelete, false); + rpc.addListener('session-close', _sessionClose, false); + rpc.addListener('session-connect', _sessionConnect, false); + rpc.addListener('session-suspend', _sessionSuspend, false); + rpc.addListener('session-lost', _sessionLost, false); systemInfo(); } @@ -162,24 +173,6 @@ class AccountProvider extends ChangeNotifier { notifyListeners(); } - updateToHome() { - this.homeShowTitle = ''; - this.currentListShow = null; - notifyListeners(); - } - - updateActivedApp([Widget coreWidget, String title, Widget homeWidget]) { - if (homeWidget != null && title != null) { - this.homeShowTitle = title; - this.currentListShow = homeWidget; - } - if (coreWidget != null) { - this.coreShowWidget = coreWidget; - } - this.systemAppFriendAddNew = false; - notifyListeners(); - } - clearActivedAccount() { this.topKeys.clear(); } @@ -208,6 +201,58 @@ class AccountProvider extends ChangeNotifier { rpc.send('account-system-info', []); } + updateToHome() { + this.homeShowTitle = ''; + this.currentListShow = null; + notifyListeners(); + } + + updateActivedSessionFromList(int fid, SessionType type, Widget coreWidget) { + int id = 0; + + for (int k in this.sessions.keys) { + final v = this.sessions[k]; + if (v.type == type && v.fid == fid) { + id = k; + break; + } + } + + if (id > 0) { + if (this.actived > 0) { + rpc.send('session-suspend', [this.actived, this.activedSession.gid]); + } + this.actived = id; + if (this.activedSession.online == OnlineType.Lost) { + rpc.send('session-connect', [id, this.activedSession.gid]); + } + } + } + + updateActivedSession(int id, [Widget coreWidget, String title, Widget homeWidget]) { + if (id > 0) { + if (this.actived > 0) { + rpc.send('session-suspend', [this.actived, this.activedSession.gid]); + } + this.actived = id; + if (this.activedSession.online == OnlineType.Lost) { + rpc.send('session-connect', [id, this.activedSession.gid]); + } + } + + if (homeWidget != null && title != null) { + this.homeShowTitle = title; + this.currentListShow = homeWidget; + } + + if (coreWidget != null) { + this.coreShowWidget = coreWidget; + } + + this.systemAppFriendAddNew = false; + notifyListeners(); + } + // -- callback when receive rpc info. -- // _systemInfo(List params) { Global.addr = '0x' + params[0]; @@ -248,13 +293,13 @@ class AccountProvider extends ChangeNotifier { params.forEach((params) { final id = params[0]; this.sessions[id] = Session.fromList(params); - - if (this.sessions[id].isTop) { - this.topKeys.add(id); - } else { - this.orderKeys.add(id); + if (!this.sessions[id].isClose) { + if (this.sessions[id].isTop) { + this.topKeys.add(id); + } else { + this.orderKeys.add(id); + } } - }); notifyListeners(); } @@ -286,11 +331,31 @@ class AccountProvider extends ChangeNotifier { notifyListeners(); } - _sessionDelete(List params) { - final id = params[1]; - this.sessions.remove(id); + _sessionClose(List params) { + final id = params[0]; + this.sessions[id].isClose = true; this.orderKeys.remove(id); this.topKeys.remove(id); notifyListeners(); } + + _sessionConnect(List params) { + final id = params[0]; + final addr = params[1]; + this.sessions[id].addr = addr; + this.sessions[id].online = OnlineType.Active; + notifyListeners(); + } + + _sessionSuspend(List params) { + final id = params[0]; + this.sessions[id].online = OnlineType.Suspend; + notifyListeners(); + } + + _sessionLost(List params) { + final id = params[0]; + this.sessions[id].online = OnlineType.Lost; + notifyListeners(); + } } diff --git a/lib/session.dart b/lib/session.dart index 0a81a4a..339d589 100644 --- a/lib/session.dart +++ b/lib/session.dart @@ -40,6 +40,13 @@ extension SessionTypeExtension on SessionType { } } +enum OnlineType { + Waiting, + Active, + Suspend, + Lost, +} + class Session { int id; int fid; @@ -48,10 +55,11 @@ class Session { SessionType type; String name; bool isTop; + bool isClose; RelativeTime lastTime; String lastContent; bool lastReaded; - bool online = false; + OnlineType online; static List innerService(InnerService service, AppLocalizations lang) { final params = service.params(lang); @@ -87,13 +95,14 @@ class Session { width: width, name: this.name, avatarPath: avatar, - online: this.online, + online: true, needOnline: needOnline, hasNew: !this.lastReaded, ); } last(List params) { + this.isClose = false; this.lastTime = RelativeTime.fromInt(params[1]); this.lastContent = params[2]; this.lastReaded = params[3]; @@ -103,7 +112,6 @@ class Session { this.addr = params[1]; this.name = params[2]; this.isTop = params[3]; - this.online = params[4]; } Session.fromList(List params) { @@ -114,9 +122,10 @@ class Session { this.type = SessionTypeExtension.fromInt(params[4]); this.name = params[5]; this.isTop = params[6]; - this.lastTime = RelativeTime.fromInt(params[7]); - this.lastContent = params[8]; - this.lastReaded = params[9]; - this.online = params[10]; + this.isClose = params[7]; + this.lastTime = RelativeTime.fromInt(params[8]); + this.lastContent = params[9]; + this.lastReaded = params[10]; + this.online = OnlineType.Lost; } } diff --git a/lib/widgets/default_home_show.dart b/lib/widgets/default_home_show.dart index ad6171d..5d4e1a0 100644 --- a/lib/widgets/default_home_show.dart +++ b/lib/widgets/default_home_show.dart @@ -8,6 +8,9 @@ import 'package:esse/options.dart'; import 'package:esse/provider.dart'; import 'package:esse/session.dart'; +import 'package:esse/apps/chat/detail.dart'; +import 'package:esse/apps/assistant/page.dart'; + class DefaultHomeShow extends StatelessWidget { const DefaultHomeShow({Key key}): super(key: key); @@ -28,7 +31,7 @@ class DefaultHomeShow extends StatelessWidget { // onPressed: () { // final widget = Text(''); // if (isDesktop) { - // Provider.of(context, listen: false).updateActivedApp(widget); + // Provider.of(context, listen: false).updateActivedSession(0, widget); // } else { // Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); // } @@ -54,21 +57,41 @@ class _SessionWidget extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { + String listTitle = ""; + Widget listWidget = null; + Widget coreWidget = null; - // TODO - - // context.read().updateActivedFriend(friend.id); + switch (session.type) { + case SessionType.Chat: + if (!isDesktop) { + coreWidget = ChatPage(); + } else { + coreWidget = ChatDetail(); + } + break; + case SessionType.Group: + break; + case SessionType.Assistant: + if (!isDesktop) { + coreWidget = AssistantPage(); + } else { + coreWidget = AssistantDetail(); + } + break; + } - // if (!isDesktop) { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (_) => ChatPage(), - // ), - // ); - // } else { - // context.read().updateActivedApp(ChatDetail()); - // } + if (!isDesktop) { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => coreWidget, + ), + ); + } else { + context.read().updateActivedSession( + session.id, coreWidget, listTitle, listWidget + ); + } }, child: Container( height: 55.0, diff --git a/lib/widgets/list_service.dart b/lib/widgets/list_service.dart deleted file mode 100644 index eb02c45..0000000 --- a/lib/widgets/list_service.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import 'package:esse/utils/adaptive.dart'; -import 'package:esse/l10n/localizations.dart'; -import 'package:esse/provider/account.dart'; - -import 'package:esse/apps/assistant/page.dart'; - -class ListService extends StatelessWidget { - const ListService({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final color = Theme.of(context).colorScheme; - final lang = AppLocalizations.of(context); - final isDesktop = isDisplayDesktop(context); - - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - final widget = AssistantPage(); - if (isDesktop) { - Provider.of(context, listen: false).updateActivedApp(widget); - } else { - Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); - } - }, - child: Container( - height: 55.0, - child: Row( - children: [ - Container( - width: 45.0, - height: 45.0, - margin: const EdgeInsets.only(left: 20.0, right: 15.0), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/logo/logo_light.png'), - fit: BoxFit.cover, - ), - borderRadius: BorderRadius.circular(15.0) - ), - ), - Expanded( - child: Container( - height: 55.0, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text('esse', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 16.0)) - ), - Container( - margin: const EdgeInsets.only(left: 15.0, right: 20.0), - child: Text('2021-11-12', - style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0), - ), - ) - ]), - SizedBox(height: 5.0), - Expanded( - child: Text('esse is a echo robot', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0)), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/src/apps/chat/layer.rs b/src/apps/chat/layer.rs index 1c9cd9f..97a7d51 100644 --- a/src/apps/chat/layer.rs +++ b/src/apps/chat/layer.rs @@ -14,7 +14,7 @@ use tdn_did::{user::User, Proof}; use crate::event::{InnerEvent, StatusEvent}; use crate::layer::{Layer, Online}; use crate::migrate::consensus::{FRIEND_TABLE_PATH, MESSAGE_TABLE_PATH, REQUEST_TABLE_PATH}; -use crate::rpc::{session_create, session_last}; +use crate::rpc::{session_connect, session_create, session_last, session_lost, session_suspend}; use crate::session::{Session, SessionType}; use crate::storage::{ chat_db, read_avatar, read_file, read_record, session_db, write_avatar_sync, write_file, @@ -56,8 +56,12 @@ pub(crate) enum LayerResponse { /// ESSE chat layer Event. #[derive(Serialize, Deserialize)] pub(crate) enum LayerEvent { - /// receiver gid, sender gid. as BaseLayerEvent. + /// offline. extend BaseLayerEvent. Offline(GroupId), + /// suspend. extend BaseLayerEvent. + Suspend(GroupId), + /// actived. extend BaseLayerEvent. + Actived(GroupId), /// receiver gid, sender gid. as BaseLayerEvent. OnlinePing, /// receiver gid, sender gid. as BaseLayerEvent. @@ -95,12 +99,18 @@ pub(crate) async fn handle( } let f = friend.unwrap(); // safe. + // 0. get session. TODO + let sid = 0; + // 1. check verify. proof.verify(&fgid, &addr, &layer.addr)?; // 2. online this group. - layer - .running_mut(&mgid)? - .check_add_online(fgid, Online::Direct(addr), f.id)?; + layer.running_mut(&mgid)?.check_add_online( + fgid, + Online::Direct(addr), + sid, + f.id, + )?; // 3. update remote addr. TODO if f.addr != addr { let db = chat_db(&layer.base, &mgid)?; @@ -155,10 +165,15 @@ pub(crate) async fn handle( let mut friend = some_friend.unwrap(); // safe checked. // already friendship & update. + + // 0. get session. TODO + let sid = 0; + // 1. online this group. layer.running_mut(&mgid)?.check_add_online( fgid, Online::Direct(addr), + sid, friend.id, )?; // 2. update remote user. @@ -258,10 +273,17 @@ pub(crate) async fn handle( } let fid = some_friend.unwrap().id; // safe. + // 0. get session. TODO + let sid = 0; + // 3. online this group. - layer - .running_mut(&mgid)? - .check_add_online(fgid, Online::Direct(addr), fid)?; + layer.running_mut(&mgid)?.check_add_online( + fgid, + Online::Direct(addr), + sid, + fid, + )?; + // 4. update remote addr. let db = chat_db(&layer.base, &mgid)?; Friend::addr_update(&db, fid, &addr)?; @@ -278,10 +300,14 @@ pub(crate) async fn handle( // 1. check verify. proof.verify(&fgid, &addr, &layer.addr)?; if let Some(friend) = load_friend(&layer.base, &mgid, &fgid)? { + // 0. get session. TODO + let sid = 0; + // already friendship. layer.running_mut(&mgid)?.check_add_online( fgid, Online::Direct(addr), + sid, friend.id, )?; results.rpcs.push(rpc::friend_online(mgid, friend.id, addr)); @@ -353,10 +379,16 @@ pub(crate) async fn handle( } let fid = some_friend.unwrap().id; // safe. + // 0. get session. TODO + let sid = 0; + // 3. online this group. - layer - .running_mut(&mgid)? - .check_add_online(fgid, Online::Direct(addr), fid)?; + layer.running_mut(&mgid)?.check_add_online( + fgid, + Online::Direct(addr), + sid, + fid, + )?; // 4. update remote addr. let db = chat_db(&layer.base, &mgid)?; Friend::addr_update(&db, fid, &addr)?; @@ -376,10 +408,14 @@ pub(crate) async fn handle( // 1. check verify. proof.verify(&fgid, &addr, &layer.addr)?; if let Some(friend) = load_friend(&layer.base, &mgid, &fgid)? { + // 0. get session. TODO + let sid = 0; + // already friendship. layer.running_mut(&mgid)?.check_add_online( fgid, Online::Direct(addr), + sid, friend.id, )?; results.rpcs.push(rpc::friend_online(mgid, friend.id, addr)); @@ -499,11 +535,24 @@ impl LayerEvent { ) -> Result { let event: LayerEvent = postcard::from_bytes(&bytes).map_err(|_| new_io_error("serialize event error."))?; - let fid = layer.get_running_remote_id(&mgid, &fgid)?; + let (sid, fid) = layer.get_running_remote_id(&mgid, &fgid)?; let mut results = HandleResult::new(); match event { + LayerEvent::Offline(_) => { + layer.running_mut(&mgid)?.check_offline(&fgid, &addr); + results.rpcs.push(session_lost(mgid, &sid)); + } + LayerEvent::Suspend(_) => { + if layer.running_mut(&mgid)?.suspend(&fgid, false)? { + results.rpcs.push(session_suspend(mgid, &sid)); + } + } + LayerEvent::Actived(_) => { + let _ = layer.running_mut(&mgid)?.active(&fgid, false); + results.rpcs.push(session_connect(mgid, &sid, &addr)); + } LayerEvent::Message(hash, m) => { let db = chat_db(&layer.base, &mgid)?; if !Message::exist(&db, &hash)? { @@ -579,7 +628,7 @@ impl LayerEvent { )?; layer .running_mut(&mgid)? - .check_add_online(fgid, Online::Direct(addr), fid)?; + .check_add_online(fgid, Online::Direct(addr), sid, fid)?; results.rpcs.push(rpc::friend_online(mgid, fid, addr)); let data = postcard::to_allocvec(&LayerEvent::OnlinePong).unwrap_or(vec![]); let msg = SendType::Event(0, addr, data); @@ -593,18 +642,9 @@ impl LayerEvent { )?; layer .running_mut(&mgid)? - .check_add_online(fgid, Online::Direct(addr), fid)?; + .check_add_online(fgid, Online::Direct(addr), sid, fid)?; results.rpcs.push(rpc::friend_online(mgid, fid, addr)); } - LayerEvent::Offline(_) => { - layer.group.write().await.status( - &mgid, - StatusEvent::SessionFriendOffline(fgid), - &mut results, - )?; - layer.running_mut(&mgid)?.check_offline(&fgid, &addr); - results.rpcs.push(rpc::friend_offline(mgid, fid, &fgid)); - } LayerEvent::Close => { layer.group.write().await.broadcast( &mgid, diff --git a/src/apps/group_chat/layer.rs b/src/apps/group_chat/layer.rs index ec4d599..2620309 100644 --- a/src/apps/group_chat/layer.rs +++ b/src/apps/group_chat/layer.rs @@ -14,6 +14,7 @@ use tdn_did::Proof; use tdn_storage::local::DStorage; use crate::layer::{Layer, Online}; +use crate::rpc::{session_connect, session_lost, session_suspend}; use crate::storage::{group_chat_db, write_avatar_sync}; use super::models::{from_network_message, GroupChat, Member, Request}; @@ -46,10 +47,14 @@ pub(crate) async fn handle( gc.ok(&db)?; results.rpcs.push(rpc::create_result(mgid, gc.id, ok)); + // 0. get session. TODO + let sid = 0; + // online this group. layer.write().await.running_mut(&mgid)?.check_add_online( gcd, Online::Direct(addr), + sid, gc.id, )?; } @@ -65,10 +70,15 @@ pub(crate) async fn handle( if group.g_addr != addr { return Ok(results); } + + // 2. get group session. + let sid = 0; // TODO + // 2. online this group. layer_lock.running_mut(&mgid)?.check_add_online( gcd, Online::Direct(addr), + sid, group.id, )?; // 3. online to UI. @@ -148,8 +158,10 @@ async fn handle_event( results: &mut HandleResult, ) -> Result<()> { println!("Got event......."); - let gid = match event { + let (sid, gid) = match event { LayerEvent::Offline(gcd) + | LayerEvent::Suspend(gcd) + | LayerEvent::Actived(gcd) | LayerEvent::OnlinePing(gcd) | LayerEvent::OnlinePong(gcd) | LayerEvent::MemberOnline(gcd, ..) @@ -161,7 +173,23 @@ async fn handle_event( match event { LayerEvent::Offline(gcd) => { - results.rpcs.push(rpc::group_offline(mgid, gid, &gcd)); + let mut layer_lock = layer.write().await; + layer_lock.running_mut(&mgid)?.check_offline(&gcd, &addr); + drop(layer_lock); + results.rpcs.push(session_lost(mgid, &sid)); + } + LayerEvent::Suspend(gcd) => { + let mut layer_lock = layer.write().await; + if layer_lock.running_mut(&mgid)?.suspend(&gcd, false)? { + results.rpcs.push(session_suspend(mgid, &sid)); + } + drop(layer_lock); + } + LayerEvent::Actived(gcd) => { + let mut layer_lock = layer.write().await; + let _ = layer_lock.running_mut(&mgid)?.active(&gcd, false); + drop(layer_lock); + results.rpcs.push(session_connect(mgid, &sid, &addr)); } LayerEvent::OnlinePing(gcd) => { results.rpcs.push(rpc::group_online(mgid, gid)); diff --git a/src/event.rs b/src/event.rs index 684f7f4..4091a2d 100644 --- a/src/event.rs +++ b/src/event.rs @@ -490,16 +490,6 @@ impl StatusEvent { results .rpcs .push(chat_rpc::friend_online(gid, f.id, f.addr)); - let layer_lock = layer.clone(); - let rgid = f.gid; - let fid = f.id; - let ggid = gid.clone(); - tdn::smol::spawn(async move { - if let Ok(running) = layer_lock.write().await.running_mut(&ggid) { - let _ = running.check_add_online(rgid, Online::Relay(addr), fid); - } - }) - .detach(); } } StatusEvent::SessionFriendOffline(rgid) => { diff --git a/src/layer.rs b/src/layer.rs index fd903bd..c473f30 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -7,7 +7,7 @@ use tdn::{ types::{ group::GroupId, message::SendType, - primitive::{new_io_error, PeerAddr, Result}, + primitive::{new_io_error, HandleResult, PeerAddr, Result}, }, }; @@ -21,8 +21,12 @@ use crate::storage::session_db; /// EVERY LAYER APP MUST EQUAL THE FIRST THREE FIELDS. #[derive(Serialize, Deserialize)] pub(crate) enum LayerEvent { - /// offline, remote_gid. + /// Offline. params: remote_id. Offline(GroupId), + /// Suspend. params: remote_id. + Suspend(GroupId), + /// Actived. params: remote_id. + Actived(GroupId), } /// ESSE layers. @@ -104,7 +108,7 @@ impl Layer { addrs } - pub fn get_running_remote_id(&self, mgid: &GroupId, fgid: &GroupId) -> Result { + pub fn get_running_remote_id(&self, mgid: &GroupId, fgid: &GroupId) -> Result<(i64, i64)> { self.running(mgid)?.get_online_id(fgid) } @@ -156,7 +160,7 @@ impl Layer { } /// online info. -pub enum Online { +pub(crate) enum Online { /// connected to this device. Direct(PeerAddr), /// connected to other device. @@ -171,42 +175,98 @@ impl Online { } } +pub(crate) struct OnlineSession { + pub online: Online, + pub db_id: i64, + pub db_fid: i64, + pub suspend_me: bool, + pub suspend_remote: bool, + pub remain: u16, // keep-alive remain minutes +} + +impl OnlineSession { + fn new(online: Online, db_id: i64, db_fid: i64) -> Self { + Self { + online, + db_id, + db_fid, + suspend_me: false, + suspend_remote: false, + remain: 0, + } + } +} + pub(crate) struct RunningAccount { /// online group (friends/services) => (group's address, group's db id) - onlines: HashMap, + sessions: HashMap, } impl RunningAccount { pub fn init() -> Self { RunningAccount { - onlines: HashMap::new(), + sessions: HashMap::new(), + } + } + + pub fn active(&mut self, gid: &GroupId, is_me: bool) -> Option { + if let Some(online) = self.sessions.get_mut(gid) { + if is_me { + online.suspend_me = false; + } else { + online.suspend_remote = false; + } + + online.remain = 0; + Some(*online.online.addr()) + } else { + None + } + } + + pub fn suspend(&mut self, gid: &GroupId, is_me: bool) -> Result { + if let Some(online) = self.sessions.get_mut(gid) { + if is_me { + online.suspend_me = true; + } else { + online.suspend_remote = true; + } + + if online.suspend_remote && online.suspend_me { + online.remain = 120; // keep-alive 2~3 minutes + Ok(true) + } else { + Ok(false) + } + } else { + Err(new_io_error("remote not online")) } } - pub fn get_online_id(&self, gid: &GroupId) -> Result { - self.onlines + pub fn get_online_id(&self, gid: &GroupId) -> Result<(i64, i64)> { + self.sessions .get(gid) - .map(|(_, id)| *id) + .map(|online| (online.db_id, online.db_fid)) .ok_or(new_io_error("remote not online")) } - /// get all onlines's groupid + /// get all sessions's groupid pub fn is_online(&self, gid: &GroupId) -> bool { - self.onlines.contains_key(gid) + self.sessions.contains_key(gid) } /// get online peer's addr. pub fn online(&self, gid: &GroupId) -> Result { - self.onlines + self.sessions .get(gid) - .map(|(online, _)| *online.addr()) + .map(|online| *online.online.addr()) .ok_or(new_io_error("remote not online")) } pub fn online_direct(&self, gid: &GroupId) -> Result { - if let Some((online, _)) = self.onlines.get(gid) { - match online { - Online::Direct(addr) => return Ok(*addr), + if let Some(online) = self.sessions.get(gid) { + match online.online { + Online::Direct(addr) => return Ok(addr), _ => {} } } @@ -215,36 +275,44 @@ impl RunningAccount { /// get all online peer. pub fn onlines(&self) -> Vec<(&GroupId, &PeerAddr)> { - self.onlines + self.sessions .iter() - .map(|(fgid, (online, _))| (fgid, online.addr())) + .map(|(fgid, online)| (fgid, online.online.addr())) .collect() } /// check add online. - pub fn check_add_online(&mut self, gid: GroupId, online: Online, id: i64) -> Result<()> { - if let Some((o, _)) = self.onlines.get(&gid) { - match (o, &online) { + pub fn check_add_online( + &mut self, + gid: GroupId, + online: Online, + id: i64, + fid: i64, + ) -> Result<()> { + if let Some(o) = self.sessions.get(&gid) { + match (&o.online, &online) { (Online::Relay(..), Online::Direct(..)) => { - self.onlines.insert(gid, (online, id)); + self.sessions + .insert(gid, OnlineSession::new(online, id, fid)); Ok(()) } _ => Err(new_io_error("remote had online")), } } else { - self.onlines.insert(gid, (online, id)); + self.sessions + .insert(gid, OnlineSession::new(online, id, fid)); Ok(()) } } /// check offline, and return is direct. pub fn check_offline(&mut self, gid: &GroupId, addr: &PeerAddr) -> bool { - if let Some((online, _)) = self.onlines.remove(gid) { - if online.addr() != addr { + if let Some(online) = self.sessions.remove(gid) { + if online.online.addr() != addr { return false; } - match online { + match online.online { Online::Direct(..) => { return true; } @@ -255,14 +323,16 @@ impl RunningAccount { } pub fn remove_online(&mut self, gid: &GroupId) -> Option { - self.onlines.remove(gid).map(|(online, _)| *online.addr()) + self.sessions + .remove(gid) + .map(|online| *online.online.addr()) } /// remove all onlines peer. pub fn remove_onlines(self) -> Vec<(PeerAddr, GroupId)> { let mut peers = vec![]; - for (fgid, (online, _)) in self.onlines { - match online { + for (fgid, online) in self.sessions { + match online.online { Online::Direct(addr) => peers.push((addr, fgid)), _ => {} } @@ -272,8 +342,8 @@ impl RunningAccount { /// check if addr is online. pub fn check_addr_online(&self, addr: &PeerAddr) -> bool { - for (_, (online, _)) in &self.onlines { - if online.addr() == addr { + for (_, online) in &self.sessions { + if online.online.addr() == addr { return true; } } @@ -283,23 +353,23 @@ impl RunningAccount { /// peer leave, remove online peer. pub fn peer_leave(&mut self, addr: &PeerAddr) -> Vec<(GroupId, i64)> { let mut peers = vec![]; - for (fgid, (online, id)) in &self.onlines { - if online.addr() == addr { - peers.push((*fgid, *id)) + for (fgid, online) in &self.sessions { + if online.online.addr() == addr { + peers.push((*fgid, online.db_id)) } } for i in &peers { - self.onlines.remove(&i.0); + self.sessions.remove(&i.0); } peers } /// list all onlines groups. pub fn _list_onlines(&self) -> Vec<(&GroupId, &PeerAddr)> { - self.onlines + self.sessions .iter() - .map(|(k, (v, _))| (k, v.addr())) + .map(|(k, online)| (k, online.online.addr())) .collect() } } diff --git a/src/migrate/session.rs b/src/migrate/session.rs index e668746..1217478 100644 --- a/src/migrate/session.rs +++ b/src/migrate/session.rs @@ -8,9 +8,10 @@ pub(super) const SESSION_VERSIONS: [&str; 3] = [ s_type INTEGER NOT NULL, name TEXT NOT NULL, is_top INTEGER NOT NULL, + is_close INTEGER NOT NULL, last_datetime INTEGER, last_content TEXT, last_readed INTEGER);", - "INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, last_datetime, last_content, last_readed) VALUES (0, '', '', 4, '', 0, 0, '', 1);", // Assistant. - "INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, last_datetime, last_content, last_readed) VALUES (0, '', '', 2, '', 0, 0, '', 1);", // File. + "INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES (0, '', '', 4, '', 0, 0, 0, '', 1);", // Assistant. + "INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES (0, '', '', 2, '', 0, 0, 0, '', 1);", // File. ]; diff --git a/src/rpc.rs b/src/rpc.rs index ecd2c02..df3ddfb 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -97,16 +97,30 @@ pub(crate) fn session_update( addr: &PeerAddr, name: &str, is_top: bool, - online: bool, ) -> RpcParam { rpc_response( 0, "session-update", - json!([id, addr.to_hex(), name, is_top, online]), + json!([id, addr.to_hex(), name, is_top]), mgid, ) } +#[inline] +pub(crate) fn session_connect(mgid: GroupId, id: &i64, addr: &PeerAddr) -> RpcParam { + rpc_response(0, "session-connect", json!([id, addr.to_hex()]), mgid) +} + +#[inline] +pub(crate) fn session_suspend(mgid: GroupId, id: &i64) -> RpcParam { + rpc_response(0, "session-suspend", json!([id]), mgid) +} + +#[inline] +pub(crate) fn session_lost(mgid: GroupId, id: &i64) -> RpcParam { + rpc_response(0, "session-lost", json!([id]), mgid) +} + #[inline] fn session_list(sessions: Vec) -> RpcParam { let mut results = vec![]; @@ -406,24 +420,6 @@ fn new_rpc_handler( let mut results = HandleResult::new(); let group_lock = state.group.read().await; - let db = session_db(group_lock.base(), &gid)?; - let sessions = Session::list(&db)?; - drop(db); - - for s in sessions { - match s.s_type { - SessionType::Chat => { - let proof = group_lock.prove_addr(&gid, &s.addr)?; - results.layers.push((gid, s.gid, chat_conn(proof, s.addr))); - } - SessionType::Group => { - let proof = group_lock.prove_addr(&gid, &s.addr)?; - add_layer(&mut results, gid, group_chat_conn(proof, s.addr, s.gid)); - } - _ => {} - } - } - let devices = group_lock.distribute_conns(&gid); for device in devices { results.groups.push((gid, device)); @@ -469,18 +465,78 @@ fn new_rpc_handler( handler.add_method( "session-list", |gid: GroupId, _params: Vec, state: Arc| async move { - let layer_lock = state.layer.read().await; - let db = session_db(layer_lock.base(), &gid)?; - let mut sessions = Session::list(&db)?; + let db = session_db(state.layer.read().await.base(), &gid)?; + Ok(HandleResult::rpc(session_list(Session::list(&db)?))) + }, + ); + + handler.add_method( + "session-connect", + |gid: GroupId, params: Vec, state: Arc| async move { + let id = params[0].as_i64()?; + let remote = GroupId::from_hex(params[1].as_str()?)?; + + let mut layer_lock = state.layer.write().await; + let online = layer_lock.running_mut(&gid)?.active(&remote, true); + drop(layer_lock); + if let Some(addr) = online { + return Ok(HandleResult::rpc(json!([id, addr.to_hex()]))); + } + + let group_lock = state.group.read().await; + let db = session_db(group_lock.base(), &gid)?; + let s = Session::get(&db, &id)?; drop(db); - let gids: Vec<&GroupId> = sessions.iter().map(|s| &s.gid).collect(); - let onlines = layer_lock.merge_online(&gid, gids)?; - for (index, online) in onlines.iter().enumerate() { - sessions[index].online = *online; + let mut results = HandleResult::new(); + match s.s_type { + SessionType::Chat => { + let proof = group_lock.prove_addr(&gid, &s.addr)?; + results.layers.push((gid, s.gid, chat_conn(proof, s.addr))); + } + SessionType::Group => { + let proof = group_lock.prove_addr(&gid, &s.addr)?; + add_layer(&mut results, gid, group_chat_conn(proof, s.addr, s.gid)); + } + _ => {} + } + Ok(results) + }, + ); + + handler.add_method( + "session-suspend", + |gid: GroupId, params: Vec, state: Arc| async move { + let id = params[0].as_i64()?; + let remote = GroupId::from_hex(params[1].as_str()?)?; + + let mut layer_lock = state.layer.write().await; + let suspend = layer_lock.running_mut(&gid)?.suspend(&remote, true)?; + drop(layer_lock); + + let mut results = HandleResult::new(); + if suspend { + results.rpcs.push(json!([id])) } - Ok(HandleResult::rpc(session_list(sessions))) + // let group_lock = state.group.read().await; + // let db = session_db(group_lock.base(), &gid)?; + // let s = Session::get(&db, &id)?; + // drop(db); + + // match s.s_type { + // SessionType::Chat => { + // let proof = group_lock.prove_addr(&gid, &s.addr)?; + // results.layers.push((gid, s.gid, chat_conn(proof, s.addr))); + // } + // SessionType::Group => { + // let proof = group_lock.prove_addr(&gid, &s.addr)?; + // add_layer(&mut results, gid, group_chat_conn(proof, s.addr, s.gid)); + // } + // _ => {} + // } + + Ok(results) }, ); diff --git a/src/session.rs b/src/session.rs index 15382b9..00f2dd5 100644 --- a/src/session.rs +++ b/src/session.rs @@ -50,10 +50,10 @@ pub(crate) struct Session { pub s_type: SessionType, name: String, is_top: bool, + is_close: bool, pub last_datetime: i64, pub last_content: String, pub last_readed: bool, - pub online: bool, } impl Session { @@ -73,10 +73,10 @@ impl Session { name, id: 0, is_top: false, + is_close: false, last_datetime: datetime, last_content: "".to_owned(), last_readed: true, - online: false, } } @@ -89,10 +89,10 @@ impl Session { self.s_type.to_int(), self.name, self.is_top, + self.is_close, self.last_datetime, self.last_content, self.last_readed, - self.online ]) } @@ -101,6 +101,7 @@ impl Session { last_readed: v.pop().unwrap().as_bool(), last_content: v.pop().unwrap().as_string(), last_datetime: v.pop().unwrap().as_i64(), + is_close: v.pop().unwrap().as_bool(), is_top: v.pop().unwrap().as_bool(), name: v.pop().unwrap().as_string(), s_type: SessionType::from_int(v.pop().unwrap().as_i64()), @@ -108,18 +109,18 @@ impl Session { gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()), fid: v.pop().unwrap().as_i64(), id: v.pop().unwrap().as_i64(), - online: false, } } pub fn insert(&mut self, db: &DStorage) -> Result<()> { - let sql = format!("INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, last_datetime, last_content, last_readed) VALUES ({}, '{}', '{}', {}, '{}', {}, {}, '{}', {})", + let sql = format!("INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES ({}, '{}', '{}', {}, '{}', {}, {}, {}, '{}', {})", self.fid, self.gid.to_hex(), self.addr.to_hex(), self.s_type.to_int(), self.name, if self.is_top { 1 } else { 0 }, + if self.is_close { 1 } else { 0 }, self.last_datetime, self.last_content, if self.last_readed { 1 } else { 0 }, @@ -129,8 +130,8 @@ impl Session { Ok(()) } - pub fn get(db: &DStorage, id: i64) -> Result { - let sql = format!("SELECT id, fid, gid, addr, s_type, name, is_top, last_datetime, last_content, last_readed FROM sessions WHERE id = {}", id); + pub fn get(db: &DStorage, id: &i64) -> Result { + let sql = format!("SELECT id, fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions WHERE id = {}", id); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Session::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -140,7 +141,7 @@ impl Session { } pub fn list(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, fid, gid, addr, s_type, name, is_top, last_datetime, last_content, last_readed FROM sessions ORDER BY last_datetime DESC")?; + let matrix = db.query("SELECT id, fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions ORDER BY last_datetime DESC")?; let mut sessions = vec![]; for values in matrix { sessions.push(Session::from_values(values)); @@ -169,7 +170,7 @@ impl Session { if let Some(mut values) = matrix.pop() { let id = values.pop().unwrap().as_i64(); - db.update(&format!("UPDATE sessions SET last_datetime = {}, last_content = '{}', last_readed = {} WHERE id = {}", datetime, content, if readed { 1 } else { 0 }, id))?; + db.update(&format!("UPDATE sessions SET is_close = 0, last_datetime = {}, last_content = '{}', last_readed = {} WHERE id = {}", datetime, content, if readed { 1 } else { 0 }, id))?; Ok(id) } else { Err(new_io_error("session missing"))