Browse Source

Add Session model for all chats and services

pull/18/head
Sun 4 years ago
parent
commit
71859fec18
  1. 6
      lib/apps/chat/detail.dart
  2. 19
      lib/apps/chat/list.dart
  3. 41
      lib/apps/chat/models.dart
  4. 41
      lib/apps/chat/provider.dart
  5. 49
      lib/apps/group_chat/add.dart
  6. 7
      lib/apps/group_chat/detail.dart
  7. 28
      lib/apps/group_chat/models.dart
  8. 16
      lib/apps/group_chat/page.dart
  9. 56
      lib/apps/group_chat/provider.dart
  10. 1
      lib/l10n/localizations.dart
  11. 4
      lib/l10n/localizations_en.dart
  12. 2
      lib/l10n/localizations_zh.dart
  13. 25
      lib/pages/home.dart
  14. 90
      lib/provider.dart
  15. 122
      lib/session.dart
  16. 143
      lib/widgets/default_home_show.dart
  17. 18
      pubspec.lock
  18. 4
      src/apps/assistant/models.rs
  19. 42
      src/apps/chat/layer.rs
  20. 76
      src/apps/chat/models.rs
  21. 52
      src/apps/chat/rpc.rs
  22. 116
      src/apps/group_chat/models.rs
  23. 44
      src/apps/group_chat/rpc.rs
  24. 1
      src/daemon.rs
  25. 83
      src/event.rs
  26. 35
      src/layer.rs
  27. 1
      src/lib.rs
  28. 20
      src/migrate.rs
  29. 11
      src/migrate/account.rs
  30. 34
      src/migrate/chat.rs
  31. 4
      src/migrate/group_chat.rs
  32. 37
      src/migrate/session.rs
  33. 95
      src/rpc.rs
  34. 171
      src/session.rs
  35. 11
      src/storage.rs

6
lib/apps/chat/detail.dart

@ -272,10 +272,7 @@ class _ChatDetailState extends State<ChatDetail> { @@ -272,10 +272,7 @@ class _ChatDetailState extends State<ChatDetail> {
color: const Color(0xFFEDEDED),
child: Icon(Icons.more_vert_rounded, color: color.primary),
onSelected: (int value) {
if (value == 1) {
Provider.of<ChatProvider>(context, listen: false).friendUpdate(
this.friend.id, isTop: !this.friend.isTop);
} else if (value == 2) {
if (value == 2) {
showShadowDialog(
context,
Icons.info,
@ -350,7 +347,6 @@ class _ChatDetailState extends State<ChatDetail> { @@ -350,7 +347,6 @@ class _ChatDetailState extends State<ChatDetail> {
},
itemBuilder: (context) {
return <PopupMenuEntry<int>>[
_menuItem(Color(0xFF6174FF), 1, Icons.vertical_align_top_rounded, this.friend.isTop ? lang.cancelTop : lang.setTop),
_menuItem(Color(0xFF6174FF), 2, Icons.qr_code_rounded, lang.friendInfo),
//_menuItem(color.primary, 3, Icons.turned_in_rounded, lang.remark),
this.friend.isClosed

19
lib/apps/chat/list.dart

@ -90,29 +90,12 @@ class ListChat extends StatelessWidget { @@ -90,29 +90,12 @@ class ListChat extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(friend.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16.0))
),
Container(
margin: const EdgeInsets.only(left: 15.0, right: 20.0),
child: Text(friend.lastMessageTime.toString(),
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0),
),
)
]),
const SizedBox(height: 4.0),
Row(
children: [
Expanded(
child: Text(friend.lastMessageContent,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0)),
style: const TextStyle(fontSize: 16.0)),
),
if (this.friend.isClosed)
Container(

41
lib/apps/chat/models.dart

@ -10,64 +10,33 @@ class Friend { @@ -10,64 +10,33 @@ class Friend {
String name;
String addr;
String remark;
bool isTop;
bool isClosed;
RelativeTime lastMessageTime;
String lastMessageContent;
bool lastMessageReaded;
RelativeTime time;
bool online = false;
// new friend from network
Friend(this.gid, this.name, this.addr) {
this.isTop = false;
this.isClosed = false;
this.lastMessageTime = RelativeTime();
this.lastMessageContent = '';
this.lastMessageReaded = true;
}
Avatar showAvatar({double width = 45.0, bool needOnline = true}) {
Avatar showAvatar({double width = 45.0}) {
final avatar = Global.avatarPath + this.gid + '.png';
return Avatar(
width: width,
name: this.name,
avatarPath: avatar,
online: this.online,
needOnline: needOnline,
hasNew: !this.lastMessageReaded,
needOnline: false,
);
}
updateLastMessage(Message msg, bool isReaded) {
this.lastMessageTime = msg.time;
this.lastMessageContent = msg.shortShow();
this.lastMessageReaded = isReaded;
}
static String betterPrint(String info) {
if (info == null) {
return '';
}
final len = info.length;
if (len > 8) {
return info.substring(0, 8) + '...' + info.substring(len - 6, len);
} else {
return info;
}
}
Friend.fromList(List params) {
this.id = params[0];
this.gid = params[1];
this.addr = params[2];
this.name = params[3];
this.remark = params[4];
this.isTop = params[5] == "1";
this.isClosed = params[6] == "1";
this.lastMessageTime = RelativeTime.fromInt(params[7]);
this.lastMessageContent = params[8];
this.lastMessageReaded = params[9];
this.online = params[10] == "1";
this.isClosed = params[5];
this.time = RelativeTime.fromInt(params[6]);
}
}

41
lib/apps/chat/provider.dart

@ -18,8 +18,6 @@ class ChatProvider extends ChangeNotifier { @@ -18,8 +18,6 @@ class ChatProvider extends ChangeNotifier {
List<int> orderKeys = []; // ordered chat friends with last message.
Map<int, RelativeTime> topKeys = {}; // Set toped friends.
/// all requests. request have order.
SplayTreeMap<int, Request> requests = SplayTreeMap();
@ -59,7 +57,6 @@ class ChatProvider extends ChangeNotifier { @@ -59,7 +57,6 @@ class ChatProvider extends ChangeNotifier {
this.orderKeys.clear();
this.requests.clear();
this.activedMessages.clear();
this.topKeys.clear();
}
updateActived() {
@ -73,7 +70,6 @@ class ChatProvider extends ChangeNotifier { @@ -73,7 +70,6 @@ class ChatProvider extends ChangeNotifier {
updateActivedFriend(int id) {
this.activedFriendId = id;
this.activedMessages.clear();
this.friends[id].lastMessageReaded = true;
rpc.send('chat-message-list', [this.activedFriendId]);
notifyListeners();
@ -85,22 +81,9 @@ class ChatProvider extends ChangeNotifier { @@ -85,22 +81,9 @@ class ChatProvider extends ChangeNotifier {
}
/// delete a friend.
friendUpdate(int id, {String remark, bool isTop}) {
if (remark != null) {
friendUpdate(int id, String remark) {
this.friends[id].remark = remark;
}
if (isTop != null) {
this.friends[id].isTop = isTop;
if (isTop) {
this.topKeys[id] = this.friends[id].lastMessageTime;
} else {
this.topKeys.remove(id);
}
}
final friend = this.friends[id];
rpc.send('chat-friend-update', [id, friend.remark, friend.isTop]);
rpc.send('chat-friend-update', [id, remark]);
notifyListeners();
}
@ -122,7 +105,6 @@ class ChatProvider extends ChangeNotifier { @@ -122,7 +105,6 @@ class ChatProvider extends ChangeNotifier {
this.friends.remove(id);
this.orderKeys.remove(id);
this.topKeys.remove(id);
rpc.send('chat-friend-delete', [id]);
notifyListeners();
@ -196,9 +178,6 @@ class ChatProvider extends ChangeNotifier { @@ -196,9 +178,6 @@ class ChatProvider extends ChangeNotifier {
final id = params[0];
this.friends[id] = Friend.fromList(params);
this.orderKeys.add(id);
if (this.friends[id].isTop) {
this.topKeys[id] = this.friends[id].lastMessageTime;
}
});
notifyListeners();
}
@ -225,21 +204,13 @@ class ChatProvider extends ChangeNotifier { @@ -225,21 +204,13 @@ class ChatProvider extends ChangeNotifier {
_friendInfo(List params) {
final id = params[0];
this.friends[id] = Friend.fromList(params);
if (this.friends[id].isTop) {
this.topKeys[id] = this.friends[id].lastMessageTime;
}
notifyListeners();
}
_friendUpdate(List params) {
final id = params[0];
if (this.friends.containsKey(id)) {
this.friends[id].isTop = params[1];
this.friends[id].remark = params[2];
if (params[1]) {
this.topKeys[id] = this.friends[id].lastMessageTime;
}
notifyListeners();
}
}
@ -287,9 +258,6 @@ class ChatProvider extends ChangeNotifier { @@ -287,9 +258,6 @@ class ChatProvider extends ChangeNotifier {
this.requests[id].overIt(true);
}
var friend = Friend.fromList(params[1]);
if (friend.isTop) {
this.topKeys[friend.id] = friend.lastMessageTime;
}
this.friends[friend.id] = friend;
orderFriends(friend.id);
notifyListeners();
@ -326,13 +294,8 @@ class ChatProvider extends ChangeNotifier { @@ -326,13 +294,8 @@ class ChatProvider extends ChangeNotifier {
if (!msg.isDelivery) {
msg.isDelivery = null; // When message create, set is is none;
}
this.friends[msg.fid].updateLastMessage(msg, true);
this.activedMessages[msg.id] = msg;
rpc.send('chat-friend-readed', [this.activedFriendId]);
} else {
if (this.friends.containsKey(msg.fid)) {
this.friends[msg.fid].updateLastMessage(msg, false);
}
}
orderFriends(msg.fid);
notifyListeners();

49
lib/apps/group_chat/add.dart

@ -55,6 +55,8 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -55,6 +55,8 @@ class _GroupAddPageState extends State<GroupAddPage> {
bool _addrChecked = false;
String _myName = '';
bool _requestsLoadMore = true;
// 0 => encrypted, 1 => common, 2 => open.
Widget _groupTypeWidget(String text, int value, ColorScheme color) {
return Row(
@ -179,7 +181,7 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -179,7 +181,7 @@ class _GroupAddPageState extends State<GroupAddPage> {
setState(() {});
});
new Future.delayed(Duration.zero, () {
//context.read<ChatProvider>().requestList();
context.read<GroupChatProvider>().requestList(false);
_myName = context.read<AccountProvider>().activedAccount.name;
});
}
@ -198,6 +200,9 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -198,6 +200,9 @@ class _GroupAddPageState extends State<GroupAddPage> {
final groups = provider.groups;
final createKeys = provider.createKeys;
final requests = provider.requests;
final requestKeys = requests.keys.toList().reversed.toList();
return SafeArea(
child: DefaultTabController(
initialIndex: 0,
@ -263,7 +268,7 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -263,7 +268,7 @@ class _GroupAddPageState extends State<GroupAddPage> {
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InputText(
icon: Icons.person,
icon: Icons.groups,
text: 'Group ID',
controller: _joinIdController,
focus: _joinIdFocus),
@ -285,18 +290,28 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -285,18 +290,28 @@ class _GroupAddPageState extends State<GroupAddPage> {
const SizedBox(height: 20.0),
const Divider(height: 1.0, color: Color(0x40ADB0BB)),
const SizedBox(height: 10.0),
// if (requests.isNotEmpty)
// Container(
// width: 600.0,
// child: ListView.builder(
// itemCount: requestKeys.length,
// shrinkWrap: true,
// physics: ClampingScrollPhysics(),
// scrollDirection: Axis.vertical,
// itemBuilder: (BuildContext context, int index) =>
// _RequestItem(request: requests[requestKeys[index]]),
// ),
// )
if (requests.isNotEmpty)
Container(
width: 600.0,
child: ListView.builder(
itemCount: requestKeys.length,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) =>
_RequestItem(request: requests[requestKeys[index]]),
),
),
if (_requestsLoadMore)
TextButton(
onPressed: () {
provider.requestList(true);
setState(() {
_requestsLoadMore = false;
});
},
child: Text('load more...', style: TextStyle(fontSize: 14.0)),
),
],
),
),
@ -410,7 +425,7 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -410,7 +425,7 @@ class _GroupAddPageState extends State<GroupAddPage> {
Container(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: InputText(
icon: Icons.person,
icon: Icons.account_box,
text: 'Group Name',
controller: _createNameController,
focus: _createNameFocus),
@ -418,7 +433,7 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -418,7 +433,7 @@ class _GroupAddPageState extends State<GroupAddPage> {
Container(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: InputText(
icon: Icons.location_on,
icon: Icons.campaign,
text: 'Group Bio',
controller: _createBioController,
focus: _createBioFocus),
@ -427,7 +442,7 @@ class _GroupAddPageState extends State<GroupAddPage> { @@ -427,7 +442,7 @@ class _GroupAddPageState extends State<GroupAddPage> {
Container(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: InputText(
icon: Icons.turned_in,
icon: Icons.enhanced_encryption,
text: 'Encrypted Key',
controller: _createKeyController,
focus: _createKeyFocus),

7
lib/apps/group_chat/detail.dart

@ -214,7 +214,7 @@ class _GroupChatDetailState extends State<GroupChatDetail> { @@ -214,7 +214,7 @@ class _GroupChatDetailState extends State<GroupChatDetail> {
child: Text('Waiting...')
);
}
final isOnline = this.group.online;
final isOnline = provider.online;
return Column(
children: [
@ -276,9 +276,7 @@ class _GroupChatDetailState extends State<GroupChatDetail> { @@ -276,9 +276,7 @@ class _GroupChatDetailState extends State<GroupChatDetail> {
color: const Color(0xFFEDEDED),
child: Icon(Icons.more_vert_rounded, color: color.primary),
onSelected: (int value) {
if (value == 1) {
//Provider.of<GroupChatProvider>(context, listen: false).groupUpdate(this.group.id, isTop: !this.group.isTop);
} else if (value == 2) {
if (value == 2) {
showShadowDialog(
context,
Icons.info,
@ -368,7 +366,6 @@ class _GroupChatDetailState extends State<GroupChatDetail> { @@ -368,7 +366,6 @@ class _GroupChatDetailState extends State<GroupChatDetail> {
},
itemBuilder: (context) {
return <PopupMenuEntry<int>>[
_menuItem(Color(0xFF6174FF), 1, Icons.vertical_align_top_rounded, this.group.isTop ? lang.cancelTop : lang.setTop),
_menuItem(Color(0xFF6174FF), 2, Icons.qr_code_rounded, lang.info),
_menuItem(Color(0xFF6174FF), 3, Icons.group_rounded, lang.members),
// _menuItem(color.primary, 3, Icons.turned_in_rounded, lang.remark),

28
lib/apps/group_chat/models.dart

@ -89,14 +89,9 @@ class GroupChat { @@ -89,14 +89,9 @@ class GroupChat {
String addr;
String name;
String bio;
bool isTop;
bool isOk;
bool isClosed;
bool isNeedAgree;
RelativeTime lastTime;
String lastContent;
bool lastReaded;
bool online = false;
GroupChat.fromList(List params) {
this.id = params[0];
@ -106,33 +101,20 @@ class GroupChat { @@ -106,33 +101,20 @@ class GroupChat {
this.addr = params[4];
this.name = params[5];
this.bio = params[6];
this.isTop = params[7] == "1";
this.isOk = params[8] == "1";
this.isClosed = params[9] == "1";
this.isNeedAgree = params[10] == "1";
this.lastTime = RelativeTime.fromInt(params[11]);
this.lastContent = params[12];
this.lastReaded = params[13] == "1";
this.online = params[14] == "1";
this.isOk = params[7];
this.isClosed = params[8];
this.isNeedAgree = params[9];
}
Avatar showAvatar({double width = 45.0, bool needOnline = true}) {
Avatar showAvatar({double width = 45.0}) {
final avatar = Global.avatarPath + this.gid + '.png';
return Avatar(
width: width,
name: this.name,
avatarPath: avatar,
online: this.online,
needOnline: needOnline,
hasNew: !this.lastReaded,
needOnline: false,
);
}
updateLastMessage(Message msg, bool isReaded) {
this.lastTime = msg.time;
this.lastContent = msg.shortShow();
this.lastReaded = isReaded;
}
}
class Request {

16
lib/apps/group_chat/page.dart

@ -97,22 +97,6 @@ class ListChat extends StatelessWidget { @@ -97,22 +97,6 @@ class ListChat extends StatelessWidget {
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16.0))
),
Container(
margin: const EdgeInsets.only(left: 15.0, right: 20.0),
child: Text(group.lastTime.toString(),
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0),
),
)
]),
const SizedBox(height: 4.0),
Row(
children: [
Expanded(
child: Text(group.lastContent,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0)),
),
if (group.isClosed)
Container(
margin: const EdgeInsets.only(left: 15.0, right: 20.0),

56
lib/apps/group_chat/provider.dart

@ -18,6 +18,7 @@ class GroupChatProvider extends ChangeNotifier { @@ -18,6 +18,7 @@ class GroupChatProvider extends ChangeNotifier {
SplayTreeMap<int, Request> requests = SplayTreeMap();
int actived;
bool activedOnline;
SplayTreeMap<int, Message> activedMessages = SplayTreeMap();
SplayTreeMap<int, Member> activedMembers = SplayTreeMap();
@ -45,6 +46,7 @@ class GroupChatProvider extends ChangeNotifier { @@ -45,6 +46,7 @@ class GroupChatProvider extends ChangeNotifier {
rpc.addListener('group-chat-join', _join, true);
rpc.addListener('group-chat-agree', _agree, true);
rpc.addListener('group-chat-reject', _reject, false);
rpc.addListener('group-chat-request-list', _requestList, false);
rpc.addListener('group-chat-member-join', _memberJoin, false);
rpc.addListener('group-chat-member-info', _memberInfo, false);
// rpc.addListener('group-chat-member-leave', _memberLeave, false);
@ -102,6 +104,10 @@ class GroupChatProvider extends ChangeNotifier { @@ -102,6 +104,10 @@ class GroupChatProvider extends ChangeNotifier {
rpc.send('group-chat-message-create', [gid, mtype.toInt(), content]);
}
requestList(bool all) {
rpc.send('group-chat-request-list', [all]);
}
_list(List params) {
this.clear();
params.forEach((params) {
@ -116,6 +122,20 @@ class GroupChatProvider extends ChangeNotifier { @@ -116,6 +122,20 @@ class GroupChatProvider extends ChangeNotifier {
notifyListeners();
}
_online(List params) {
if (this.actived == params[0]) {
this.online = true;
notifyListeners();
}
}
_offline(List params) {
if (this.actived == params[0]) {
this.online = false;
notifyListeners();
}
}
_check(List params) {
this.createSupported.clear();
this.createCheckType = CheckTypeExtension.fromInt(params[0]);
@ -140,7 +160,6 @@ class GroupChatProvider extends ChangeNotifier { @@ -140,7 +160,6 @@ class GroupChatProvider extends ChangeNotifier {
_result(List params) {
final id = params[0];
this.groups[id].isOk = params[1];
this.groups[id].online = true;
if (params[1]) {
//this.createKeys.remove(id);
this.orderKeys.add(id);
@ -159,24 +178,6 @@ class GroupChatProvider extends ChangeNotifier { @@ -159,24 +178,6 @@ class GroupChatProvider extends ChangeNotifier {
notifyListeners();
}
_online(List params) {
final id = params[0];
if (this.groups.containsKey(id)) {
this.groups[id].online = true;
notifyListeners();
}
}
_offline(List params) {
final id = params[0];
if (this.groups.containsKey(id)) {
if (this.groups[id].gid == params[1]) {
this.groups[id].online = false;
notifyListeners();
}
}
}
_join(List params) {
this.requests[params[0]] = Request.fromList(params);
notifyListeners();
@ -202,6 +203,14 @@ class GroupChatProvider extends ChangeNotifier { @@ -202,6 +203,14 @@ class GroupChatProvider extends ChangeNotifier {
}
}
_requestList(List params) {
this.requests.clear();
params.forEach((param) {
this.requests[param[0]] = Request.fromList(param);
});
notifyListeners();
}
_memberJoin(List params) {
final member = Member.fromList(params);
if (this.actived == member.fid) {
@ -234,15 +243,8 @@ class GroupChatProvider extends ChangeNotifier { @@ -234,15 +243,8 @@ class GroupChatProvider extends ChangeNotifier {
if (!msg.isDelivery) {
msg.isDelivery = null; // When message create, set is is none;
}
this.groups[msg.fid].updateLastMessage(msg, true);
this.activedMessages[msg.id] = msg;
rpc.send('group-chat-readed', [this.actived]);
} else {
if (this.groups.containsKey(msg.fid)) {
this.groups[msg.fid].updateLastMessage(msg, false);
}
}
//orderGroups(msg.fid);
notifyListeners();
}
}
}

1
lib/l10n/localizations.dart

@ -105,7 +105,6 @@ abstract class AppLocalizations { @@ -105,7 +105,6 @@ abstract class AppLocalizations {
// homeage
String get addFriend;
String get addGroup;
String get chats;
String get groups;
String get devices;
String get nightly;

4
lib/l10n/localizations_en.dart

@ -21,7 +21,7 @@ class AppLocalizationsEn extends AppLocalizations { @@ -21,7 +21,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get info => 'Info';
@override
String get contact => 'Contact';
String get contact => 'Contacts';
@override
String get friend => 'Friend';
@override
@ -127,8 +127,6 @@ class AppLocalizationsEn extends AppLocalizations { @@ -127,8 +127,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get addGroup => 'Add Service';
@override
String get chats => 'Sessions';
@override
String get groups => 'Services';
@override
String get devices => 'Devices';

2
lib/l10n/localizations_zh.dart

@ -127,8 +127,6 @@ class AppLocalizationsZh extends AppLocalizations { @@ -127,8 +127,6 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get addGroup => '添加服务';
@override
String get chats => '聊天列表';
@override
String get groups => '服务列表';
@override
String get devices => '关联设备';

25
lib/pages/home.dart

@ -156,9 +156,6 @@ class _HomeListState extends State<HomeList> with SingleTickerProviderStateMixin @@ -156,9 +156,6 @@ class _HomeListState extends State<HomeList> with SingleTickerProviderStateMixin
final color = Theme.of(context).colorScheme;
final lang = AppLocalizations.of(context);
final provider = context.watch<AccountProvider>();
final chatProvider = context.watch<ChatProvider>();
final chatTops = chatProvider.topKeys;
final friends = chatProvider.friends;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
@ -384,7 +381,27 @@ class DrawerWidget extends StatelessWidget { @@ -384,7 +381,27 @@ class DrawerWidget extends StatelessWidget {
),
const SizedBox(height: 5.0),
const Divider(height: 1.0, color: Color(0x40ADB0BB)),
const SizedBox(height: 10.0),
ListTile(
leading: Icon(Icons.people_rounded, color: color.primary),
title: Text(lang.contact, textAlign: TextAlign.left,
style: TextStyle(fontSize: 16.0)),
onTap: () {
Navigator.pop(context);
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
null, lang.contact, ChatList()
);
}),
ListTile(
leading: Icon(Icons.grid_view_rounded, color: color.primary),
title: Text(lang.groups, textAlign: TextAlign.left,
style: TextStyle(fontSize: 16.0)),
onTap: () {
Navigator.pop(context);
Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
null, lang.groups, ServiceList()
);
}),
const Divider(height: 1.0, color: Color(0x40ADB0BB)),
ListTile(
leading: Icon(Icons.person, color: color.primary),
title: Text(lang.profile,

90
lib/provider.dart

@ -10,6 +10,7 @@ import 'package:esse/widgets/default_core_show.dart'; @@ -10,6 +10,7 @@ import 'package:esse/widgets/default_core_show.dart';
import 'package:esse/widgets/default_home_show.dart';
import 'package:esse/global.dart';
import 'package:esse/rpc.dart';
import 'package:esse/session.dart';
const DEFAULT_ONLINE_INIT = 8;
const DEFAULT_ONLINE_DELAY = 5;
@ -19,7 +20,10 @@ class AccountProvider extends ChangeNotifier { @@ -19,7 +20,10 @@ class AccountProvider extends ChangeNotifier {
String activedAccountId; // actived account gid.
Account get activedAccount => this.accounts[activedAccountId];
Set<int> topKeys = Set();
/// 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;
@ -32,6 +36,13 @@ class AccountProvider extends ChangeNotifier { @@ -32,6 +36,13 @@ class AccountProvider extends ChangeNotifier {
Widget get homeShowWidget => this.currentListShow ?? this.defaultListShow;
void orderSessions(int id) {
if (this.orderKeys.length == 0 || this.orderKeys[0] != id) {
this.orderKeys.remove(id);
this.orderKeys.insert(0, id);
}
}
AccountProvider() {
// rpc notice when account not actived.
rpc.addNotice(_accountNotice, _newRequestNotice);
@ -41,11 +52,13 @@ class AccountProvider extends ChangeNotifier { @@ -41,11 +52,13 @@ class AccountProvider extends ChangeNotifier {
rpc.addListener('account-update', _accountUpdate, false);
rpc.addListener('account-login', _accountLogin, false);
systemInfo();
}
rpc.addListener('session-list', _sessionList, false);
rpc.addListener('session-last', _sessionLast, true);
rpc.addListener('session-create', _sessionCreate, true);
rpc.addListener('session-update', _sessionUpdate, false);
rpc.addListener('session-delete', _sessionDelete, false);
handleTops() {
//
systemInfo();
}
/// when security load accounts from rpc.
@ -62,6 +75,8 @@ class AccountProvider extends ChangeNotifier { @@ -62,6 +75,8 @@ class AccountProvider extends ChangeNotifier {
this.activedAccount.online = true;
rpc.send('account-login', [gid, this.activedAccount.lock]);
rpc.send('session-list', []);
new Future.delayed(Duration(seconds: DEFAULT_ONLINE_INIT),
() => rpc.send('account-online', [gid]));
@ -81,6 +96,8 @@ class AccountProvider extends ChangeNotifier { @@ -81,6 +96,8 @@ class AccountProvider extends ChangeNotifier {
this.accounts[account.gid] = account;
rpc.send('account-login', [account.gid, account.lock]);
rpc.send('session-list', []);
new Future.delayed(Duration(seconds: DEFAULT_ONLINE_DELAY),
() => rpc.send('account-online', [account.gid]));
updateLogined(account);
@ -94,6 +111,11 @@ class AccountProvider extends ChangeNotifier { @@ -94,6 +111,11 @@ class AccountProvider extends ChangeNotifier {
this.coreShowWidget = DefaultCoreShow();
this.currentListShow = null;
// load sessions.
this.sessions.clear();
this.orderKeys.clear();
rpc.send('session-list', []);
if (!this.activedAccount.online) {
this.activedAccount.online = true;
rpc.send('account-login', [gid, this.activedAccount.lock]);
@ -109,6 +131,10 @@ class AccountProvider extends ChangeNotifier { @@ -109,6 +131,10 @@ class AccountProvider extends ChangeNotifier {
this.accounts.clear();
this.clearActivedAccount();
this.currentListShow = null;
this.sessions.clear();
this.orderKeys.clear();
this.topKeys.clear();
rpc.send('account-logout', []);
clearLogined();
}
@ -213,4 +239,58 @@ class AccountProvider extends ChangeNotifier { @@ -213,4 +239,58 @@ class AccountProvider extends ChangeNotifier {
}
notifyListeners();
}
_sessionList(List params) {
this.sessions.clear();
this.orderKeys.clear();
this.topKeys.clear();
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);
}
});
notifyListeners();
}
_sessionCreate(List params) {
final id = params[0];
this.sessions[id] = Session.fromList(params);
orderSessions(id);
notifyListeners();
}
_sessionLast(List params) {
final id = params[0];
this.sessions[id].last(params);
orderSessions(id);
notifyListeners();
}
_sessionUpdate(List params) {
final id = params[0];
this.sessions[id].update(params);
if (this.sessions[id].isTop) {
this.topKeys.add(id);
this.orderKeys.remove(id);
} else {
orderSessions(id);
this.topKeys.remove(id);
}
notifyListeners();
}
_sessionDelete(List params) {
final id = params[1];
this.sessions.remove(id);
this.orderKeys.remove(id);
this.topKeys.remove(id);
notifyListeners();
}
}

122
lib/session.dart

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'package:esse/l10n/localizations.dart';
import 'package:esse/utils/relative_time.dart';
import 'package:esse/widgets/avatar.dart';
import 'package:esse/global.dart';
import 'package:esse/apps/service/models.dart';
import 'package:esse/apps/primitives.dart';
enum SessionType {
Chat,
Group,
Files,
Device,
Assistant,
Domain,
Service,
}
extension SessionTypeExtension on SessionType {
static SessionType fromInt(int s) {
switch (s) {
case 0:
return SessionType.Chat;
case 1:
return SessionType.Group;
case 2:
return SessionType.Files;
case 3:
return SessionType.Device;
case 4:
return SessionType.Assistant;
case 5:
return SessionType.Domain;
case 6:
return SessionType.Service;
default:
return SessionType.Chat;
}
}
}
class Session {
int id;
int fid;
String gid;
String addr;
SessionType type;
String name;
bool isTop;
RelativeTime lastTime;
String lastContent;
bool lastReaded;
bool online = false;
static List innerService(InnerService service, AppLocalizations lang) {
final params = service.params(lang);
final avatar = Container(
padding: const EdgeInsets.all(6.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
),
child: Image.asset(params[2]),
);
final name = params[0];
final bio = params[1];
return [avatar, name, bio];
}
List parse(AppLocalizations lang) {
switch (this.type) {
case SessionType.Chat:
return [showAvatar(), this.name, this.lastContent, this.lastTime.toString()];
case SessionType.Assistant:
final params = Session.innerService(InnerService.Assistant, lang);
return [params[0], params[1], params[2], ''];
case SessionType.Files:
final params = Session.innerService(InnerService.Files, lang);
return [params[0], params[1], params[2], ''];
}
}
Avatar showAvatar({double width = 45.0, bool needOnline = true}) {
final avatar = Global.avatarPath + this.gid + '.png';
return Avatar(
width: width,
name: this.name,
avatarPath: avatar,
online: this.online,
needOnline: needOnline,
hasNew: !this.lastReaded,
);
}
last(List params) {
this.lastTime = RelativeTime.fromInt(params[1]);
this.lastContent = params[2];
this.lastReaded = params[3];
}
update(List params) {
this.addr = params[1];
this.name = params[2];
this.isTop = params[3];
this.online = params[4];
}
Session.fromList(List params) {
this.id = params[0];
this.fid = params[1];
this.gid = params[2];
this.addr = params[3];
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];
}
}

143
lib/widgets/default_home_show.dart

@ -6,11 +6,7 @@ import 'package:esse/utils/adaptive.dart'; @@ -6,11 +6,7 @@ import 'package:esse/utils/adaptive.dart';
import 'package:esse/widgets/list_system_app.dart';
import 'package:esse/options.dart';
import 'package:esse/provider.dart';
import 'package:esse/apps/service/list.dart';
import 'package:esse/apps/service/models.dart';
import 'package:esse/apps/chat/provider.dart';
import 'package:esse/apps/chat/list.dart';
import 'package:esse/session.dart';
class DefaultHomeShow extends StatelessWidget {
const DefaultHomeShow({Key key}): super(key: key);
@ -19,39 +15,118 @@ class DefaultHomeShow extends StatelessWidget { @@ -19,39 +15,118 @@ class DefaultHomeShow extends StatelessWidget {
Widget build(BuildContext context) {
final isDesktop = isDisplayDesktop(context);
final lang = AppLocalizations.of(context);
final chatProvider = context.watch<ChatProvider>();
final chatTops = chatProvider.topKeys;
final friends = chatProvider.friends;
return Column(children: [
ListSystemApp(name: lang.chats, icon: Icons.people_rounded,
callback: () => Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
null, lang.chats, ChatList())),
ListSystemApp(name: lang.groups, icon: Icons.grid_view_rounded,
callback: () => Provider.of<AccountProvider>(context, listen: false).updateActivedApp(
null, lang.groups, ServiceList())),
const SizedBox(height: 5.0),
const Divider(height: 1.0, color: Color(0x40ADB0BB)),
const SizedBox(height: 5.0),
Column(
children: INNER_SERVICES.map((v) {
final params = v.params(lang);
return ListInnerService(
name: params[0],
bio: params[1],
logo: params[2],
callback: () => v.callback(context, isDesktop, lang),
isDesktop: isDesktop,
final provider = context.watch<AccountProvider>();
final allKeys = provider.topKeys + provider.orderKeys;
final sessions = provider.sessions;
return Scaffold(
body: ListView.builder(
itemCount: allKeys.length,
itemBuilder: (BuildContext ctx, int index) => _SessionWidget(session: sessions[allKeys[index]]),
),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// final widget = Text('');
// if (isDesktop) {
// Provider.of<AccountProvider>(context, listen: false).updateActivedApp(widget);
// } else {
// Navigator.push(context, MaterialPageRoute(builder: (_) => widget));
// }
// },
// child: const Icon(Icons.add, color: Colors.white),
// backgroundColor: Color(0xFF6174FF),
// ),
);
}).toList()
}
}
class _SessionWidget extends StatelessWidget {
final Session session;
const _SessionWidget({Key key, this.session}) : super(key: key);
@override
Widget build(BuildContext context) {
final color = Theme.of(context).colorScheme;
final lang = AppLocalizations.of(context);
final isDesktop = isDisplayDesktop(context);
final params = session.parse(lang);
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
// TODO
// context.read<ChatProvider>().updateActivedFriend(friend.id);
// if (!isDesktop) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (_) => ChatPage(),
// ),
// );
// } else {
// context.read<AccountProvider>().updateActivedApp(ChatDetail());
// }
},
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),
child: params[0],
),
Expanded(
child: ListView.builder(
itemCount: chatTops.length,
itemBuilder: (BuildContext ctx, int index) => ListChat(
friend: friends[chatTops.keys.elementAt(index)]),
child: Container(
height: 55.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(params[1],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16.0))
),
Container(
margin: const EdgeInsets.only(left: 15.0, right: 20.0),
child: Text(params[3],
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0),
),
)
]);
]),
const SizedBox(height: 4.0),
Row(
children: [
Expanded(
child: Text(params[2],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Color(0xFFADB0BB), fontSize: 12.0)),
),
// if (session.isClosed)
// Container(
// margin: const EdgeInsets.only(left: 15.0, right: 20.0),
// child: Text(lang.unfriended,
// style: TextStyle(color: color.primary, fontSize: 12.0),
// ),
// )
]),
],
),
),
),
],
),
),
);
}
}

18
pubspec.lock

@ -161,7 +161,7 @@ packages: @@ -161,7 +161,7 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.0"
version: "6.1.1"
file_picker:
dependency: "direct main"
description:
@ -302,7 +302,7 @@ packages: @@ -302,7 +302,7 @@ packages:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
version: "0.7.5+2"
image_picker_for_web:
dependency: transitive
description:
@ -447,14 +447,14 @@ packages: @@ -447,14 +447,14 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.0"
version: "8.0.0+2"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.0"
version: "3.5.0"
petitparser:
dependency: transitive
description:
@ -641,7 +641,7 @@ packages: @@ -641,7 +641,7 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
version: "6.0.4"
url_launcher_linux:
dependency: transitive
description:
@ -662,7 +662,7 @@ packages: @@ -662,7 +662,7 @@ packages:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
url_launcher_web:
dependency: transitive
description:
@ -718,7 +718,7 @@ packages: @@ -718,7 +718,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
version: "2.1.1"
xdg_directories:
dependency: transitive
description:
@ -732,7 +732,7 @@ packages: @@ -732,7 +732,7 @@ packages:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.1.1"
yaml:
dependency: transitive
description:
@ -741,5 +741,5 @@ packages: @@ -741,5 +741,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.12.1 <3.0.0"
dart: ">=2.13.0 <3.0.0"
flutter: ">=2.0.2"

4
src/apps/assistant/models.rs

@ -9,7 +9,7 @@ use tdn::types::{ @@ -9,7 +9,7 @@ use tdn::types::{
use tdn_storage::local::{DStorage, DsValue};
use crate::apps::chat::Friend;
use crate::storage::{read_file, session_db, write_file, write_image};
use crate::storage::{chat_db, read_file, write_file, write_image};
#[derive(Eq, PartialEq, Clone)]
pub(crate) enum MessageType {
@ -69,7 +69,7 @@ impl MessageType { @@ -69,7 +69,7 @@ impl MessageType {
}
MessageType::Contact => {
let cid: i64 = content.parse().map_err(|_e| new_io_error("id error"))?;
let db = session_db(base, mgid)?;
let db = chat_db(base, mgid)?;
let contact = Friend::get_id(&db, cid)??;
db.close()?;
let tmp_name = contact.name.replace(";", "-;");

42
src/apps/chat/layer.rs

@ -15,7 +15,7 @@ use crate::event::{InnerEvent, StatusEvent}; @@ -15,7 +15,7 @@ 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::storage::{
read_avatar, read_file, read_record, session_db, write_avatar_sync, write_file, write_image,
chat_db, read_avatar, read_file, read_record, write_avatar_sync, write_file, write_image,
};
use super::models::{Friend, Message, MessageType, NetworkMessage, Request};
@ -100,7 +100,7 @@ pub(crate) async fn handle( @@ -100,7 +100,7 @@ pub(crate) async fn handle(
.check_add_online(fgid, Online::Direct(addr), f.id)?;
// 3. update remote addr. TODO
if f.addr != addr {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
let _ = Friend::addr_update(&db, f.id, &addr);
drop(db);
}
@ -119,7 +119,7 @@ pub(crate) async fn handle( @@ -119,7 +119,7 @@ pub(crate) async fn handle(
let some_friend = load_friend(&layer.base, &mgid, &fgid)?;
if some_friend.is_none() {
// check if exist request.
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(req) = Request::get(&db, &remote.id)? {
req.delete(&db)?; // delete the old request.
results.rpcs.push(rpc::request_delete(mgid, req.id));
@ -161,13 +161,15 @@ pub(crate) async fn handle( @@ -161,13 +161,15 @@ pub(crate) async fn handle(
// 2. update remote user.
friend.name = remote.name;
friend.addr = remote.addr;
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
friend.remote_update(&db)?;
drop(db);
write_avatar_sync(&layer.base, &mgid, &remote.id, remote.avatar)?;
// 3. online to UI.
friend.online = true;
// TODO UPDATE SESSION
results.rpcs.push(rpc::friend_info(mgid, &friend));
// 4. connected.
let msg = conn_agree_message(&mut layer, 0, &mgid, addr).await?;
@ -204,7 +206,7 @@ pub(crate) async fn handle( @@ -204,7 +206,7 @@ pub(crate) async fn handle(
RecvType::Result(addr, is_ok, data) => {
// check to close.
if !is_ok {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(friend) = Friend::get_it(&db, &fgid)? {
if friend.contains_addr(&addr) {
results.rpcs.push(rpc::friend_close(mgid, friend.id));
@ -217,7 +219,7 @@ pub(crate) async fn handle( @@ -217,7 +219,7 @@ pub(crate) async fn handle(
.map_err(|_e| new_io_error("Deseralize result failure"))?;
match response {
LayerResponse::Reject => {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(mut request) = Request::get(&db, &fgid)? {
layer.group.write().await.broadcast(
&mgid,
@ -258,7 +260,7 @@ pub(crate) async fn handle( @@ -258,7 +260,7 @@ pub(crate) async fn handle(
.running_mut(&mgid)?
.check_add_online(fgid, Online::Direct(addr), fid)?;
// 4. update remote addr.
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
Friend::addr_update(&db, fid, &addr)?;
drop(db);
// 5. online to UI.
@ -287,7 +289,7 @@ pub(crate) async fn handle( @@ -287,7 +289,7 @@ pub(crate) async fn handle(
)?;
} else {
// agree request for friend.
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(mut request) = Request::get(&db, &remote.id)? {
layer.group.write().await.broadcast(
&mgid,
@ -340,7 +342,7 @@ pub(crate) async fn handle( @@ -340,7 +342,7 @@ pub(crate) async fn handle(
.running_mut(&mgid)?
.check_add_online(fgid, Online::Direct(addr), fid)?;
// 4. update remote addr.
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
Friend::addr_update(&db, fid, &addr)?;
drop(db);
// 5. online to UI.
@ -372,7 +374,7 @@ pub(crate) async fn handle( @@ -372,7 +374,7 @@ pub(crate) async fn handle(
)?;
} else {
// agree request for friend.
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(mut request) = Request::get(&db, &remote.id)? {
layer.group.write().await.broadcast(
&mgid,
@ -402,7 +404,7 @@ pub(crate) async fn handle( @@ -402,7 +404,7 @@ pub(crate) async fn handle(
results.layers.push((mgid, fgid, msg));
}
LayerResponse::Reject => {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if let Some(mut request) = Request::get(&db, &fgid)? {
layer.group.write().await.broadcast(
&mgid,
@ -431,7 +433,7 @@ pub(crate) async fn handle( @@ -431,7 +433,7 @@ pub(crate) async fn handle(
// TODO maybe send failure need handle.
if is_ok {
if let Some((gid, db_id)) = layer.delivery.remove(&tid) {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
let resp = match t {
DeliveryType::Event => {
Message::delivery(&db, db_id, true)?;
@ -474,7 +476,7 @@ impl LayerEvent { @@ -474,7 +476,7 @@ impl LayerEvent {
match event {
LayerEvent::Message(hash, m) => {
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
if !Message::exist(&db, &hash)? {
let msg = m.clone().handle(false, mgid, &layer.base, &db, fid, hash)?;
layer.group.write().await.broadcast(
@ -489,7 +491,7 @@ impl LayerEvent { @@ -489,7 +491,7 @@ impl LayerEvent {
}
LayerEvent::Info(remote) => {
let avatar = remote.avatar.clone();
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
let mut f = Friend::get_id(&db, fid)?.ok_or(new_io_error(""))?;
f.name = remote.name;
f.addr = remote.addr;
@ -549,7 +551,7 @@ impl LayerEvent { @@ -549,7 +551,7 @@ impl LayerEvent {
&mut results,
)?;
layer.remove_online(&mgid, &fgid);
let db = session_db(&layer.base, &mgid)?;
let db = chat_db(&layer.base, &mgid)?;
Friend::id_close(&db, fid)?;
drop(db);
results.rpcs.push(rpc::friend_close(mgid, fid));
@ -571,7 +573,7 @@ impl LayerEvent { @@ -571,7 +573,7 @@ impl LayerEvent {
m_type: MessageType,
content: String,
) -> std::result::Result<(Message, NetworkMessage), tdn::types::rpc::RpcError> {
let db = session_db(&base, &mgid)?;
let db = chat_db(&base, &mgid)?;
// handle message's type.
let (nm_type, raw) = match m_type {
@ -630,7 +632,9 @@ impl LayerEvent { @@ -630,7 +632,9 @@ impl LayerEvent {
let mut msg = Message::new(&mgid, fid, true, m_type, raw, false);
msg.insert(&db)?;
Friend::update_last_message(&db, fid, &msg, true)?;
// TODO UPDATE SESSION
drop(db);
Ok((msg, nm_type))
}
@ -638,7 +642,7 @@ impl LayerEvent { @@ -638,7 +642,7 @@ impl LayerEvent {
#[inline]
fn load_friend(base: &PathBuf, mgid: &GroupId, fgid: &GroupId) -> Result<Option<Friend>> {
let db = session_db(base, mgid)?;
let db = chat_db(base, mgid)?;
Friend::get(&db, fgid)
}

76
src/apps/chat/models.rs

@ -19,13 +19,9 @@ pub(crate) struct Friend { @@ -19,13 +19,9 @@ pub(crate) struct Friend {
pub addr: PeerAddr,
pub name: String,
pub remark: String,
pub is_top: bool,
pub is_closed: bool,
pub last_message_datetime: i64,
pub last_message_content: String,
pub last_message_readed: bool,
pub online: bool,
pub is_deleted: bool,
pub datetime: i64,
}
#[derive(Clone)]
@ -114,7 +110,9 @@ impl NetworkMessage { @@ -114,7 +110,9 @@ impl NetworkMessage {
let mut msg = Message::new_with_id(hash, fid, is_me, m_type, raw, true);
msg.insert(db)?;
Friend::update_last_message(db, fid, &msg, false)?;
// TODO UPDATE SESSION
Ok(msg)
}
@ -221,15 +219,11 @@ impl Friend { @@ -221,15 +219,11 @@ impl Friend {
Friend {
id: 0,
last_message_datetime: datetime,
last_message_content: "".to_owned(),
last_message_readed: true,
gid,
addr,
name,
remark,
online: false,
is_top: false,
datetime,
is_closed: false,
is_deleted: false,
}
@ -249,17 +243,13 @@ impl Friend { @@ -249,17 +243,13 @@ impl Friend {
Friend {
is_deleted,
last_message_readed: v.pop().unwrap().as_bool(),
last_message_content: v.pop().unwrap().as_string(),
last_message_datetime: v.pop().unwrap().as_i64(),
datetime: v.pop().unwrap().as_i64(),
is_closed: v.pop().unwrap().as_bool(),
is_top: v.pop().unwrap().as_bool(),
remark: v.pop().unwrap().as_string(),
name: v.pop().unwrap().as_string(),
addr: PeerAddr::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerAddr::default()),
gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()),
id: v.pop().unwrap().as_i64(),
online: false,
}
}
@ -284,17 +274,13 @@ impl Friend { @@ -284,17 +274,13 @@ impl Friend {
self.addr.to_hex(),
self.name,
self.remark,
if self.is_top { "1" } else { "0" },
if self.is_closed { "1" } else { "0" },
self.last_message_datetime,
self.last_message_content,
self.last_message_readed,
if self.online { "1" } else { "0" },
self.is_closed,
self.datetime
])
}
pub fn get(db: &DStorage, gid: &GroupId) -> Result<Option<Friend>> {
let sql = format!("SELECT id, gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed FROM friends WHERE gid = '{}' and is_deleted = false", gid.to_hex());
let sql = format!("SELECT id, gid, addr, name, remark, is_closed, datetime FROM friends WHERE gid = '{}' and is_deleted = false", gid.to_hex());
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
return Ok(Some(Friend::from_values(matrix.pop().unwrap(), false))); // safe unwrap()
@ -303,7 +289,7 @@ impl Friend { @@ -303,7 +289,7 @@ impl Friend {
}
pub fn get_it(db: &DStorage, gid: &GroupId) -> Result<Option<Friend>> {
let sql = format!("SELECT id, gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed, is_deleted FROM friends WHERE gid = '{}'", gid.to_hex());
let sql = format!("SELECT id, gid, addr, name, remark, is_closed, datetime, is_deleted FROM friends WHERE gid = '{}'", gid.to_hex());
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
return Ok(Some(Friend::from_values(matrix.pop().unwrap(), true))); // safe unwrap()
@ -312,7 +298,7 @@ impl Friend { @@ -312,7 +298,7 @@ impl Friend {
}
pub fn get_id(db: &DStorage, id: i64) -> Result<Option<Friend>> {
let sql = format!("SELECT id, gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed, is_deleted FROM friends WHERE id = {}", id);
let sql = format!("SELECT id, gid, addr, name, remark, is_closed, datetime, is_deleted FROM friends WHERE id = {}", id);
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
return Ok(Some(Friend::from_values(matrix.pop().unwrap(), true))); // safe unwrap()
@ -322,7 +308,7 @@ impl Friend { @@ -322,7 +308,7 @@ impl Friend {
/// use in rpc when load account friends.
pub fn all(db: &DStorage) -> Result<Vec<Friend>> {
let matrix = db.query("SELECT id, gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed FROM friends where is_deleted = false ORDER BY last_message_datetime DESC")?;
let matrix = db.query("SELECT id, gid, addr, name, remark, is_closed, datetime FROM friends where is_deleted = false")?;
let mut friends = vec![];
for values in matrix {
friends.push(Friend::from_values(values, false));
@ -332,7 +318,7 @@ impl Friend { @@ -332,7 +318,7 @@ impl Friend {
/// use in rpc when load account friends.
pub fn all_ok(db: &DStorage) -> Result<Vec<Friend>> {
let matrix = db.query("SELECT id, gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed FROM friends where is_closed = false ORDER BY last_message_datetime DESC")?;
let matrix = db.query("SELECT id, gid, addr, name, remark, is_closed, datetime FROM friends where is_closed = false")?;
let mut friends = vec![];
for values in matrix {
friends.push(Friend::from_values(values, false));
@ -355,16 +341,13 @@ impl Friend { @@ -355,16 +341,13 @@ impl Friend {
}
pub fn insert(&mut self, db: &DStorage) -> Result<()> {
let sql = format!("INSERT INTO friends (gid, addr, name, remark, is_top, is_closed, last_message_datetime, last_message_content, last_message_readed, is_deleted) VALUES ('{}', '{}', '{}', '{}', {}, {}, {}, '{}', {}, false)",
let sql = format!("INSERT INTO friends (gid, addr, name, remark, is_closed, datetime, is_deleted) VALUES ('{}', '{}', '{}', '{}', {}, {}, false)",
self.gid.to_hex(),
self.addr.to_hex(),
self.name,
self.remark,
if self.is_top { 1 } else { 0 },
if self.is_closed { 1 } else { 0 },
self.last_message_datetime,
self.last_message_content,
if self.last_message_readed { 1 } else { 0 }
self.datetime,
);
let id = db.insert(&sql)?;
self.id = id;
@ -372,15 +355,11 @@ impl Friend { @@ -372,15 +355,11 @@ impl Friend {
}
pub fn update(&self, db: &DStorage) -> Result<usize> {
let sql = format!("UPDATE friends SET addr = '{}', name = '{}', remark = '{}', is_top = {}, is_closed = {}, last_message_datetime = {}, last_message_content = '{}', last_message_readed = {}, is_deleted = {} WHERE id = {}",
let sql = format!("UPDATE friends SET addr = '{}', name = '{}', remark = '{}', is_closed = {}, is_deleted = {} WHERE id = {}",
self.addr.to_hex(),
self.name,
self.remark,
if self.is_top { 1 } else { 0 },
if self.is_closed { 1 } else { 0 },
self.last_message_datetime,
self.last_message_content,
if self.last_message_readed { 1 } else { 0 },
if self.is_deleted { 1 } else { 0 },
self.id
);
@ -389,8 +368,8 @@ impl Friend { @@ -389,8 +368,8 @@ impl Friend {
pub fn me_update(&mut self, db: &DStorage) -> Result<usize> {
let sql = format!(
"UPDATE friends SET remark='{}', is_top={} WHERE id = {}",
self.remark, self.is_top, self.id,
"UPDATE friends SET remark='{}' WHERE id = {}",
self.remark, self.id,
);
db.update(&sql)
}
@ -414,21 +393,6 @@ impl Friend { @@ -414,21 +393,6 @@ impl Friend {
db.update(&sql)
}
pub fn update_last_message(db: &DStorage, id: i64, msg: &Message, read: bool) -> Result<usize> {
let sql = format!("UPDATE friends SET last_message_datetime={}, last_message_content='{}', last_message_readed={} WHERE id = {}",
msg.datetime,
msg.content,
if read { 1 } else { 0 },
id,
);
db.update(&sql)
}
pub fn readed(db: &DStorage, id: i64) -> Result<usize> {
let sql = format!("UPDATE friends SET last_message_readed=1 WHERE id = {}", id);
db.update(&sql)
}
/// used in rpc, when what to delete a friend.
pub fn close(&self, db: &DStorage) -> Result<usize> {
let sql = format!("UPDATE friends SET is_closed = true WHERE id = {}", self.id);
@ -492,7 +456,9 @@ impl Request { @@ -492,7 +456,9 @@ impl Request {
pub fn to_friend(self) -> Friend {
let mut friend = Friend::new(self.gid, self.addr, self.name, self.remark);
friend.is_top = true; // default set to top page.
// TODO add new session.
friend
}

52
src/apps/chat/rpc.rs

@ -11,7 +11,7 @@ use tdn_did::user::User; @@ -11,7 +11,7 @@ use tdn_did::user::User;
use crate::event::InnerEvent;
use crate::migrate::consensus::{FRIEND_TABLE_PATH, MESSAGE_TABLE_PATH, REQUEST_TABLE_PATH};
use crate::rpc::{sleep_waiting_close_stable, RpcState};
use crate::storage::{delete_avatar, session_db};
use crate::storage::{chat_db, delete_avatar};
use super::layer::LayerEvent;
use super::{Friend, Message, MessageType, Request};
@ -32,8 +32,8 @@ pub(crate) fn friend_info(mgid: GroupId, friend: &Friend) -> RpcParam { @@ -32,8 +32,8 @@ pub(crate) fn friend_info(mgid: GroupId, friend: &Friend) -> RpcParam {
}
#[inline]
pub(crate) fn friend_update(mgid: GroupId, fid: i64, is_top: bool, remark: &str) -> RpcParam {
rpc_response(0, "chat-friend-update", json!([fid, is_top, remark]), mgid)
pub(crate) fn friend_update(mgid: GroupId, fid: i64, remark: &str) -> RpcParam {
rpc_response(0, "chat-friend-update", json!([fid, remark]), mgid)
}
#[inline]
@ -123,16 +123,10 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -123,16 +123,10 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
"chat-friend-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 db = chat_db(&layer_lock.base, &gid)?;
let mut friends = Friend::all(&db)?;
drop(db);
let gids: Vec<&GroupId> = friends.iter().map(|f| &f.gid).collect();
let onlines = layer_lock.merge_online(&gid, gids)?;
for (index, online) in onlines.iter().enumerate() {
friends[index].online = *online;
}
Ok(HandleResult::rpc(friend_list(friends)))
},
);
@ -142,12 +136,10 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -142,12 +136,10 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let id = params[0].as_i64()?;
let remark = params[1].as_str()?;
let is_top = params[2].as_bool()?;
let mut results = HandleResult::new();
let db = session_db(state.layer.read().await.base(), &gid)?;
let db = chat_db(state.layer.read().await.base(), &gid)?;
let f = if let Some(mut f) = Friend::get_id(&db, id)? {
f.is_top = is_top;
f.remark = remark.to_owned();
f.me_update(&db)?;
f
@ -157,7 +149,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -157,7 +149,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
drop(db);
state.group.write().await.broadcast(
&gid,
InnerEvent::SessionFriendUpdate(f.gid, f.is_top, f.remark),
InnerEvent::SessionFriendUpdate(f.gid, f.remark),
FRIEND_TABLE_PATH,
f.id,
&mut results,
@ -166,19 +158,6 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -166,19 +158,6 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
},
);
handler.add_method(
"chat-friend-readed",
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let fid = params[0].as_i64()?;
let db = session_db(state.layer.read().await.base(), &gid)?;
Friend::readed(&db, fid)?;
drop(db);
Ok(HandleResult::new())
},
);
handler.add_method(
"chat-friend-close",
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
@ -187,7 +166,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -187,7 +166,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let mut results = HandleResult::new();
let mut layer_lock = state.layer.write().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
let friend = Friend::get_id(&db, id)??;
friend.close(&db)?;
drop(db);
@ -227,7 +206,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -227,7 +206,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let mut results = HandleResult::new();
let mut layer_lock = state.layer.write().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
let friend = Friend::get_id(&db, id)??;
friend.delete(&db)?;
drop(db);
@ -264,7 +243,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -264,7 +243,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
"chat-request-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 db = chat_db(layer_lock.base(), &gid)?;
drop(layer_lock);
let requests = Request::all(&db)?;
drop(db);
@ -292,7 +271,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -292,7 +271,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let me = state.group.read().await.clone_user(&gid)?;
let mut layer_lock = state.layer.write().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
if Friend::is_friend(&db, &request.gid)? {
debug!("had friend.");
drop(layer_lock);
@ -340,7 +319,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -340,7 +319,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let mut group_lock = state.group.write().await;
let me = group_lock.clone_user(&gid)?;
let mut layer_lock = state.layer.write().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
let mut results = HandleResult::new();
if let Some(mut request) = Request::get_id(&db, id)? {
@ -376,7 +355,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -376,7 +355,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let id = params[0].as_i64()?;
let mut layer_lock = state.layer.write().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
let mut req = Request::get_id(&db, id)??;
req.is_ok = false;
req.is_over = true;
@ -403,7 +382,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -403,7 +382,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let id = params[0].as_i64()?;
let layer_lock = state.layer.read().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
let base = layer_lock.base().clone();
drop(layer_lock);
let req = Request::get_id(&db, id)??;
@ -433,10 +412,9 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -433,10 +412,9 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let fid = params[0].as_i64()?;
let layer_lock = state.layer.read().await;
let db = session_db(layer_lock.base(), &gid)?;
let db = chat_db(layer_lock.base(), &gid)?;
drop(layer_lock);
Friend::readed(&db, fid)?;
let messages = Message::get(&db, &fid)?;
drop(db);
Ok(HandleResult::rpc(message_list(messages)))
@ -486,7 +464,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -486,7 +464,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let id = params[0].as_i64()?;
let layer_lock = state.layer.read().await;
let db = session_db(&layer_lock.base(), &gid)?;
let db = chat_db(&layer_lock.base(), &gid)?;
drop(layer_lock);
let msg = Message::get_id(&db, id)??;

116
src/apps/group_chat/models.rs

@ -71,8 +71,6 @@ pub(crate) struct GroupChat { @@ -71,8 +71,6 @@ pub(crate) struct GroupChat {
g_name: String,
/// group chat simple intro.
g_bio: String,
/// group chat is set top sessions.
is_top: bool,
/// group chat is created ok.
is_ok: bool,
/// group chat is closed.
@ -81,16 +79,8 @@ pub(crate) struct GroupChat { @@ -81,16 +79,8 @@ pub(crate) struct GroupChat {
is_need_agree: bool,
/// group chat encrypted-key.
key: GroupChatKey,
/// group chat lastest message time. (only ESSE used)
last_datetime: i64,
/// group chat lastest message content. (only ESSE used)
last_content: String,
/// group chat lastest message readed. (only ESSE used)
last_readed: bool,
/// group chat created time.
pub datetime: i64,
/// group chat is online.
pub online: bool,
/// is deleted.
is_deleted: bool,
}
@ -126,13 +116,8 @@ impl GroupChat { @@ -126,13 +116,8 @@ impl GroupChat {
datetime,
id: 0,
height: 0,
is_top: true,
is_ok: false,
is_closed: false,
last_datetime: datetime,
last_content: Default::default(),
last_readed: true,
online: false,
is_deleted: false,
}
}
@ -166,13 +151,8 @@ impl GroupChat { @@ -166,13 +151,8 @@ impl GroupChat {
datetime,
id: 0,
height,
is_top: true,
is_ok: true,
is_closed: false,
last_datetime: datetime,
last_content: Default::default(),
last_readed: true,
online: false,
is_deleted: false,
}
}
@ -243,14 +223,9 @@ impl GroupChat { @@ -243,14 +223,9 @@ impl GroupChat {
self.g_addr.to_hex(),
self.g_name,
self.g_bio,
if self.is_top { "1" } else { "0" },
if self.is_ok { "1" } else { "0" },
if self.is_closed { "1" } else { "0" },
if self.is_need_agree { "1" } else { "0" },
self.last_datetime,
self.last_content,
if self.last_readed { "1" } else { "0" },
if self.online { "1" } else { "0" },
self.is_ok,
self.is_closed,
self.is_need_agree,
])
}
@ -263,17 +238,12 @@ impl GroupChat { @@ -263,17 +238,12 @@ impl GroupChat {
Self {
is_deleted,
online: false,
datetime: v.pop().unwrap().as_i64(),
last_readed: v.pop().unwrap().as_bool(),
last_content: v.pop().unwrap().as_string(),
last_datetime: v.pop().unwrap().as_i64(),
key: GroupChatKey::from_hex(v.pop().unwrap().as_string())
.unwrap_or(GroupChatKey::new(vec![])),
is_closed: v.pop().unwrap().as_bool(),
is_need_agree: v.pop().unwrap().as_bool(),
is_ok: v.pop().unwrap().as_bool(),
is_top: v.pop().unwrap().as_bool(),
g_bio: v.pop().unwrap().as_string(),
g_name: v.pop().unwrap().as_string(),
g_addr: PeerAddr::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()),
@ -287,7 +257,7 @@ impl GroupChat { @@ -287,7 +257,7 @@ impl GroupChat {
/// use in rpc when load account friends.
pub fn all(db: &DStorage) -> Result<Vec<GroupChat>> {
let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_deleted = false ORDER BY last_datetime DESC")?;
let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_ok, is_need_agree, is_closed, key, datetime FROM groups WHERE is_deleted = false")?;
let mut groups = vec![];
for values in matrix {
groups.push(GroupChat::from_values(values, false));
@ -297,7 +267,7 @@ impl GroupChat { @@ -297,7 +267,7 @@ impl GroupChat {
/// use in rpc when load account groups.
pub fn all_ok(db: &DStorage) -> Result<Vec<GroupChat>> {
let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_closed = false ORDER BY last_datetime DESC")?;
let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_ok, is_need_agree, is_closed, key, datetime FROM groups WHERE is_closed = false")?;
let mut groups = vec![];
for values in matrix {
groups.push(GroupChat::from_values(values, false));
@ -306,7 +276,7 @@ impl GroupChat { @@ -306,7 +276,7 @@ impl GroupChat {
}
pub fn get(db: &DStorage, gid: &GroupId) -> Result<Option<GroupChat>> {
let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE gcd = '{}' AND is_deleted = false", gid.to_hex());
let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_ok, is_need_agree, is_closed, key, datetime FROM groups WHERE gcd = '{}' AND is_deleted = false", gid.to_hex());
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
let values = matrix.pop().unwrap(); // safe unwrap()
@ -316,7 +286,7 @@ impl GroupChat { @@ -316,7 +286,7 @@ impl GroupChat {
}
pub fn get_id(db: &DStorage, id: &i64) -> Result<Option<GroupChat>> {
let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE id = {} AND is_deleted = false", id);
let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_ok, is_need_agree, is_closed, key, datetime FROM groups WHERE id = {} AND is_deleted = false", id);
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
let values = matrix.pop().unwrap(); // safe unwrap()
@ -326,7 +296,7 @@ impl GroupChat { @@ -326,7 +296,7 @@ impl GroupChat {
}
pub fn insert(&mut self, db: &DStorage) -> Result<()> {
let sql = format!("INSERT INTO groups (height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime, is_deleted) VALUES ({}, '{}', '{}', {}, '{}', '{}', '{}', {}, {}, {}, {}, '{}', {}, '{}', {}, {}, false)",
let sql = format!("INSERT INTO groups (height, owner, gcd, gtype, addr, name, bio, is_ok, is_need_agree, is_closed, key, datetime, is_deleted) VALUES ({}, '{}', '{}', {}, '{}', '{}', '{}', {}, {}, {}, '{}', {}, false)",
self.height,
self.owner.to_hex(),
self.g_id.to_hex(),
@ -334,14 +304,10 @@ impl GroupChat { @@ -334,14 +304,10 @@ impl GroupChat {
self.g_addr.to_hex(),
self.g_name,
self.g_bio,
if self.is_top { 1 } else { 0 },
if self.is_ok { 1 } else { 0 },
if self.is_need_agree { 1 } else { 0 },
if self.is_closed { 1 } else { 0 },
self.key.to_hex(),
self.last_datetime,
self.last_content,
if self.last_readed { 1 } else { 0 },
self.datetime,
);
let id = db.insert(&sql)?;
@ -359,29 +325,6 @@ impl GroupChat { @@ -359,29 +325,6 @@ impl GroupChat {
let sql = format!("UPDATE groups SET height={} WHERE id = {}", height, id,);
db.update(&sql)
}
pub fn update_last_message(
db: &DStorage,
id: i64,
msg: &Message,
read: bool,
height: i64,
) -> Result<usize> {
let sql = format!(
"UPDATE groups SET height={}, last_datetime={}, last_content='{}', last_readed={} WHERE id = {}",
height,
msg.datetime,
msg.content,
if read { 1 } else { 0 },
id,
);
db.update(&sql)
}
pub fn readed(db: &DStorage, id: i64) -> Result<usize> {
let sql = format!("UPDATE groups SET last_readed=1 WHERE id = {}", id);
db.update(&sql)
}
}
/// Group Join Request model. include my requests and other requests.
@ -397,6 +340,7 @@ pub(crate) struct Request { @@ -397,6 +340,7 @@ pub(crate) struct Request {
is_ok: bool,
is_over: bool,
datetime: i64,
is_deleted: bool,
}
impl Request {
@ -418,6 +362,7 @@ impl Request { @@ -418,6 +362,7 @@ impl Request {
key: GroupChatKey(vec![]),
is_ok: false,
is_over: false,
is_deleted: false,
id: 0,
}
}
@ -444,6 +389,7 @@ impl Request { @@ -444,6 +389,7 @@ impl Request {
key,
is_ok: false,
is_over: false,
is_deleted: false,
fid: 0,
id: 0,
}
@ -463,6 +409,42 @@ impl Request { @@ -463,6 +409,42 @@ impl Request {
])
}
fn from_values(mut v: Vec<DsValue>, contains_deleted: bool) -> Self {
let is_deleted = if contains_deleted {
v.pop().unwrap().as_bool()
} else {
false
};
Self {
is_deleted,
key: GroupChatKey(vec![]),
datetime: v.pop().unwrap().as_i64(),
is_over: v.pop().unwrap().as_bool(),
is_ok: v.pop().unwrap().as_bool(),
remark: v.pop().unwrap().as_string(),
name: v.pop().unwrap().as_string(),
addr: PeerAddr::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()),
gid: GroupId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()),
fid: v.pop().unwrap().as_i64(),
id: v.pop().unwrap().as_i64(),
}
}
pub fn list(db: &DStorage, is_all: bool) -> Result<Vec<Request>> {
let sql = if is_all {
format!("SELECT id, fid, gid, addr, name, remark, is_ok, is_over, datetime FROM requests WHERE is_deleted = false")
} else {
format!("SELECT id, fid, gid, addr, name, remark, is_ok, is_over, datetime FROM requests WHERE is_deleted = false AND is_over = 0")
};
let matrix = db.query(&sql)?;
let mut requests = vec![];
for values in matrix {
requests.push(Request::from_values(values, false));
}
Ok(requests)
}
pub fn insert(&mut self, db: &DStorage) -> Result<()> {
let sql = format!("INSERT INTO requests (fid, gid, addr, name, remark, key, is_ok, is_over, datetime, is_deleted) VALUES ({}, '{}', '{}', '{}', '{}', '{}', {}, {}, {}, false)",
self.fid,
@ -826,6 +808,8 @@ pub(super) fn from_network_message( @@ -826,6 +808,8 @@ pub(super) fn from_network_message(
let mut msg = Message::new_with_time(height, gdid, mdid, is_me, m_type, raw, datetime);
msg.insert(&db)?;
GroupChat::update_last_message(&db, gdid, &msg, false, height)?;
// TODO SESSION UPDATE.
Ok(msg)
}

44
src/apps/group_chat/rpc.rs

@ -2,7 +2,7 @@ use std::sync::Arc; @@ -2,7 +2,7 @@ use std::sync::Arc;
use tdn::types::{
group::GroupId,
message::SendType,
primitive::{new_io_error, HandleResult, PeerAddr},
primitive::{HandleResult, PeerAddr},
rpc::{json, rpc_response, RpcHandler, RpcParam},
};
use tdn_did::Proof;
@ -97,6 +97,16 @@ fn group_list(groups: Vec<GroupChat>) -> RpcParam { @@ -97,6 +97,16 @@ fn group_list(groups: Vec<GroupChat>) -> RpcParam {
json!(results)
}
#[inline]
fn request_list(requests: Vec<Request>) -> RpcParam {
let mut results = vec![];
for request in requests {
results.push(request.to_rpc());
}
json!(results)
}
#[inline]
fn detail_list(members: Vec<Member>, messages: Vec<Message>) -> RpcParam {
let mut member_results = vec![];
@ -122,16 +132,17 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -122,16 +132,17 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
|gid: GroupId, _params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let layer_lock = state.layer.read().await;
let db = group_chat_db(&layer_lock.base, &gid)?;
let mut groups = GroupChat::all(&db)?;
drop(db);
let gids: Vec<&GroupId> = groups.iter().map(|g| &g.g_id).collect();
let onlines = layer_lock.merge_online(&gid, gids)?;
for (index, online) in onlines.iter().enumerate() {
groups[index].online = *online;
}
Ok(HandleResult::rpc(group_list(GroupChat::all(&db)?)))
},
);
Ok(HandleResult::rpc(group_list(groups)))
handler.add_method(
"group-chat-request-list",
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let is_all = params[0].as_bool()?;
let layer_lock = state.layer.read().await;
let db = group_chat_db(&layer_lock.base, &gid)?;
Ok(HandleResult::rpc(request_list(Request::list(&db, is_all)?)))
},
);
@ -266,17 +277,4 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { @@ -266,17 +277,4 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
Ok(results)
},
);
handler.add_method(
"group-chat-readed",
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let fid = params[0].as_i64()?;
let db = group_chat_db(state.layer.read().await.base(), &gid)?;
GroupChat::readed(&db, fid)?;
drop(db);
Ok(HandleResult::new())
},
);
}

1
src/daemon.rs

@ -14,6 +14,7 @@ mod migrate; @@ -14,6 +14,7 @@ mod migrate;
mod primitives;
mod rpc;
mod server;
mod session;
mod storage;
mod utils;

83
src/event.rs

@ -26,7 +26,7 @@ use crate::apps::chat::{Friend, Message, NetworkMessage, Request}; @@ -26,7 +26,7 @@ use crate::apps::chat::{Friend, Message, NetworkMessage, Request};
use crate::apps::file::{FileId, FileType};
use crate::rpc;
use crate::storage::{
account_db, consensus_db, delete_avatar_sync, read_avatar_sync, session_db, write_avatar_sync,
account_db, chat_db, consensus_db, delete_avatar_sync, read_avatar_sync, write_avatar_sync,
};
/// Event that will update data.
@ -46,8 +46,8 @@ pub(crate) enum InnerEvent { @@ -46,8 +46,8 @@ pub(crate) enum InnerEvent {
/// params: f_gid, addr, name, avatar. (TODO addrs as list to store. keep others device)
SessionFriendInfo(GroupId, PeerAddr, String, Vec<u8>),
/// Session's friend update by me.
/// params: f_gid, is_top, remark
SessionFriendUpdate(GroupId, bool, String),
/// params: f_gid, remark
SessionFriendUpdate(GroupId, String),
/// Session's friend close.
/// params: f_gid.
SessionFriendClose(GroupId),
@ -100,7 +100,7 @@ pub(crate) enum SyncEvent { @@ -100,7 +100,7 @@ pub(crate) enum SyncEvent {
bool,
),
RequestHad(EventId, GroupId),
/// eid, friend_gid, addr, name, avatar, remark, is_top, is_closed, is_deleted
/// eid, friend_gid, addr, name, avatar, remark, is_closed, is_deleted
Friend(
EventId,
GroupId,
@ -110,7 +110,6 @@ pub(crate) enum SyncEvent { @@ -110,7 +110,6 @@ pub(crate) enum SyncEvent {
String,
bool,
bool,
bool,
),
FriendHad(EventId, GroupId),
/// eid, friend_gid, msg_id, is_me, message.
@ -250,7 +249,7 @@ impl InnerEvent { @@ -250,7 +249,7 @@ impl InnerEvent {
(ACCOUNT_TABLE_PATH, 0)
}
InnerEvent::SessionRequestCreate(is_me, remote, remark) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
// check if exist request.
if Friend::get(&db, &remote.id)?.is_some() {
return Ok(());
@ -270,7 +269,7 @@ impl InnerEvent { @@ -270,7 +269,7 @@ impl InnerEvent {
(REQUEST_TABLE_PATH, request.id)
}
InnerEvent::SessionRequestHandle(rgid, is_ok, avatar) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if Friend::get(&db, &rgid)?.is_some() {
return Ok(());
}
@ -297,7 +296,7 @@ impl InnerEvent { @@ -297,7 +296,7 @@ impl InnerEvent {
}
}
InnerEvent::SessionRequestDelete(rgid) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(request) = Request::get(&db, &rgid)? {
let rid = request.id;
request.delete(&db)?;
@ -312,7 +311,7 @@ impl InnerEvent { @@ -312,7 +311,7 @@ impl InnerEvent {
}
}
InnerEvent::SessionMessageCreate(rgid, is_me, hash, m) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if Message::exist(&db, &hash)? {
return Ok(());
}
@ -342,7 +341,7 @@ impl InnerEvent { @@ -342,7 +341,7 @@ impl InnerEvent {
}
}
InnerEvent::SessionMessageDelete(hash) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(m) = Message::get_it(&db, &hash)? {
m.delete(&db)?;
results.rpcs.push(chat_rpc::message_delete(gid, m.id));
@ -352,7 +351,7 @@ impl InnerEvent { @@ -352,7 +351,7 @@ impl InnerEvent {
}
}
InnerEvent::SessionFriendInfo(rgid, raddr, rname, ravatar) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(mut f) = Friend::get_it(&db, &rgid)? {
f.addr = raddr;
f.name = rname;
@ -366,22 +365,21 @@ impl InnerEvent { @@ -366,22 +365,21 @@ impl InnerEvent {
return Ok(());
}
}
InnerEvent::SessionFriendUpdate(rgid, is_top, remark) => {
let db = session_db(group.base(), &gid)?;
InnerEvent::SessionFriendUpdate(rgid, remark) => {
let db = chat_db(group.base(), &gid)?;
if let Some(mut f) = Friend::get_it(&db, &rgid)? {
f.is_top = is_top;
f.remark = remark;
f.me_update(&db)?;
results
.rpcs
.push(chat_rpc::friend_update(gid, f.id, is_top, &f.remark));
.push(chat_rpc::friend_update(gid, f.id, &f.remark));
(FRIEND_TABLE_PATH, f.id)
} else {
return Ok(());
}
}
InnerEvent::SessionFriendClose(rgid) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(f) = Friend::get_it(&db, &rgid)? {
f.close(&db)?;
results.rpcs.push(chat_rpc::friend_close(gid, f.id));
@ -410,7 +408,7 @@ impl InnerEvent { @@ -410,7 +408,7 @@ impl InnerEvent {
}
}
InnerEvent::SessionFriendDelete(rgid) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(f) = Friend::get_it(&db, &rgid)? {
f.delete(&db)?;
results.rpcs.push(chat_rpc::friend_delete(gid, f.id));
@ -487,7 +485,7 @@ impl StatusEvent { @@ -487,7 +485,7 @@ impl StatusEvent {
) -> Result<()> {
match self {
StatusEvent::SessionFriendOnline(rgid) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(f) = Friend::get_it(&db, &rgid)? {
results
.rpcs
@ -505,7 +503,7 @@ impl StatusEvent { @@ -505,7 +503,7 @@ impl StatusEvent {
}
}
StatusEvent::SessionFriendOffline(rgid) => {
let db = session_db(group.base(), &gid)?;
let db = chat_db(group.base(), &gid)?;
if let Some(f) = Friend::get_it(&db, &rgid)? {
let layer_lock = layer.clone();
let rgid = f.gid;
@ -574,7 +572,7 @@ impl SyncEvent { @@ -574,7 +572,7 @@ impl SyncEvent {
events.push(SyncEvent::Account(hash, name, avatar));
}
REQUEST_TABLE_PATH => {
let db = session_db(base, gid)?;
let db = chat_db(base, gid)?;
let event = if let Some(request) = Request::get_id(&db, row)? {
if pre_keys.contains(&(path, row)) {
events.push(SyncEvent::RequestHad(hash, request.gid));
@ -609,7 +607,7 @@ impl SyncEvent { @@ -609,7 +607,7 @@ impl SyncEvent {
events.push(event);
}
FRIEND_TABLE_PATH => {
let db = session_db(base, gid)?;
let db = chat_db(base, gid)?;
let event = if let Some(friend) = Friend::get_id(&db, row)? {
if pre_keys.contains(&(path, row)) {
events.push(SyncEvent::FriendHad(hash, friend.gid));
@ -631,7 +629,6 @@ impl SyncEvent { @@ -631,7 +629,6 @@ impl SyncEvent {
friend.name,
avatar,
friend.remark,
friend.is_top,
friend.is_closed,
friend.is_deleted,
)
@ -642,7 +639,7 @@ impl SyncEvent { @@ -642,7 +639,7 @@ impl SyncEvent {
events.push(event);
}
MESSAGE_TABLE_PATH => {
let db = session_db(base, gid)?;
let db = chat_db(base, gid)?;
let event = if let Some(msg) = Message::get_id(&db, row)? {
let fgid = if let Some(f) = Friend::get_id(&db, msg.fid)? {
f.gid
@ -746,11 +743,11 @@ impl SyncEvent { @@ -746,11 +743,11 @@ impl SyncEvent {
is_over,
is_delete,
) => {
let session_db = session_db(&base, &gid)?;
let request = if let Some(mut req) = Request::get(&session_db, &rgid)? {
let chat_db = chat_db(&base, &gid)?;
let request = if let Some(mut req) = Request::get(&chat_db, &rgid)? {
if is_delete {
req.is_deleted = true;
if Friend::get(&session_db, &rgid)?.is_none() {
if Friend::get(&chat_db, &rgid)?.is_none() {
delete_avatar_sync(&base, &gid, &rgid)?;
}
results.rpcs.push(chat_rpc::request_delete(gid, req.id));
@ -758,7 +755,7 @@ impl SyncEvent { @@ -758,7 +755,7 @@ impl SyncEvent {
req.is_ok = is_ok;
req.is_over = is_over;
req.update(&session_db)?;
req.update(&chat_db)?;
req
} else {
let mut request = Request::new(rgid, raddr, rname, remark, is_me, true);
@ -767,12 +764,12 @@ impl SyncEvent { @@ -767,12 +764,12 @@ impl SyncEvent {
request.is_deleted = is_delete;
// save to db.
request.insert(&session_db)?;
request.insert(&chat_db)?;
let rid = request.id;
results.rpcs.push(chat_rpc::request_create(gid, &request));
if is_delete {
if Friend::get(&session_db, &rgid)?.is_none() {
if Friend::get(&chat_db, &rgid)?.is_none() {
delete_avatar_sync(&base, &gid, &rgid)?;
}
results.rpcs.push(chat_rpc::request_delete(gid, rid));
@ -786,20 +783,20 @@ impl SyncEvent { @@ -786,20 +783,20 @@ impl SyncEvent {
if avatar.len() > 0 {
write_avatar_sync(&base, &gid, &request.gid, avatar)?;
}
let friend = Friend::from_request(&session_db, request)?;
let friend = Friend::from_request(&chat_db, request)?;
results
.rpcs
.push(chat_rpc::request_agree(gid, rid, &friend));
} else {
results.rpcs.push(chat_rpc::request_reject(gid, rid));
}
session_db.close()?;
chat_db.close()?;
(eid, REQUEST_TABLE_PATH, rid)
}
SyncEvent::RequestHad(eid, rgid) => {
let session_db = session_db(&base, &gid)?;
let id = if let Some(req) = Request::get(&session_db, &rgid)? {
let chat_db = chat_db(&base, &gid)?;
let id = if let Some(req) = Request::get(&chat_db, &rgid)? {
req.id
} else {
-1
@ -813,19 +810,17 @@ impl SyncEvent { @@ -813,19 +810,17 @@ impl SyncEvent {
fname,
avatar,
remark,
is_top,
is_closed,
is_deleted,
) => {
let session_db = session_db(&base, &gid)?;
let id = if let Some(mut friend) = Friend::get(&session_db, &fgid)? {
let chat_db = chat_db(&base, &gid)?;
let id = if let Some(mut friend) = Friend::get(&chat_db, &fgid)? {
friend.addr = faddr;
friend.name = fname;
friend.remark = remark;
friend.is_top = is_top;
friend.is_closed = is_closed;
friend.is_deleted = is_deleted;
friend.update(&session_db)?;
friend.update(&chat_db)?;
if !is_deleted && avatar.len() > 0 {
write_avatar_sync(&base, &gid, &friend.gid, avatar)?;
@ -865,8 +860,8 @@ impl SyncEvent { @@ -865,8 +860,8 @@ impl SyncEvent {
(eid, FRIEND_TABLE_PATH, id)
}
SyncEvent::FriendHad(eid, fgid) => {
let session_db = session_db(&base, &gid)?;
let id = if let Some(friend) = Friend::get(&session_db, &fgid)? {
let chat_db = chat_db(&base, &gid)?;
let id = if let Some(friend) = Friend::get(&chat_db, &fgid)? {
friend.id
} else {
-1
@ -874,13 +869,13 @@ impl SyncEvent { @@ -874,13 +869,13 @@ impl SyncEvent {
(eid, FRIEND_TABLE_PATH, id)
}
SyncEvent::Message(eid, fgid, meid, is_me, m) => {
let session_db = session_db(&base, &gid)?;
if Message::exist(&session_db, &meid)? {
let chat_db = chat_db(&base, &gid)?;
if Message::exist(&chat_db, &meid)? {
continue;
}
let id = if let Some(f) = Friend::get_it(&session_db, &fgid)? {
let msg = m.handle(is_me, gid, &base, &session_db, f.id, eid)?;
let id = if let Some(f) = Friend::get_it(&chat_db, &fgid)? {
let msg = m.handle(is_me, gid, &base, &chat_db, f.id, eid)?;
results.rpcs.push(chat_rpc::message_create(gid, &msg));
msg.id
} else {

35
src/layer.rs

@ -10,12 +10,12 @@ use tdn::{ @@ -10,12 +10,12 @@ use tdn::{
primitive::{new_io_error, PeerAddr, Result},
},
};
use tdn_did::user::User;
use crate::apps::chat::{chat_conn, Friend};
use crate::apps::group_chat::{group_chat_conn, GroupChat, GROUP_ID};
use crate::apps::chat::chat_conn;
use crate::apps::group_chat::{group_chat_conn, GROUP_ID};
use crate::group::Group;
use crate::storage::{group_chat_db, session_db, write_avatar_sync};
use crate::session::{Session, SessionType};
use crate::storage::session_db;
/// ESSE app's BaseLayerEvent.
/// EVERY LAYER APP MUST EQUAL THE FIRST THREE FIELDS.
@ -123,22 +123,23 @@ impl Layer { @@ -123,22 +123,23 @@ impl Layer {
for mgid in self.runnings.keys() {
let mut vecs = vec![];
// load friend chat.
let db = session_db(&self.base, mgid)?;
for friend in Friend::all_ok(&db)? {
let proof = group_lock.prove_addr(mgid, &friend.addr).unwrap();
vecs.push((friend.gid, chat_conn(proof, friend.addr)));
}
let db = session_db(&self.base, &mgid)?;
let sessions = Session::list(&db)?;
drop(db);
// load group chat.
let db = group_chat_db(&self.base, mgid)?;
let groups = GroupChat::all_ok(&db)?;
for g in groups {
let proof = group_lock.prove_addr(mgid, &g.g_addr)?;
vecs.push((GROUP_ID, group_chat_conn(proof, g.g_addr, g.g_id)));
for s in sessions {
match s.s_type {
SessionType::Chat => {
let proof = group_lock.prove_addr(mgid, &s.addr)?;
vecs.push((s.gid, chat_conn(proof, s.addr)));
}
SessionType::Group => {
let proof = group_lock.prove_addr(mgid, &s.addr)?;
vecs.push((GROUP_ID, group_chat_conn(proof, s.addr, s.gid)));
}
_ => {}
}
}
drop(db);
conns.insert(*mgid, vecs);
}

1
src/lib.rs

@ -15,6 +15,7 @@ mod migrate; @@ -15,6 +15,7 @@ mod migrate;
mod primitives;
mod rpc;
mod server;
mod session;
mod storage;
mod utils;

20
src/migrate.rs

@ -4,12 +4,14 @@ use tdn_storage::local::DStorage; @@ -4,12 +4,14 @@ use tdn_storage::local::DStorage;
pub mod consensus;
mod account;
mod chat;
mod file;
mod group_chat;
mod service;
mod session;
use account::ACCOUNT_VERSIONS;
use chat::CHAT_VERSIONS;
use consensus::CONSENSUS_VERSIONS;
use file::FILE_VERSIONS;
use group_chat::GROUP_CHAT_VERSIONS;
@ -27,6 +29,9 @@ pub(crate) const CONSENSUS_DB: &'static str = "consensus.db"; @@ -27,6 +29,9 @@ pub(crate) const CONSENSUS_DB: &'static str = "consensus.db";
/// Account's session database name
pub(crate) const SESSION_DB: &'static str = "session.db";
/// Account's chat database name
pub(crate) const CHAT_DB: &'static str = "chat.db";
/// Account's consensus database name
pub(crate) const FILE_DB: &'static str = "file.db";
@ -105,6 +110,7 @@ pub(crate) fn main_migrate(path: &PathBuf) -> std::io::Result<()> { @@ -105,6 +110,7 @@ pub(crate) fn main_migrate(path: &PathBuf) -> std::io::Result<()> {
SERVICE_DB => SERVICE_VERSIONS.as_ref(),
ASSISTANT_DB => ASSISTANT_VERSIONS.as_ref(),
GROUP_CHAT_DB => GROUP_CHAT_VERSIONS.as_ref(),
CHAT_DB => CHAT_VERSIONS.as_ref(),
_ => {
continue;
}
@ -182,6 +188,12 @@ pub(crate) fn main_migrate(path: &PathBuf) -> std::io::Result<()> { @@ -182,6 +188,12 @@ pub(crate) fn main_migrate(path: &PathBuf) -> std::io::Result<()> {
GROUP_CHAT_DB,
))?;
db.update(&format!(
"UPDATE migrates SET version = {} where db_name = '{}'",
CHAT_VERSIONS.len(),
CHAT_DB,
))?;
db.close()?;
}
@ -235,5 +247,13 @@ pub(crate) fn account_init_migrate(path: &PathBuf) -> std::io::Result<()> { @@ -235,5 +247,13 @@ pub(crate) fn account_init_migrate(path: &PathBuf) -> std::io::Result<()> {
for i in &GROUP_CHAT_VERSIONS {
db.execute(i)?;
}
db.close()?;
let mut db_path = path.clone();
db_path.push(CHAT_DB);
let db = DStorage::open(db_path)?;
for i in &CHAT_VERSIONS {
db.execute(i)?;
}
db.close()
}

11
src/migrate/account.rs

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
#[rustfmt::skip]
pub(super) const ACCOUNT_VERSIONS: [&str; 8] = [
pub(super) const ACCOUNT_VERSIONS: [&str; 9] = [
"CREATE TABLE IF NOT EXISTS accounts(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
gid TEXT NOT NULL,
@ -14,10 +14,11 @@ pub(super) const ACCOUNT_VERSIONS: [&str; 8] = [ @@ -14,10 +14,11 @@ pub(super) const ACCOUNT_VERSIONS: [&str; 8] = [
"CREATE TABLE IF NOT EXISTS migrates(
db_name TEXT NOT NULL,
version INTEGER NOT NULL);",
"INSERT INTO migrates (db_name, version) values ('account.db', 1)",
"INSERT INTO migrates (db_name, version) values ('consensus.db', 9)",
"INSERT INTO migrates (db_name, version) values ('session.db', 3)",
"INSERT INTO migrates (db_name, version) values ('file.db', 1)",
"INSERT INTO migrates (db_name, version) values ('account.db', 0)",
"INSERT INTO migrates (db_name, version) values ('consensus.db', 0)",
"INSERT INTO migrates (db_name, version) values ('session.db', 0)",
"INSERT INTO migrates (db_name, version) values ('file.db', 0)",
"INSERT INTO migrates (db_name, version) values ('assistant.db', 0)",
"INSERT INTO migrates (db_name, version) values ('group_chat.db', 0)",
"INSERT INTO migrates (db_name, version) values ('chat.db', 0)",
];

34
src/migrate/chat.rs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
#[rustfmt::skip]
pub(super) const CHAT_VERSIONS: [&str; 3] = [
"CREATE TABLE IF NOT EXISTS friends(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
gid TEXT NOT NULL,
addr TEXT NOT NULL,
name TEXT NOT NULL,
remark TEXT,
is_closed INTEGER NOT NULL,
datetime INTEGER NOT NULL,
is_deleted INTEGER NOT NULL);",
"CREATE TABLE IF NOT EXISTS requests(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
gid TEXT NOT NULL,
addr TEXT NOT NULL,
name TEXT,
remark TEXT,
is_me INTEGER NOT NULL,
is_ok INTEGER NOT NULL,
is_over INTEGER NOT NULL,
is_delivery INTEGER NOT NULL,
datetime INTEGER NOT NULL,
is_deleted INTEGER NOT NULL);",
"CREATE TABLE IF NOT EXISTS messages(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
hash TEXT NOT NULL,
fid INTEGER NOT NULL,
is_me INTEGER NOT NULL,
m_type INTEGER NOT NULL,
content TEXT NOT NULL,
is_delivery INTEGER NOT NULL,
datetime INTEGER NOT NULL,
is_deleted INTEGER NOT NULL);",
];

4
src/migrate/group_chat.rs

@ -9,14 +9,10 @@ pub(super) const GROUP_CHAT_VERSIONS: [&str; 4] = [ @@ -9,14 +9,10 @@ pub(super) const GROUP_CHAT_VERSIONS: [&str; 4] = [
addr TEXT NOT NULL,
name TEXT NOT NULL,
bio TEXT NOT NULL,
is_top INTEGER NOT NULL,
is_ok INTEGER NOT NULL,
is_need_agree INTEGER NOT NULL,
is_closed INTEGER NOT NULL,
key TEXT NOT NULL,
last_datetime INTEGER,
last_content TEXT,
last_readed INTEGER,
datetime INTEGER NOT NULL,
is_deleted INTEGER NOT NULL);",
"CREATE TABLE IF NOT EXISTS requests(

37
src/migrate/session.rs

@ -1,37 +1,16 @@ @@ -1,37 +1,16 @@
#[rustfmt::skip]
pub(super) const SESSION_VERSIONS: [&str; 3] = [
"CREATE TABLE IF NOT EXISTS friends(
"CREATE TABLE IF NOT EXISTS sessions(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
fid INTEGER NOT NULL,
gid TEXT NOT NULL,
addr TEXT NOT NULL,
s_type INTEGER NOT NULL,
name TEXT NOT NULL,
remark TEXT,
is_top INTEGER NOT NULL,
is_closed INTEGER NOT NULL,
last_message_datetime INTEGER,
last_message_content TEXT,
last_message_readed INTEGER,
is_deleted INTEGER NOT NULL);",
"CREATE TABLE IF NOT EXISTS requests(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
gid TEXT NOT NULL,
addr TEXT NOT NULL,
name TEXT,
remark TEXT,
is_me INTEGER NOT NULL,
is_ok INTEGER NOT NULL,
is_over INTEGER NOT NULL,
is_delivery INTEGER NOT NULL,
datetime INTEGER NOT NULL,
is_deleted INTEGER NOT NULL);",
"CREATE TABLE IF NOT EXISTS messages(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
hash TEXT NOT NULL,
fid INTEGER NOT NULL,
is_me INTEGER NOT NULL,
m_type INTEGER NOT NULL,
content TEXT NOT NULL,
is_delivery INTEGER NOT NULL,
datetime INTEGER NOT NULL,
is_deleted 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.
];

95
src/rpc.rs

@ -13,12 +13,13 @@ use tdn::{ @@ -13,12 +13,13 @@ use tdn::{
};
use crate::apps::app_rpc_inject;
use crate::apps::chat::{chat_conn, Friend};
use crate::apps::group_chat::{add_layer, group_chat_conn, GroupChat};
use crate::apps::chat::chat_conn;
use crate::apps::group_chat::{add_layer, group_chat_conn};
use crate::event::InnerEvent;
use crate::group::Group;
use crate::layer::{Layer, LayerEvent};
use crate::storage::{group_chat_db, session_db};
use crate::session::{Session, SessionType};
use crate::storage::session_db;
pub(crate) fn init_rpc(
addr: PeerAddr,
@ -73,6 +74,48 @@ pub(crate) fn account_update(mgid: GroupId, name: &str, avatar: String) -> RpcPa @@ -73,6 +74,48 @@ pub(crate) fn account_update(mgid: GroupId, name: &str, avatar: String) -> RpcPa
)
}
#[inline]
pub(crate) fn session_create(mgid: GroupId, session: &Session) -> RpcParam {
rpc_response(0, "session-create", session.to_rpc(), mgid)
}
#[inline]
pub(crate) fn session_last(
mgid: GroupId,
id: &i64,
time: &i64,
content: &str,
readed: bool,
) -> RpcParam {
rpc_response(0, "session-last", json!([id, time, content, readed]), mgid)
}
#[inline]
pub(crate) fn session_update(
mgid: GroupId,
id: &i64,
addr: &PeerAddr,
name: &str,
is_top: bool,
online: bool,
) -> RpcParam {
rpc_response(
0,
"session-update",
json!([id, addr.to_hex(), name, is_top, online]),
mgid,
)
}
#[inline]
fn session_list(sessions: Vec<Session>) -> RpcParam {
let mut results = vec![];
for session in sessions {
results.push(session.to_rpc());
}
json!(results)
}
#[inline]
pub(crate) async fn sleep_waiting_close_stable(
sender: Sender<SendMessage>,
@ -364,27 +407,29 @@ fn new_rpc_handler( @@ -364,27 +407,29 @@ fn new_rpc_handler(
let group_lock = state.group.read().await;
let db = session_db(group_lock.base(), &gid)?;
let friends = Friend::all_ok(&db)?;
let sessions = Session::list(&db)?;
drop(db);
for f in friends {
let proof = group_lock.prove_addr(&gid, &f.addr)?;
results.layers.push((gid, f.gid, chat_conn(proof, f.addr)));
}
let db = group_chat_db(group_lock.base(), &gid)?;
let groups = GroupChat::all_ok(&db)?;
for g in groups {
let proof = group_lock.prove_addr(&gid, &g.g_addr)?;
add_layer(&mut results, gid, group_chat_conn(proof, g.g_addr, g.g_id));
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));
}
_ => {}
}
}
drop(db);
drop(group_lock);
let devices = state.group.read().await.distribute_conns(&gid);
let devices = group_lock.distribute_conns(&gid);
for device in devices {
results.groups.push((gid, device));
}
drop(group_lock);
debug!("Account Online: {}.", gid.to_hex());
Ok(results)
@ -421,5 +466,23 @@ fn new_rpc_handler( @@ -421,5 +466,23 @@ 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)?;
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;
}
Ok(HandleResult::rpc(session_list(sessions)))
},
);
handler
}

171
src/session.rs

@ -0,0 +1,171 @@ @@ -0,0 +1,171 @@
use tdn::types::{
group::GroupId,
primitive::{new_io_error, PeerAddr, Result},
rpc::{json, RpcParam},
};
use tdn_storage::local::{DStorage, DsValue};
pub(crate) enum SessionType {
Chat,
Group,
Files,
Device,
Assistant,
Domain,
Service,
}
impl SessionType {
fn to_int(&self) -> i64 {
match self {
SessionType::Chat => 0,
SessionType::Group => 1,
SessionType::Files => 2,
SessionType::Device => 3,
SessionType::Assistant => 4,
SessionType::Domain => 5,
SessionType::Service => 6,
}
}
fn from_int(i: i64) -> Self {
match i {
0 => SessionType::Chat,
1 => SessionType::Group,
2 => SessionType::Files,
3 => SessionType::Device,
4 => SessionType::Assistant,
5 => SessionType::Domain,
6 => SessionType::Service,
_ => SessionType::Chat,
}
}
}
pub(crate) struct Session {
id: i64,
fid: i64,
pub gid: GroupId,
pub addr: PeerAddr,
pub s_type: SessionType,
name: String,
is_top: bool,
last_datetime: i64,
last_content: String,
last_readed: bool,
pub online: bool,
}
impl Session {
pub fn new(
fid: i64,
gid: GroupId,
addr: PeerAddr,
s_type: SessionType,
name: String,
datetime: i64,
) -> Self {
Self {
fid,
gid,
addr,
s_type,
name,
id: 0,
is_top: false,
last_datetime: datetime,
last_content: "".to_owned(),
last_readed: true,
online: false,
}
}
pub fn to_rpc(&self) -> RpcParam {
json!([
self.id,
self.fid,
self.gid.to_hex(),
self.addr.to_hex(),
self.s_type.to_int(),
self.name,
self.is_top,
self.last_datetime,
self.last_content,
self.last_readed,
self.online
])
}
fn from_values(mut v: Vec<DsValue>) -> Self {
Self {
last_readed: v.pop().unwrap().as_bool(),
last_content: v.pop().unwrap().as_string(),
last_datetime: v.pop().unwrap().as_i64(),
is_top: v.pop().unwrap().as_bool(),
name: v.pop().unwrap().as_string(),
s_type: SessionType::from_int(v.pop().unwrap().as_i64()),
addr: PeerAddr::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerAddr::default()),
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 ({}, '{}', '{}', {}, '{}', {}, {}, '{}', {})",
self.fid,
self.gid.to_hex(),
self.addr.to_hex(),
self.s_type.to_int(),
self.name,
if self.is_top { 1 } else { 0 },
self.last_datetime,
self.last_content,
if self.last_readed { 1 } else { 0 },
);
let id = db.insert(&sql)?;
self.id = id;
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);
let mut matrix = db.query(&sql)?;
if matrix.len() > 0 {
Ok(Session::from_values(matrix.pop().unwrap())) // safe unwrap()
} else {
Err(new_io_error("session missing."))
}
}
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 mut sessions = vec![];
for values in matrix {
sessions.push(Session::from_values(values));
}
Ok(sessions)
}
pub fn top(db: &DStorage, id: &i64, is_top: bool) -> Result<usize> {
db.update(&format!("UPDATE sessions SET is_top = 1 WHERE id = {}", id))
}
pub fn last(
db: &DStorage,
id: &i64,
datetime: &i64,
content: &str,
readed: bool,
) -> Result<usize> {
db.update(&format!("UPDATE sessions SET last_datetime = {}, last_content = '{}', last_readed = {} WHERE id = {}", datetime, content, if readed { 1 } else { 0 }, id))
}
pub fn read(db: &DStorage, id: &i64) -> Result<usize> {
db.update(&format!(
"UPDATE sessions SET last_readed = 1 WHERE id = {}",
id
))
}
}

11
src/storage.rs

@ -2,6 +2,7 @@ use async_fs as fs; @@ -2,6 +2,7 @@ use async_fs as fs;
use image::{load_from_memory, DynamicImage, GenericImageView};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use tdn::types::{
@ -11,7 +12,7 @@ use tdn::types::{ @@ -11,7 +12,7 @@ use tdn::types::{
use tdn_storage::local::DStorage;
use crate::migrate::{
account_init_migrate, ACCOUNT_DB, ASSISTANT_DB, CONSENSUS_DB, FILE_DB, GROUP_CHAT_DB,
account_init_migrate, ACCOUNT_DB, ASSISTANT_DB, CHAT_DB, CONSENSUS_DB, FILE_DB, GROUP_CHAT_DB,
SERVICE_DB, SESSION_DB,
};
@ -327,6 +328,14 @@ pub(crate) fn session_db(base: &PathBuf, gid: &GroupId) -> Result<DStorage> { @@ -327,6 +328,14 @@ pub(crate) fn session_db(base: &PathBuf, gid: &GroupId) -> Result<DStorage> {
DStorage::open(db_path)
}
#[inline]
pub(crate) fn chat_db(base: &PathBuf, gid: &GroupId) -> Result<DStorage> {
let mut db_path = base.clone();
db_path.push(gid.to_hex());
db_path.push(CHAT_DB);
DStorage::open(db_path)
}
#[inline]
pub(crate) fn _file_db(base: &PathBuf, gid: &GroupId) -> Result<DStorage> {
let mut db_path = base.clone();

Loading…
Cancel
Save