Browse Source

apply new session online design

pull/18/head
Sun 4 years ago
parent
commit
1cc084627c
  1. 60
      lib/apps/chat/detail.dart
  2. 8
      lib/apps/chat/list.dart
  3. 4
      lib/apps/device/page.dart
  4. 2
      lib/apps/file/page.dart
  5. 7
      lib/apps/group_chat/page.dart
  6. 4
      lib/apps/service/list.dart
  7. 6
      lib/apps/service/models.dart
  8. 10
      lib/pages/home.dart
  9. 131
      lib/provider.dart
  10. 23
      lib/session.dart
  11. 51
      lib/widgets/default_home_show.dart
  12. 84
      lib/widgets/list_service.dart
  13. 86
      src/apps/chat/layer.rs
  14. 32
      src/apps/group_chat/layer.rs
  15. 10
      src/event.rs
  16. 144
      src/layer.rs
  17. 5
      src/migrate/session.rs
  18. 112
      src/rpc.rs
  19. 19
      src/session.rs

60
lib/apps/chat/detail.dart

@ -13,6 +13,7 @@ import 'package:esse/widgets/user_info.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<ChatDetail> { @@ -46,7 +47,9 @@ class _ChatDetailState extends State<ChatDetail> {
bool recordShow = false;
String _recordName;
Friend friend;
int _actived;
Friend _friend;
String _meName;
@override
initState() {
@ -60,12 +63,21 @@ class _ChatDetailState extends State<ChatDetail> { @@ -60,12 +63,21 @@ class _ChatDetailState extends State<ChatDetail> {
});
}
});
new Future.delayed(Duration.zero, () {
final accountProvider = context.read<AccountProvider>();
final chatProvider = context.read<ChatProvider>();
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<ChatDetail> { @@ -74,7 +86,7 @@ class _ChatDetailState extends State<ChatDetail> {
return;
}
context.read<ChatProvider>().messageCreate(Message(friend.id, MessageType.String, textController.text));
context.read<ChatProvider>().messageCreate(Message(_actived, MessageType.String, textController.text));
setState(() {
textController.text = '';
textFocus.requestFocus();
@ -93,7 +105,7 @@ class _ChatDetailState extends State<ChatDetail> { @@ -93,7 +105,7 @@ class _ChatDetailState extends State<ChatDetail> {
void _sendImage() async {
final image = await pickImage();
if (image != null) {
context.read<ChatProvider>().messageCreate(Message(friend.id, MessageType.Image, image));
context.read<ChatProvider>().messageCreate(Message(_actived, MessageType.Image, image));
}
setState(() {
textFocus.requestFocus();
@ -107,7 +119,7 @@ class _ChatDetailState extends State<ChatDetail> { @@ -107,7 +119,7 @@ class _ChatDetailState extends State<ChatDetail> {
void _sendFile() async {
final file = await pickFile();
if (file != null) {
context.read<ChatProvider>().messageCreate(Message(friend.id, MessageType.File, file));
context.read<ChatProvider>().messageCreate(Message(_actived, MessageType.File, file));
}
setState(() {
textFocus.requestFocus();
@ -120,7 +132,7 @@ class _ChatDetailState extends State<ChatDetail> { @@ -120,7 +132,7 @@ class _ChatDetailState extends State<ChatDetail> {
void _sendRecord(int time) async {
final raw = BaseMessage.rawRecordName(time, _recordName);
context.read<ChatProvider>().messageCreate(Message(friend.id, MessageType.Record, raw));
context.read<ChatProvider>().messageCreate(Message(_actived, MessageType.Record, raw));
setState(() {
textFocus.requestFocus();
@ -165,7 +177,7 @@ class _ChatDetailState extends State<ChatDetail> { @@ -165,7 +177,7 @@ class _ChatDetailState extends State<ChatDetail> {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
context.read<ChatProvider>().messageCreate(Message(friend.id, MessageType.Contact, "${contact.id}"));
context.read<ChatProvider>().messageCreate(Message(_actived, MessageType.Contact, "${contact.id}"));
Navigator.of(context).pop();
setState(() {
textFocus.requestFocus();
@ -201,16 +213,16 @@ class _ChatDetailState extends State<ChatDetail> { @@ -201,16 +213,16 @@ class _ChatDetailState extends State<ChatDetail> {
final recentMessages = provider.activedMessages;
final recentMessageKeys = recentMessages.keys.toList().reversed.toList();
final meName = context.read<AccountProvider>().activedAccount.name;
this.friend = provider.activedFriend;
final session = context.watch<AccountProvider>().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<ChatDetail> { @@ -235,11 +247,11 @@ class _ChatDetailState extends State<ChatDetail> {
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<ChatDetail> { @@ -278,9 +290,9 @@ class _ChatDetailState extends State<ChatDetail> {
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<ChatDetail> { @@ -290,7 +302,7 @@ class _ChatDetailState extends State<ChatDetail> {
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<ChatDetail> { @@ -302,7 +314,7 @@ class _ChatDetailState extends State<ChatDetail> {
onPressed: () {
Navigator.pop(context);
Provider.of<ChatProvider>(
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<ChatDetail> { @@ -314,14 +326,14 @@ class _ChatDetailState extends State<ChatDetail> {
);
} else if (value == 5) {
Provider.of<ChatProvider>(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<ChatDetail> { @@ -333,7 +345,7 @@ class _ChatDetailState extends State<ChatDetail> {
onPressed: () {
Navigator.pop(context);
Provider.of<ChatProvider>(
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<ChatDetail> { @@ -349,7 +361,7 @@ class _ChatDetailState extends State<ChatDetail> {
return <PopupMenuEntry<int>>[
_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<ChatDetail> { @@ -366,11 +378,11 @@ class _ChatDetailState extends State<ChatDetail> {
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(

8
lib/apps/chat/list.dart

@ -4,6 +4,7 @@ import 'package:provider/provider.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<ChatList> { @@ -34,7 +35,7 @@ class _ChatListState extends State<ChatList> {
onPressed: () {
final widget = ChatAddPage();
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widget);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
}
@ -60,7 +61,6 @@ class ListChat extends StatelessWidget { @@ -60,7 +61,6 @@ class ListChat extends StatelessWidget {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
context.read<ChatProvider>().updateActivedFriend(friend.id);
if (!isDesktop) {
Navigator.push(
context,
@ -69,7 +69,9 @@ class ListChat extends StatelessWidget { @@ -69,7 +69,9 @@ class ListChat extends StatelessWidget {
),
);
} else {
context.read<AccountProvider>().updateActivedApp(ChatDetail());
context.read<AccountProvider>().updateActivedSessionFromList(
friend.id, SessionType.Chat, ChatDetail()
);
}
},
child: Container(

4
lib/apps/device/page.dart

@ -152,7 +152,7 @@ class _DevicesPageState extends State<DevicesPage> { @@ -152,7 +152,7 @@ class _DevicesPageState extends State<DevicesPage> {
Provider.of<DeviceProvider>(context, listen: false).updateActivedDevice(device.id);
final widget = DeviceListenPage();
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widget);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
}
@ -355,7 +355,7 @@ class _DeviceListenPageState extends State<DeviceListenPage> { @@ -355,7 +355,7 @@ class _DeviceListenPageState extends State<DeviceListenPage> {
onTap: () {
Provider.of<DeviceProvider>(context, listen: false).clear();
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(DevicesPage());
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, DevicesPage());
} else {
Navigator.pop(context);
}

2
lib/apps/file/page.dart

@ -39,7 +39,7 @@ class _FolderListState extends State<FolderList> { @@ -39,7 +39,7 @@ class _FolderListState extends State<FolderList> {
loadFolder(bool isDesktop, int index) async {
final widget = FilePage(title: FILE_DIRECTORY[index][0]);
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widget);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
}

7
lib/apps/group_chat/page.dart

@ -5,6 +5,7 @@ import 'package:esse/utils/adaptive.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<GroupChatList> { @@ -34,7 +35,7 @@ class _GroupChatListState extends State<GroupChatList> {
onPressed: () {
final widget = GroupAddPage();
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widget);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
}
@ -68,7 +69,9 @@ class ListChat extends StatelessWidget { @@ -68,7 +69,9 @@ class ListChat extends StatelessWidget {
),
);
} else {
context.read<AccountProvider>().updateActivedApp(GroupChatDetail());
context.read<AccountProvider>().updateActivedSessionFromList(
group.id, SessionType.Group, GroupChatDetail()
);
}
},
child: Container(

4
lib/apps/service/list.dart

@ -73,10 +73,10 @@ class ListInnerService extends StatelessWidget { @@ -73,10 +73,10 @@ class ListInnerService extends StatelessWidget {
final widgets = this.callback();
if (widgets != null) {
if (this.isDesktop) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widgets[0], widgets[1], widgets[2]);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widgets[0], widgets[1], widgets[2]);
} else {
if (widgets[2] != null) {
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(null, widgets[1], widgets[2]);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, null, widgets[1], widgets[2]);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widgets[0]));
}

6
lib/apps/service/models.dart

@ -46,17 +46,17 @@ extension InnerServiceExtension on InnerService { @@ -46,17 +46,17 @@ extension InnerServiceExtension on InnerService {
listHome = GroupChatList();
break;
}
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(coreWidget, listTitle, listHome);
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, coreWidget, listTitle, listHome);
} else {
switch (this) {
case InnerService.Files:
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(null, lang.files, FolderList());
Provider.of<AccountProvider>(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<AccountProvider>(context, listen: false).updateActivedApp(null, lang.groupChat, GroupChatList());
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, null, lang.groupChat, GroupChatList());
break;
}
}

10
lib/pages/home.dart

@ -135,7 +135,7 @@ class _HomeListState extends State<HomeList> with SingleTickerProviderStateMixin @@ -135,7 +135,7 @@ class _HomeListState extends State<HomeList> with SingleTickerProviderStateMixin
.systemAppFriendAddNew = false;
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false)
.updateActivedApp(widget);
.updateActivedSession(0, widget);
} else {
Navigator.push(
context, MaterialPageRoute(builder: (_) => widget));
@ -199,7 +199,7 @@ class _HomeListState extends State<HomeList> with SingleTickerProviderStateMixin @@ -199,7 +199,7 @@ class _HomeListState extends State<HomeList> 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 { @@ -319,7 +319,7 @@ class DrawerWidget extends StatelessWidget {
final widget = DevicesPage();
if (isDesktop) {
Provider.of<AccountProvider>(context, listen: false)
.updateActivedApp(widget);
.updateActivedSession(0, widget);
} else {
Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
}
@ -387,7 +387,7 @@ class DrawerWidget extends StatelessWidget { @@ -387,7 +387,7 @@ class DrawerWidget extends StatelessWidget {
style: TextStyle(fontSize: 16.0)),
onTap: () {
Navigator.pop(context);
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0,
null, lang.contact, ChatList()
);
}),
@ -397,7 +397,7 @@ class DrawerWidget extends StatelessWidget { @@ -397,7 +397,7 @@ class DrawerWidget extends StatelessWidget {
style: TextStyle(fontSize: 16.0)),
onTap: () {
Navigator.pop(context);
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0,
null, lang.groups, ServiceList()
);
}),

131
lib/provider.dart

@ -20,22 +20,30 @@ class AccountProvider extends ChangeNotifier { @@ -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<int, Session> sessions = {};
List<int> topKeys = [];
List<int> 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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();
}
}

23
lib/session.dart

@ -40,6 +40,13 @@ extension SessionTypeExtension on SessionType { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}

51
lib/widgets/default_home_show.dart

@ -8,6 +8,9 @@ import 'package:esse/options.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 { @@ -28,7 +31,7 @@ class DefaultHomeShow extends StatelessWidget {
// onPressed: () {
// final widget = Text('');
// if (isDesktop) {
// Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
// Provider.of<AccountProvider>(context, listen: false).updateActivedSession(0, widget);
// } else {
// Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
// }
@ -54,21 +57,41 @@ class _SessionWidget extends StatelessWidget { @@ -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<ChatProvider>().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<AccountProvider>().updateActivedApp(ChatDetail());
// }
if (!isDesktop) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => coreWidget,
),
);
} else {
context.read<AccountProvider>().updateActivedSession(
session.id, coreWidget, listTitle, listWidget
);
}
},
child: Container(
height: 55.0,

84
lib/widgets/list_service.dart

@ -1,84 +0,0 @@ @@ -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<AccountProvider>(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)),
),
],
),
),
),
],
),
),
);
}
}

86
src/apps/chat/layer.rs

@ -14,7 +14,7 @@ use tdn_did::{user::User, Proof}; @@ -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 { @@ -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( @@ -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( @@ -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( @@ -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( @@ -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( @@ -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( @@ -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 { @@ -499,11 +535,24 @@ impl LayerEvent {
) -> Result<HandleResult> {
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 { @@ -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 { @@ -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,

32
src/apps/group_chat/layer.rs

@ -14,6 +14,7 @@ use tdn_did::Proof; @@ -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( @@ -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( @@ -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( @@ -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( @@ -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));

10
src/event.rs

@ -490,16 +490,6 @@ impl StatusEvent { @@ -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) => {

144
src/layer.rs

@ -7,7 +7,7 @@ use tdn::{ @@ -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; @@ -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 { @@ -104,7 +108,7 @@ impl Layer {
addrs
}
pub fn get_running_remote_id(&self, mgid: &GroupId, fgid: &GroupId) -> Result<i64> {
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 { @@ -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 { @@ -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<GroupId, (Online, i64)>,
sessions: HashMap<GroupId, OnlineSession>,
}
impl RunningAccount {
pub fn init() -> Self {
RunningAccount {
onlines: HashMap::new(),
sessions: HashMap::new(),
}
}
pub fn active(&mut self, gid: &GroupId, is_me: bool) -> Option<PeerAddr> {
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<bool> {
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<i64> {
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<PeerAddr> {
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<PeerAddr> {
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 { @@ -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 { @@ -255,14 +323,16 @@ impl RunningAccount {
}
pub fn remove_online(&mut self, gid: &GroupId) -> Option<PeerAddr> {
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 { @@ -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 { @@ -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()
}
}

5
src/migrate/session.rs

@ -8,9 +8,10 @@ pub(super) const SESSION_VERSIONS: [&str; 3] = [ @@ -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.
];

112
src/rpc.rs

@ -97,16 +97,30 @@ pub(crate) fn session_update( @@ -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<Session>) -> RpcParam {
let mut results = vec![];
@ -406,24 +420,6 @@ fn new_rpc_handler( @@ -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( @@ -469,18 +465,78 @@ fn new_rpc_handler(
handler.add_method(
"session-list",
|gid: GroupId, _params: Vec<RpcParam>, state: Arc<RpcState>| 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<RpcParam>, state: Arc<RpcState>| 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<RpcParam>, state: Arc<RpcState>| 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)
},
);

19
src/session.rs

@ -50,10 +50,10 @@ pub(crate) struct Session { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -129,8 +130,8 @@ impl Session {
Ok(())
}
pub fn get(db: &DStorage, id: i64) -> Result<Session> {
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<Session> {
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 { @@ -140,7 +141,7 @@ impl Session {
}
pub fn list(db: &DStorage) -> Result<Vec<Session>> {
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 { @@ -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"))

Loading…
Cancel
Save