diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..16f1e73 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["--cfg", "tokio_unstable"] \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 582361b..025e379 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,9 +34,9 @@ panic = 'abort' anyhow = "1.0" log = "0.4" rand = "0.8" -once_cell = "1.8" +once_cell = "1.9" simplelog = "0.11" -image = "0.23" +image = "0.24" base64 = "0.13" hex = "0.4" sha2 = "0.10" @@ -44,13 +44,14 @@ argon2 = "0.3" blake3 = "1.3" bincode = "1.3" aes-gcm = "0.9" -sysinfo = "0.21" +sysinfo = "0.23" serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["full"] } -web3 = { version = "0.17", default-features = false, features = ["http-tls", "signing"] } -tdn = { version = "0.7", default-features = false, features = ["full"] } +web3 = { version = "0.18", default-features = false, features = ["http-tls", "signing"] } +tdn = { version = "0.7", default-features = false, features = ["std"] } tdn_did = { version = "0.7" } tdn_storage = { git = "https://github.com/cympletech/tdn", branch="main" } +esse_primitives = { version = "0.1", path = "./types/primitives" } chat_types = { version = "0.1", path = "./types/chat" } group_types = { version = "0.1", path = "./types/group" } cloud_types = { version = "0.1", path = "./types/cloud" } @@ -59,6 +60,7 @@ dao_types = { version = "0.1", path = "./types/dao" } data = { version = "0.1", path = "./types/data" } openssl = { version = "0.10", features = ["vendored"] } # Add for cross-compile. +console-subscriber = "0.1" # only use in bin daemon. [target.'cfg(target_os="android")'.dependencies] jni = { version = "0.19", default-features = false } @@ -66,6 +68,8 @@ jni = { version = "0.19", default-features = false } # DEBUG patch. [patch.crates-io] +chamomile = { git = "https://github.com/cympletech/chamomile" } +chamomile_types = { git = "https://github.com/cympletech/chamomile" } tdn = { git = "https://github.com/cympletech/tdn" } tdn_types = { git = "https://github.com/cympletech/tdn" } tdn_did = { git = "https://github.com/cympletech/tdn" } diff --git a/LICENSE-AW b/LICENSE-AW deleted file mode 100644 index 6df32cc..0000000 --- a/LICENSE-AW +++ /dev/null @@ -1,12 +0,0 @@ -Anti-War LICENSE - -Version 0.1, February 2022 - -THIS IS AN EXTENSION OPEN SOURCE LICENSE - -All those who support start a war are banned to -use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software. - -This software only targets the aggressor, -not the victimized party. diff --git a/README.md b/README.md index 98c98af..65e6e8d 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,6 @@ It is recommended to use [rust.sh](./rust.sh) to auto-compile the Rust code This project is licensed under * GNU GENERAL PUBLIC LICENSE, Version 3.0, [LICENSE](LICENSE) - * Anti-War license ([LICENSE-AW](LICENSE-AW) * Any question, please contact: contact@cympletech.com ## Donation diff --git a/lib/account.dart b/lib/account.dart index ac4201f..1408566 100644 --- a/lib/account.dart +++ b/lib/account.dart @@ -124,15 +124,15 @@ extension LanguageExtension on Language { } class Account { - String gid = ''; + String pid = ''; String name = ''; Uint8List? avatar; bool online = false; bool hasNew = false; String pin = ''; - Account(String gid, String name, [String avatar = "", bool online = false]) { - this.gid = gid; + Account(String pid, String name, [String avatar = "", bool online = false]) { + this.pid = pid; this.name = name; this.updateAvatar(avatar); this.online = online; diff --git a/lib/apps/chat/add.dart b/lib/apps/chat/add.dart index 80c312e..687024a 100644 --- a/lib/apps/chat/add.dart +++ b/lib/apps/chat/add.dart @@ -26,9 +26,8 @@ import 'package:esse/apps/domain/models.dart'; class ChatAdd extends StatefulWidget { final String id; - final String addr; final String name; - ChatAdd({Key? key, this.id = '', this.addr = '', this.name = ''}) : super(key: key); + ChatAdd({Key? key, this.id = '', this.name = ''}) : super(key: key); @override _ChatAddState createState() => _ChatAddState(); @@ -42,18 +41,16 @@ class _ChatAddState extends State { void _scanCallback(bool isOk, String app, List params) { Navigator.of(context).pop(); - if (isOk && app == 'add-friend' && params.length == 3) { + if (isOk && app == 'add-friend' && params.length == 2) { setState(() { this._showHome = false; - final avatar = Avatar(name: params[2], width: 100.0, colorSurface: false); - String id = gidParse(params[0].trim()); - String addr = addrParse(params[1]); + final avatar = Avatar(name: params[1], width: 100.0, colorSurface: false); + String id = pidParse(params[0].trim()); this._coreScreen = _InfoScreen( callback: this._sendCallback, id: id, - addr: addr, - name: params[2], + name: params[1], bio: '', avatar: avatar, ); @@ -61,13 +58,12 @@ class _ChatAddState extends State { } } - void _searchCallBack(String id, String addr, String name, String bio, Avatar avatar) { + void _searchCallBack(String id, String name, String bio, Avatar avatar) { setState(() { this._showHome = false; this._coreScreen = _InfoScreen( callback: this._sendCallback, id: id, - addr: addr, name: name, bio: bio, avatar: avatar, @@ -151,7 +147,6 @@ class _ChatAddState extends State { callback: this._sendCallback, name: widget.name, id: widget.id, - addr: widget.addr, bio: '', avatar: avatar, ); @@ -196,9 +191,7 @@ class _ChatAddState extends State { final res = await httpPost('chat-request-list', []); if (res.isOk) { res.params.forEach((param) { - if (param.length == 10) { - this._requests[param[0]] = Request.fromList(param); - } + this._requests[param[0]] = Request.fromList(param); }); setState(() {}); } else { @@ -235,8 +228,7 @@ class _ChatAddState extends State { context, Icons.info, lang.info, - UserInfo(app: 'add-friend', - id: account.gid, name: account.name, addr: Global.addr) + UserInfo(app: 'add-friend', id: account.pid, name: account.name) ), child: Padding( padding: const EdgeInsets.only(right: 10.0), @@ -320,8 +312,7 @@ class _ChatAddState extends State { const SizedBox(height: 10.0), const Divider(height: 1.0, color: Color(0x40ADB0BB)), const SizedBox(height: 10.0), - _infoListTooltip(Icons.person, color.primary, gidText(request.gid), gidPrint(request.gid)), - _infoListTooltip(Icons.location_on, color.primary, addrText(request.addr), addrPrint(request.addr)), + _infoListTooltip(Icons.person, color.primary, pidText(request.pid), pidPrint(request.pid)), _infoList(Icons.turned_in, color.primary, request.remark), _infoList(Icons.access_time_rounded, color.primary, request.time.toString()), const SizedBox(height: 10.0), @@ -415,9 +406,7 @@ class _ChatAddState extends State { InkWell( onTap: () { Navigator.pop(context); - rpc.send('chat-request-create', [ - request.gid, request.addr, request.name, request.remark - ]); + rpc.send('chat-request-create', [request.pid, request.name, request.remark]); setState(() { this._requests.remove(request.id); }); @@ -672,27 +661,23 @@ class _InputScreen extends StatefulWidget { class _InputScreenState extends State<_InputScreen> { TextEditingController userIdEditingController = TextEditingController(); - TextEditingController addrEditingController = TextEditingController(); TextEditingController remarkEditingController = TextEditingController(); TextEditingController nameEditingController = TextEditingController(); FocusNode userIdFocus = FocusNode(); - FocusNode addrFocus = FocusNode(); FocusNode remarkFocus = FocusNode(); send() { - final id = gidParse(userIdEditingController.text.trim()); - final addr = addrParse(addrEditingController.text.trim()); - if (id == '' || addr == '') { + final id = pidParse(userIdEditingController.text.trim()); + if (id == '') { return; } final name = nameEditingController.text.trim(); final remark = remarkEditingController.text.trim(); - rpc.send('chat-request-create', [id, addr, name, remark]); + rpc.send('chat-request-create', [id, name, remark]); setState(() { userIdEditingController.text = ''; - addrEditingController.text = ''; nameEditingController.text = ''; remarkEditingController.text = ''; }); @@ -714,12 +699,6 @@ class _InputScreenState extends State<_InputScreen> { controller: userIdEditingController, focus: userIdFocus), const SizedBox(height: 20.0), - InputText( - icon: Icons.location_on, - text: lang.address + ' (0x00..00)', - controller: addrEditingController, - focus: addrFocus), - const SizedBox(height: 20.0), InputText( icon: Icons.turned_in, text: lang.remark, @@ -735,7 +714,6 @@ class _InputScreenState extends State<_InputScreen> { class _InfoScreen extends StatelessWidget { final Function callback; final String id; - final String addr; final String name; final String bio; final Avatar avatar; @@ -744,7 +722,6 @@ class _InfoScreen extends StatelessWidget { Key? key, required this.callback, required this.id, - required this.addr, required this.name, required this.bio, required this.avatar, @@ -773,19 +750,10 @@ class _InfoScreen extends StatelessWidget { ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0), leading: Icon(Icons.person, color: color.primary), - title: Text(gidPrint(this.id), style: TextStyle(fontSize: 16.0)), - trailing: TextButton( - child: Icon(Icons.copy, size: 20.0), - onPressed: () => Clipboard.setData(ClipboardData(text: gidText(this.id))), - ) - ), - ListTile( - contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0), - leading: Icon(Icons.location_on, color: color.primary), - title: Text(addrPrint(this.addr), style: TextStyle(fontSize: 16.0)), + title: Text(pidPrint(this.id), style: TextStyle(fontSize: 16.0)), trailing: TextButton( child: Icon(Icons.copy, size: 20.0), - onPressed: () => Clipboard.setData(ClipboardData(text: addrText(this.addr))), + onPressed: () => Clipboard.setData(ClipboardData(text: pidText(this.id))), ) ), ListTile( @@ -797,7 +765,7 @@ class _InfoScreen extends StatelessWidget { TextButton( child: Text(lang.addFriend, style: TextStyle(fontSize: 20.0)), onPressed: () { - rpc.send('chat-request-create', [this.id, this.addr, this.name, '']); + rpc.send('chat-request-create', [this.id, this.name, '']); this.callback(); } ), diff --git a/lib/apps/chat/detail.dart b/lib/apps/chat/detail.dart index a3664f1..77c81b0 100644 --- a/lib/apps/chat/detail.dart +++ b/lib/apps/chat/detail.dart @@ -26,7 +26,7 @@ class ChatDetail extends StatefulWidget { class _ChatDetailState extends State { bool _loading = false; - Friend _friend = Friend('', '', ''); + Friend _friend = Friend('', ''); Map _messages = {}; @override @@ -83,7 +83,7 @@ class _ChatDetailState extends State { } _send(MessageType mtype, String raw) { - rpc.send('chat-message-create', [_friend.id, _friend.gid, mtype.toInt(), raw]); + rpc.send('chat-message-create', [_friend.id, _friend.pid, mtype.toInt(), raw]); } @override @@ -165,9 +165,8 @@ class _ChatDetailState extends State { lang.friendInfo, UserInfo( app: 'add-friend', - id: _friend.gid, + id: _friend.pid, name: _friend.name, - addr: _friend.addr, title: lang.qrFriend, remark: _friend.remark, ), @@ -207,7 +206,7 @@ class _ChatDetailState extends State { ); } else if (value == 4) { rpc.send('chat-request-create', [ - _friend.gid, _friend.addr, _friend.name, lang.fromContactCard(meName) + _friend.pid, _friend.name, lang.fromContactCard(meName) ]); } else if (value == 5) { showDialog( @@ -264,7 +263,7 @@ class _ChatDetailState extends State { itemCount: recentMessageKeys.length, reverse: true, itemBuilder: (BuildContext context, index) => ChatMessage( - fgid: _friend.gid, + fpid: _friend.pid, name: _friend.name, message: this._messages[recentMessageKeys[index]]!, ) diff --git a/lib/apps/chat/models.dart b/lib/apps/chat/models.dart index 413a6a6..ed87780 100644 --- a/lib/apps/chat/models.dart +++ b/lib/apps/chat/models.dart @@ -8,9 +8,8 @@ import 'package:esse/apps/primitives.dart'; class Friend { int id = 0; - String gid = ''; + String pid = ''; String name = ''; - String addr = ''; String wallet = ''; String remark = ''; bool isClosed = false; @@ -18,10 +17,10 @@ class Friend { bool online = false; // new friend from network - Friend(this.gid, this.name, this.addr); + Friend(this.pid, this.name); Avatar showAvatar({bool needOnline = false, double width = 45.0}) { - final avatar = Global.avatarPath + this.gid + '.png'; + final avatar = Global.avatarPath + this.pid + '.png'; if (needOnline) { return Avatar(width: width, name: this.name, avatarPath: avatar, online: this.online, @@ -34,23 +33,21 @@ class Friend { Friend.fromList(List params) { this.id = params[0]; - this.gid = params[1]; - this.addr = params[2]; - this.name = params[3]; - this.wallet = params[4]; - this.remark = params[5]; - this.isClosed = params[6]; - this.time = RelativeTime.fromInt(params[7]); - if (params.length == 9) { - this.online = params[8]; + this.pid = params[1]; + this.name = params[2]; + this.wallet = params[3]; + this.remark = params[4]; + this.isClosed = params[5]; + this.time = RelativeTime.fromInt(params[6]); + if (params.length == 8) { + this.online = params[7]; } } } class Request { int id = 0; - String gid = ''; - String addr = ''; + String pid = ''; String name = ''; String remark = ''; bool isMe = true; @@ -59,33 +56,32 @@ class Request { bool isDelivery = false; RelativeTime time = RelativeTime(); - Request(this.gid, this.addr, this.name, this.remark); + Request(this.pid, this.name, this.remark); overIt(bool isOk) { this.over = true; this.ok = isOk; } - Friend toFriend(String gid) { - return Friend(gid, this.name, this.addr); + Friend toFriend(String pid) { + return Friend(pid, this.name); } Avatar showAvatar([double width = 45.0]) { - final avatar = Global.avatarPath + this.gid + '.png'; + final avatar = Global.avatarPath + this.pid + '.png'; return Avatar(width: width, name: this.name, avatarPath: avatar); } Request.fromList(List params) { this.id = params[0]; - this.gid = params[1]; - this.addr = params[2]; - this.name = params[3]; - this.remark = params[4]; - this.isMe = params[5]; - this.ok = params[6]; - this.over = params[7]; - this.isDelivery = params[8]; - this.time = RelativeTime.fromInt(params[9]); + this.pid = params[1]; + this.name = params[2]; + this.remark = params[3]; + this.isMe = params[4]; + this.ok = params[5]; + this.over = params[6]; + this.isDelivery = params[7]; + this.time = RelativeTime.fromInt(params[8]); } } diff --git a/lib/apps/device/page.dart b/lib/apps/device/page.dart index 8e324e5..f26d64d 100644 --- a/lib/apps/device/page.dart +++ b/lib/apps/device/page.dart @@ -48,11 +48,11 @@ class _DevicesPageState extends State { )); } - _showQrCode(String name, String id, String addr, String lock, ColorScheme color, lang) async { + _showQrCode(String name, String id, String lock, ColorScheme color, lang) async { final res = await httpPost('account-mnemonic', [lock]); if (res.isOk) { final words = res.params[0]; - final info = json.encode({'app': 'distribute', 'params': [name, gidText(id), addrText(addr), words]}); + final info = json.encode({'app': 'distribute', 'params': [name, pidText(id), words]}); showShadowDialog(context, Icons.qr_code_rounded, lang.deviceQrcode, Column( children: [ @@ -109,7 +109,7 @@ class _DevicesPageState extends State { } Widget deviceWidget(ColorScheme color, Device device, bool isDesktop, double widgetWidth, lang) { - final bool isLocal = device.addr == Global.addr; + final bool isLocal = true; // TODO final String name = isLocal ? (device.name + " (${lang.deviceLocal})") : device.name; return Container( @@ -126,10 +126,6 @@ class _DevicesPageState extends State { ? Icon(Icons.cloud_done_rounded, size: 38.0, color: Color(0xFF6174FF)) : Icon(Icons.cloud_off_rounded, size: 38.0, color: Colors.grey), title: Text(name), - subtitle: Container( - padding: const EdgeInsets.only(top: 8.0), - child: Text(addrPrint(device.addr)) - ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -207,13 +203,12 @@ class _DevicesPageState extends State { Icons.security_rounded, lang.verifyPin, PinWords( - gid: account.gid, + pid: account.pid, callback: (key) async { Navigator.of(context).pop(); _showQrCode( account.name, - account.gid, - Global.addr, + account.pid, key, color, lang, @@ -280,21 +275,22 @@ class DeviceListenPage extends StatefulWidget { class _DeviceListenPageState extends State { Widget percentWidget(double cpu_p, String cpu_u, double radius, Color color) { return Container( - width: radius + 10, + margin: const EdgeInsets.symmetric(vertical: 10.0), + width: radius * 2, alignment: Alignment.center, child: CircularPercentIndicator( radius: radius, lineWidth: 16.0, animation: true, percent: cpu_p/100, - center: Text("${cpu_p}%", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0), - ), - footer: Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 32.0), - child: Text(cpu_u, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17.0), - ), + center: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text("${cpu_p}%", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0)), + const SizedBox(height: 4.0), + Text(cpu_u) + ] ), circularStrokeCap: CircularStrokeCap.round, progressColor: color, @@ -310,17 +306,28 @@ class _DeviceListenPageState extends State { final status = context.watch().status; final uptimes = status.uptime.uptime(); - double radius = MediaQuery.of(context).size.width / 2 - 40; - if (radius > 150) { - radius = 150; + double radius = MediaQuery.of(context).size.width / 4 - 10; + if (radius > 100) { + radius = 100; + } else { + radius = MediaQuery.of(context).size.width / 2 - 50; + if (radius > 99) { + radius = 99; + } } - double height = MediaQuery.of(context).size.height / 2 - radius - 60; - if (height < 16) { - height = 16; - } else if (!isDesktop) { - height = 32; - } + final w1 = percentWidget( + status.cpu_p(), "CPU: ${status.cpu_u()} cores", radius, Color(0xFF6174FF), + ); + final w2 = percentWidget( + status.memory_p(), "${lang.memory}: ${status.memory_u()}", radius, Colors.blue, + ); + final w3 = percentWidget( + status.swap_p(), "${lang.swap}: ${status.memory_u()}", radius, Colors.green, + ); + final w4 = percentWidget( + status.disk_p(), "${lang.disk}: ${status.disk_u()}", radius, Colors.purple, + ); return Scaffold( body: SafeArea( @@ -355,47 +362,21 @@ class _DeviceListenPageState extends State { const SizedBox(height: 10.0), ] ), - SizedBox(height: height), + const SizedBox(height: 20.0), Expanded( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - percentWidget( - status.cpu_p(), - "CPU: ${status.cpu_u()} cores", - radius, - Color(0xFF6174FF), - ), - percentWidget( - status.memory_p(), - "${lang.memory}: ${status.memory_u()}", - radius, - Colors.blue, - ), - ] + children: + radius == 100 ? [ + Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [w1, w2] ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - percentWidget( - status.swap_p(), - "${lang.swap}: ${status.memory_u()}", - radius, - Colors.green, - ), - percentWidget( - status.disk_p(), - "${lang.disk}: ${status.disk_u()}", - radius, - Colors.purple, - ), - ] + const SizedBox(height: 40.0), + Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [w3, w4] ), - ] + ] : [w1, w2, w3, w4] ), ) ) diff --git a/lib/apps/device/provider.dart b/lib/apps/device/provider.dart index 0e67091..0e9f0f5 100644 --- a/lib/apps/device/provider.dart +++ b/lib/apps/device/provider.dart @@ -32,7 +32,7 @@ class DeviceProvider extends ChangeNotifier { this.clear(); // load status. - rpc.send('device-status', [this.devices[id]!.addr]); + rpc.send('device-status', [id]); } connect(String addr) { diff --git a/lib/apps/group/detail.dart b/lib/apps/group/detail.dart index a32c83e..15fd86d 100644 --- a/lib/apps/group/detail.dart +++ b/lib/apps/group/detail.dart @@ -85,10 +85,9 @@ class _GroupChatDetailState extends State { } } - // [group_id, member_id, member_addr] + // [group_id, member_id] _memberOnline(List params) { if (_group.id == params[0] && this._members.containsKey(params[1])) { - this._members[params[1]]!.addr = params[2]; this._members[params[1]]!.online = true; setState(() {}); } @@ -289,7 +288,7 @@ class _GroupChatDetailState extends State { final msg = this._messages[recentMessageKeys[index]]!; return ChatMessage( avatar: this._members[msg.mid]!.showAvatar(isOnline: false), - fgid: this._members[msg.mid]!.mid, + fpid: this._members[msg.mid]!.mid, name: this._members[msg.mid]!.name, message: msg, ); @@ -336,7 +335,6 @@ class _MemberScreenState extends State<_MemberScreen> { app: 'add-friend', id: member.mid, name: member.name, - addr: member.addr, title: lang.qrFriend, ), 0.0, diff --git a/lib/apps/group/models.dart b/lib/apps/group/models.dart index 672b9cf..ff0d834 100644 --- a/lib/apps/group/models.dart +++ b/lib/apps/group/models.dart @@ -35,7 +35,6 @@ class Member { int id = 0; int fid = 0; String mid = ''; - String addr = ''; String name = ''; bool leave = false; bool online = false; @@ -44,10 +43,9 @@ class Member { this.id = params[0]; this.fid = params[1]; this.mid = params[2]; - this.addr = params[3]; - this.name = params[4]; - this.leave = params[5]; - if (this.addr == Global.addr) { + this.name = params[3]; + this.leave = params[4]; + if (this.mid == Global.pid) { this.online = true; } } diff --git a/lib/apps/jarvis/detail.dart b/lib/apps/jarvis/detail.dart index 816f6e8..10ce312 100644 --- a/lib/apps/jarvis/detail.dart +++ b/lib/apps/jarvis/detail.dart @@ -120,7 +120,7 @@ class _JarvisDetailState extends State { itemCount: recentMessageKeys.length, reverse: true, itemBuilder: (BuildContext context, index) => ChatMessage( - fgid: '', + fpid: '', name: lang.jarvis, message: this._messages[recentMessageKeys[index]]!, ) diff --git a/lib/apps/primitives.dart b/lib/apps/primitives.dart index e969f89..de83051 100644 --- a/lib/apps/primitives.dart +++ b/lib/apps/primitives.dart @@ -154,7 +154,7 @@ class BaseMessage { List showInvite() { var type = GroupType.Tmp; - var gid = ''; + var pid = ''; var addr = ''; var name = ''; var proof = ''; @@ -166,12 +166,12 @@ class BaseMessage { } final raw_0 = this.content.substring(iType + 2); - final iGid = raw_0.indexOf(';;'); - if (iGid > 0) { - gid = raw_0.substring(0, iGid); + final iPid = raw_0.indexOf(';;'); + if (iPid > 0) { + pid = raw_0.substring(0, iPid); } - final raw_1 = raw_0.substring(iGid + 2); + final raw_1 = raw_0.substring(iPid + 2); final iAddr = raw_1.indexOf(';;'); if (iAddr > 0) { addr = raw_1.substring(0, iAddr); @@ -183,7 +183,7 @@ class BaseMessage { name = raw_2.substring(0, iName).replaceAll('-;', ';'); } else { name = raw_2.replaceAll('-;', ';'); - return [type, gid, addr, name, proof, key]; + return [type, pid, addr, name, proof, key]; } final raw_3 = raw_2.substring(iName + 2); @@ -195,7 +195,7 @@ class BaseMessage { proof = raw_3; } - return [type, gid, addr, name, proof, key]; + return [type, pid, addr, name, proof, key]; } // [hash, to, amount, name, network] diff --git a/lib/apps/wallet/page.dart b/lib/apps/wallet/page.dart index 0788c7d..0308567 100644 --- a/lib/apps/wallet/page.dart +++ b/lib/apps/wallet/page.dart @@ -1025,7 +1025,7 @@ class _TransferTokenState extends State<_TransferToken> { items: this._nft.map((value) { return DropdownMenuItem( value: value, - child: Text(gidPrint(value, '', 6)), + child: Text(pidPrint(value, '', 6)), ); }).toList(), ), @@ -1090,13 +1090,13 @@ class _TransferTokenState extends State<_TransferToken> { return; } final amount = restoreBalance(a, widget.token.decimal); - final gid = context.read().activedAccount.gid; + final pid = context.read().activedAccount.pid; showShadowDialog( context, Icons.security_rounded, lang.verifyPin, PinWords( - gid: gid, + pid: pid, callback: (key) async { Navigator.of(context).pop(); rpc.send('wallet-transfer', [ @@ -1248,7 +1248,7 @@ class _ImportNftState extends State<_ImportNft> { itemBuilder: (BuildContext context, int index) { final hash = this._nft[index]; return ListTile( - title: Text('TokenID: ' + gidPrint(hash, '', 6)), + title: Text('TokenID: ' + pidPrint(hash, '', 6)), trailing: IconButton(icon: Icon(Icons.link, color: color.primary), onPressed: () { launch(widget.token.nftUrl(hash)); diff --git a/lib/global.dart b/lib/global.dart index c26a935..ad62e12 100644 --- a/lib/global.dart +++ b/lib/global.dart @@ -1,31 +1,30 @@ class Global { static String version = 'v0.5.0'; - static String gid = '0000000000000000000000000000000000000000000000000000000000000000'; - static String httpRpc = '127.0.0.1:8000'; - static String wsRpc = '127.0.0.1:8080'; + static String pid = '0000000000000000000000000000000000000000000000000000000000000000'; + static String httpRpc = '127.0.0.1:7365'; + static String wsRpc = '127.0.0.1:7366'; //static String httpRpc = '192.168.2.148:8001'; // test code //static String wsRpc = '192.168.2.148:8081'; // test code //static String httpRpc = '192.168.50.250:8001'; // test code //static String wsRpc = '192.168.50.250:8081'; // test code static String optionCache = 'option'; - static String addr = '0x'; static String home = '.tdn'; - static String filePath = home + '/' + gid + '/files/'; - static String imagePath = home + '/' + gid + '/images/'; - static String thumbPath = home + '/' + gid + '/thumbs/'; - static String emojiPath = home + '/' + gid + '/emojis/'; - static String recordPath = home + '/' + gid + '/records/'; - static String avatarPath = home + '/' + gid + '/avatars/'; + static String filePath = home + '/' + pid + '/files/'; + static String imagePath = home + '/' + pid + '/images/'; + static String thumbPath = home + '/' + pid + '/thumbs/'; + static String emojiPath = home + '/' + pid + '/emojis/'; + static String recordPath = home + '/' + pid + '/records/'; + static String avatarPath = home + '/' + pid + '/avatars/'; - static changeGid(String gid) { - Global.gid = gid; - Global.filePath = home + '/' + gid + '/files/'; - Global.imagePath = home + '/' + gid + '/images/'; - Global.thumbPath = home + '/' + gid + '/thumbs/'; - Global.emojiPath = home + '/' + gid + '/emojis/'; - Global.recordPath = home + '/' + gid + '/records/'; - Global.avatarPath = home + '/' + gid + '/avatars/'; + static changePid(String pid) { + Global.pid = pid; + Global.filePath = home + '/' + pid + '/files/'; + Global.imagePath = home + '/' + pid + '/images/'; + Global.thumbPath = home + '/' + pid + '/thumbs/'; + Global.emojiPath = home + '/' + pid + '/emojis/'; + Global.recordPath = home + '/' + pid + '/records/'; + Global.avatarPath = home + '/' + pid + '/avatars/'; } static changeWs(String newWs) { diff --git a/lib/pages/account_generate.dart b/lib/pages/account_generate.dart index 00b9f44..554f480 100644 --- a/lib/pages/account_generate.dart +++ b/lib/pages/account_generate.dart @@ -31,6 +31,7 @@ class _AccountGeneratePageState extends State { bool _mnemonicChecked = false; bool _registerChecked = false; bool _isAccount = false; + bool _loading = false; TextEditingController _nameController = new TextEditingController(); FocusNode _nameFocus = new FocusNode(); @@ -91,22 +92,32 @@ class _AccountGeneratePageState extends State { SetPinWords( callback: (lock) async { Navigator.of(context).pop(); + setState(() { this._loading = true; }); + // send to core node service by rpc. final res = await httpPost('account-create', [ _selectedLang.toInt(), mnemonic, "", name, lock, avatar ]); if (res.isOk) { - // save this User - final account = Account(res.params[0], name, avatar); + final pid = res.params[0]; + final login = await httpPost('account-login', [pid, lock]); + + if (login.isOk) { + // save this User + final account = Account(pid, name, avatar); - Provider.of(context, listen: false).addAccount(account, lock); - Provider.of(context, listen: false).updateActived(); + Provider.of(context, listen: false).addAccount(account, lock); + Provider.of(context, listen: false).updateActived(); - Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen( - name: name, - ))); + Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen( + name: name, + ))); + } else { + setState(() { this._loading = false; }); + } } else { + setState(() { this._loading = false; }); // TODO tostor error print(res.error); } @@ -272,8 +283,9 @@ class _AccountGeneratePageState extends State { }), ), const SizedBox(height: 32.0), - ButtonText(text: lang.ok, action: () => registerNewAction(lang.setPin), - enable: this._registerChecked), + ButtonText(text: this._loading ? lang.waiting : lang.ok, + action: () => registerNewAction(lang.setPin), + enable: this._registerChecked && !this._loading), _footer(lang.hasAccount, () => Navigator.of(context).pop()), ]) ]); diff --git a/lib/pages/account_quick.dart b/lib/pages/account_quick.dart index 667c27e..4a35eb1 100644 --- a/lib/pages/account_quick.dart +++ b/lib/pages/account_quick.dart @@ -28,6 +28,7 @@ class AccountQuickPage extends StatefulWidget { class _AccountQuickPageState extends State { bool _registerChecked = false; + bool _loading = false; TextEditingController _nameController = new TextEditingController(); FocusNode _nameFocus = new FocusNode(); @@ -97,8 +98,9 @@ class _AccountQuickPageState extends State { }), ), const SizedBox(height: 32.0), - ButtonText(text: lang.ok, action: () => registerNewAction(locale), - enable: this._registerChecked), + ButtonText(text: this._loading ? lang.waiting : lang.ok, + action: () => registerNewAction(locale), + enable: this._registerChecked && !this._loading), _footer(lang.hasAccount, () => Navigator.of(context).pop()), ]) ]) @@ -134,22 +136,32 @@ class _AccountQuickPageState extends State { return; } + setState(() { this._loading = true; }); + // send to core node service by rpc. final res = await httpPost('account-create', [ language.toInt(), mnemonic, "", name, lock, avatar ]); if (res.isOk) { - // save this User - final account = Account(res.params[0], name, avatar); - - Provider.of(context, listen: false).addAccount(account, lock); - Provider.of(context, listen: false).updateActived(); - - Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen( - name: name, - ))); + final pid = res.params[0]; + final login = await httpPost('account-login', [pid, lock]); + + if (login.isOk) { + // save this User + final account = Account(pid, name, avatar); + + Provider.of(context, listen: false).addAccount(account, lock); + Provider.of(context, listen: false).updateActived(); + + Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen( + name: name, + ))); + } else { + setState(() { this._loading = false; }); + } } else { + setState(() { this._loading = false; }); // TODO tostor error print(res.error); } diff --git a/lib/pages/account_restore.dart b/lib/pages/account_restore.dart index c500b67..7cfada5 100644 --- a/lib/pages/account_restore.dart +++ b/lib/pages/account_restore.dart @@ -25,23 +25,16 @@ class _AccountRestorePageState extends State { bool _statusChecked = false; String _name = ''; - TextEditingController _addrController = new TextEditingController(); - FocusNode _addrFocus = new FocusNode(); - bool _addrOnline = false; - bool _addrChecked = false; - Language _selectedLang = Language.English; TextEditingController _wordController = new TextEditingController(); FocusNode _wordFocus = new FocusNode(); List _mnemoicWords = []; bool _wordChecked = false; + bool _loading = false; @override initState() { super.initState(); - _addrFocus.addListener(() { - setState(() {}); - }); _wordFocus.addListener(() { setState(() {}); }); @@ -66,6 +59,11 @@ class _AccountRestorePageState extends State { deleteIconColor: Color(0xFFADB0BB))); }); + double maxHeight = (MediaQuery.of(context).size.height - 600) / 2; + if (maxHeight < 20.0) { + maxHeight = 20.0; + } + return Scaffold( body: SafeArea( child: Container( @@ -104,84 +102,10 @@ class _AccountRestorePageState extends State { onPressed: _scanQr, child: Icon(Icons.qr_code_scanner_rounded)), ])), - const SizedBox(height: 32.0), - Text( - 'Online Network Address', - style: - TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16.0), + SizedBox(height: maxHeight), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - height: 50.0, - width: 600.0, - child: Row(children: [ - Expanded( - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 20.0), - decoration: BoxDecoration( - color: color.surface, - border: Border.all( - color: this._addrFocus.hasFocus - ? color.primary - : color.surface), - borderRadius: BorderRadius.circular(10.0), - ), - child: TextField( - style: TextStyle(fontSize: 16.0), - decoration: InputDecoration( - border: InputBorder.none, - hintText: lang.address), - controller: this._addrController, - focusNode: this._addrFocus, - onSubmitted: (_v) => _checkAddrOnline(), - onChanged: (v) { - if (v.length > 0 && - !this._addrChecked) { - setState(() { - this._addrChecked = true; - }); - } - }), - ), - ), - if (this._addrOnline) - Container( - padding: const EdgeInsets.only(left: 8.0), - child: Icon(Icons.cloud_done_rounded, - color: Colors.green), - ), - const SizedBox(width: 8.0), - Container( - width: 100.0, - child: InkWell( - onTap: this._addrChecked - ? _checkAddrOnline - : null, - child: Container( - height: 45.0, - decoration: BoxDecoration( - color: this._addrChecked - ? Color(0xFF6174FF) - : Color(0xFFADB0BB), - borderRadius: - BorderRadius.circular(10.0)), - child: Center( - child: Text(lang.search, - style: TextStyle( - fontSize: 16.0, - color: Colors.white))), - ))), - ])), - const SizedBox(height: 32.0), - Text( - 'Mnemoic Words', - style: TextStyle( - fontSize: 18.0, fontWeight: FontWeight.bold), - ), Container( width: 600.0, height: 45.0, @@ -305,8 +229,8 @@ class _AccountRestorePageState extends State { ])), const SizedBox(height: 32.0), ButtonText( - text: lang.next, - enable: _statusChecked, + text: this._loading ? lang.waiting : lang.next, + enable: _statusChecked && !this._loading, action: () => _mnemonicRegister(lang.unknown, lang.setPin), ), _footer( @@ -322,33 +246,20 @@ class _AccountRestorePageState extends State { MaterialPageRoute( builder: (context) => QRScan(callback: (isOk, app, params) { Navigator.of(context).pop(); - if (app == 'distribute' && params.length == 4) { + if (app == 'distribute' && params.length == 2) { final name = params[0]; - //final id = gidParse(params[1]); - final addr = addrParse(params[2]); - final mnemonicWords = params[3]; + final mnemonicWords = params[1]; setState(() { - this._addrOnline = true; - this._addrChecked = false; this._wordController.text = ''; this._wordChecked = false; this._statusChecked = true; this._name = name; - this._addrController.text = addrText(addr); this._mnemoicWords = mnemonicWords.split(" "); }); } }))); } - _checkAddrOnline() { - FocusScope.of(context).unfocus(); - setState(() { - this._addrOnline = true; - this._addrChecked = false; - }); - } - _addWord() { final word = this._wordController.text.trim(); if (word.length == 0) { @@ -386,10 +297,6 @@ class _AccountRestorePageState extends State { if (this._name == '') { this._name = defaultName; } - final addr = addrParse(this._addrController.text.trim()); - if (addr.length < 2) { - return; - } showShadowDialog( context, @@ -398,9 +305,11 @@ class _AccountRestorePageState extends State { SetPinWords( callback: (lock) async { Navigator.of(context).pop(); + setState(() { this._loading = false; }); + // send to core node service by rpc. final res = await httpPost('account-restore', [ - _selectedLang.toInt(), mnemonic, "", this._name, lock, addr + _selectedLang.toInt(), mnemonic, "", this._name, lock ]); if (res.isOk) { @@ -412,6 +321,7 @@ class _AccountRestorePageState extends State { Navigator.of(context).pushNamedAndRemoveUntil("/", (Route route) => false); } else { + setState(() { this._loading = true; }); // TODO tostor error print(res.error); } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index e58a1ee..ae6536a 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -98,23 +98,20 @@ class _HomeListState extends State { MaterialPageRoute( builder: (context) => QRScan(callback: (isOk, app, params) { Navigator.of(context).pop(); - if (app == 'add-friend' && params.length == 3) { - final id = gidParse(params[0]); - final addr = addrParse(params[1]); - final name = params[2].trim(); - final widget = ChatAdd(id: id, addr: addr, name: name); + if (app == 'add-friend' && params.length == 2) { + final id = pidParse(params[0]); + final name = params[1].trim(); + final widget = ChatAdd(id: id, name: name); Provider.of(context, listen: false).systemAppFriendAddNew = false; if (isDesktop) { Provider.of(context, listen: false).updateActivedWidget(widget); } else { Navigator.push(context, MaterialPageRoute(builder: (_) => widget)); } - } else if (app == 'distribute' && params.length == 4) { + } else if (app == 'distribute' && params.length == 2) { //final _name = params[0].trim(); - //final id = gidParse(params[1]); - final addr = addrParse(params[2]); - //final _mnemonicWords = params[3]; - Provider.of(context, listen: false).connect(addr); + //final _mnemonicWords = params[1]; + //Provider.of(context, listen: false).connect(addr); } }))); } @@ -174,8 +171,7 @@ class _HomeListState extends State { UserInfo( app: 'add-friend', id: provider.id, - name: provider.activedAccount.name, - addr: Global.addr)); + name: provider.activedAccount.name)); } }, itemBuilder: (context) { @@ -312,7 +308,7 @@ class DrawerWidget extends StatelessWidget { ? () { Navigator.of(context).pop(); Provider.of(context, listen: false) - .updateActivedAccount(account.gid, account.pin); + .updateActivedAccount(account.pid, account.pin); Provider.of(context, listen: false) .updateActived(); } @@ -340,18 +336,18 @@ class DrawerWidget extends StatelessWidget { Icons.security_rounded, lang.verifyPin, PinWords( - gid: account.gid, + pid: account.pid, callback: (key) async { Navigator.of(context).pop(); Provider.of(context, listen: false) - .onlineAccount(account.gid, key); + .onlineAccount(account.pid, key); }), 0.0, ); } else { Provider.of(context, listen: false) - .offlineAccount(account.gid); + .offlineAccount(account.pid); } }, ), @@ -380,8 +376,8 @@ class DrawerWidget extends StatelessWidget { final accounts = provider.accounts; List accountsWidget = []; - accounts.forEach((gid, account) { - if (gid != me.gid) { + accounts.forEach((pid, account) { + if (pid != me.pid) { accountsWidget.add(_listAccount(context, account, color.primary, lang)); } }); diff --git a/lib/pages/setting/network.dart b/lib/pages/setting/network.dart index c420a6e..2ed7864 100644 --- a/lib/pages/setting/network.dart +++ b/lib/pages/setting/network.dart @@ -26,7 +26,6 @@ class _NetworkDetailState extends State { changeWs() async { Global.changeWs(wsController.text); await rpc.init(wsController.text); - rpc.send('system-info', []); setState(() {}); } @@ -42,6 +41,7 @@ class _NetworkDetailState extends State { void loadNetworkDht() async { final res = await httpPost('network-dht', []); + print(res); if (res.isOk) { this.networkDht.clear(); res.params.forEach((p) { diff --git a/lib/pages/setting/profile.dart b/lib/pages/setting/profile.dart index 59a7eb5..6583e84 100644 --- a/lib/pages/setting/profile.dart +++ b/lib/pages/setting/profile.dart @@ -167,8 +167,7 @@ class _ProfileDetailState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ - _infoListTooltip(Icons.person, color.primary, gidText(account.gid), gidPrint(account.gid)), - _infoListTooltip(Icons.location_on, color.primary, addrText(Global.addr), addrPrint(Global.addr)), + _infoListTooltip(Icons.person, color.primary, pidText(account.pid), pidPrint(account.pid)), SizedBox( height: 40.0, child: Row( @@ -177,8 +176,8 @@ class _ProfileDetailState extends State { size: 20.0, color: color.primary), const SizedBox(width: 20.0), TextButton( - onPressed: () => _pinCheck(account.gid, - (key) => _changePin(context, account.gid, key, lang.setPin), + onPressed: () => _pinCheck(account.pid, + (key) => _changePin(context, account.pid, key, lang.setPin), lang.verifyPin, color ), child: Text(lang.change + ' PIN'), @@ -200,8 +199,8 @@ class _ProfileDetailState extends State { child: Text(lang.hide + ' ' + lang.mnemonic), ) : TextButton( - onPressed: () => _pinCheck(account.gid, - (key) => _showMnemonic(account.gid, key), lang.verifyPin, color), + onPressed: () => _pinCheck(account.pid, + (key) => _showMnemonic(account.pid, key), lang.verifyPin, color), child: Text(lang.show + ' ' + lang.mnemonic), ), ]), @@ -278,13 +277,13 @@ class _ProfileDetailState extends State { } } - _pinCheck(String gid, Function callback, String title, color) { + _pinCheck(String pid, Function callback, String title, color) { showShadowDialog( context, Icons.security_rounded, title, PinWords( - gid: gid, + pid: pid, callback: (key) async { Navigator.of(context).pop(); callback(key); diff --git a/lib/provider.dart b/lib/provider.dart index 395812f..aa407e8 100644 --- a/lib/provider.dart +++ b/lib/provider.dart @@ -14,12 +14,12 @@ const DEFAULT_ONLINE_INIT = 8; const DEFAULT_ONLINE_DELAY = 5; class AccountProvider extends ChangeNotifier { - Map accounts = {}; // account's gid and account. - String activedAccountId = ''; // actived account gid. + Map accounts = {}; // account's pid and account. + String activedAccountId = ''; // actived account pid. Account get activedAccount => this.accounts[activedAccountId]!; /// current user's did. - String get id => this.activedAccount.gid; + String get id => this.activedAccount.pid; bool systemAppFriendAddNew = false; @@ -48,7 +48,6 @@ class AccountProvider extends ChangeNotifier { rpc.addNotice(_accountNotice); // rpc - rpc.addListener('account-system-info', _systemInfo); rpc.addListener('account-update', _accountUpdate); rpc.addListener('account-login', _accountLogin); @@ -65,28 +64,26 @@ class AccountProvider extends ChangeNotifier { } /// when security load accounts from cache. - autoAccounts(String gid, String pin, Map accounts) { - Global.changeGid(gid); + autoAccounts(String pid, String pin, Map accounts) { + Global.changePid(pid); this.accounts = accounts; - this.activedAccountId = gid; + this.activedAccountId = pid; this.activedAccount.online = true; this.activedAccount.pin = pin; rpc.send('session-list', []); - new Future.delayed(Duration(seconds: DEFAULT_ONLINE_INIT), - () => rpc.send('account-online', [gid])); - initLogined(gid, this.accounts.values.toList()); + initLogined(pid, this.accounts.values.toList()); this.coreShowWidget = DefaultCoreShow(); } /// when security add account. addAccount(Account account, String pin) { - Global.changeGid(account.gid); - this.accounts[account.gid] = account; + Global.changePid(account.pid); + this.accounts[account.pid] = account; - this.activedAccountId = account.gid; + this.activedAccountId = account.pid; this.activedAccount.online = true; this.activedAccount.pin = pin; @@ -94,11 +91,11 @@ class AccountProvider extends ChangeNotifier { updateLogined(account); } - updateActivedAccount(String gid, String pin) { - Global.changeGid(gid); + updateActivedAccount(String pid, String pin) { + Global.changePid(pid); this.clearActivedAccount(); - this.activedAccountId = gid; + this.activedAccountId = pid; this.activedAccount.online = true; this.activedAccount.pin = pin; this.activedAccount.hasNew = false; @@ -113,11 +110,9 @@ class AccountProvider extends ChangeNotifier { if (!this.activedAccount.online) { this.activedAccount.online = true; - new Future.delayed(Duration(seconds: DEFAULT_ONLINE_DELAY), - () => rpc.send('account-online', [gid])); } - mainLogined(gid); + mainLogined(pid); notifyListeners(); } @@ -133,25 +128,22 @@ class AccountProvider extends ChangeNotifier { clearLogined(); } - onlineAccount(String gid, String pin) { - this.accounts[gid]!.online = true; - this.accounts[gid]!.pin = pin; + onlineAccount(String pid, String pin) { + this.accounts[pid]!.online = true; + this.accounts[pid]!.pin = pin; - rpc.send('account-login', [gid, pin]); - - new Future.delayed(Duration(seconds: DEFAULT_ONLINE_DELAY), - () => rpc.send('account-online', [gid])); + rpc.send('account-login', [pid, pin]); notifyListeners(); } - offlineAccount(String gid) { - this.accounts[gid]!.online = false; - this.accounts[gid]!.pin = ''; + offlineAccount(String pid) { + this.accounts[pid]!.online = false; + this.accounts[pid]!.pin = ''; - if (gid == this.activedAccountId) { + if (pid == this.activedAccountId) { this.clearActivedAccount(); } - rpc.send('account-offline', [gid]); + rpc.send('account-offline', [pid]); notifyListeners(); } @@ -181,7 +173,7 @@ class AccountProvider extends ChangeNotifier { clearActivedSession(SessionType type) { if (this.actived > 0 && this.activedSession.type == type) { - rpc.send('session-suspend', [this.actived, this.activedSession.gid, + rpc.send('session-suspend', [this.actived, this.activedSession.pid, this.activedSession.type == SessionType.Group] ); this.actived = 0; @@ -202,7 +194,7 @@ class AccountProvider extends ChangeNotifier { if (id > 0) { if (this.actived != id && this.actived > 0) { - rpc.send('session-suspend', [this.actived, this.activedSession.gid, + rpc.send('session-suspend', [this.actived, this.activedSession.pid, this.activedSession.type == SessionType.Group] ); } @@ -219,7 +211,7 @@ class AccountProvider extends ChangeNotifier { } }); } - rpc.send('session-connect', [id, this.activedSession.gid]); + rpc.send('session-connect', [id, this.activedSession.pid]); notifyListeners(); } } @@ -237,17 +229,13 @@ class AccountProvider extends ChangeNotifier { } // -- callback when receive rpc info. -- // - _systemInfo(List params) { - Global.addr = params[0]; - } - _accountLogin(List _params) { // nothing. } - _accountNotice(String gid) { - if (this.accounts.containsKey(gid)) { - this.accounts[gid]!.hasNew = true; + _accountNotice(String pid) { + if (this.accounts.containsKey(pid)) { + this.accounts[pid]!.hasNew = true; notifyListeners(); } } @@ -261,10 +249,10 @@ class AccountProvider extends ChangeNotifier { } _accountUpdate(List params) { - final gid = params[0]; - this.accounts[gid]!.name = params[1]; + final pid = params[0]; + this.accounts[pid]!.name = params[1]; if (params[2].length > 1) { - this.accounts[gid]!.updateAvatar(params[2]); + this.accounts[pid]!.updateAvatar(params[2]); } notifyListeners(); } diff --git a/lib/rpc.dart b/lib/rpc.dart index 516872f..6b27213 100644 --- a/lib/rpc.dart +++ b/lib/rpc.dart @@ -10,7 +10,6 @@ import 'package:esse/global.dart'; Map jsonrpc = { "jsonrpc": "2.0", "id": 1, - "gid": Global.gid, "method": "", "params": [], }; @@ -111,7 +110,6 @@ class WebSocketsNotifications { send(String method, List params) { jsonrpc["method"] = method; jsonrpc["params"] = params; - jsonrpc["gid"] = Global.gid; if (_channel != null) { _channel!.sink.add(json.encode(jsonrpc)); @@ -134,23 +132,16 @@ class WebSocketsNotifications { Map response = json.decode(message); print(response); - if (response["result"] != null && - response["method"] != null && - response["gid"] != null - ) { - String method = response["method"]; - List params = response["result"]; - String gid = response["gid"]; + if (response["result"] != null && response["method"] != null) { + String method = response["method"]; + List params = response["result"]; + if (_listeners[method] != null) { final callbacks = _listeners[method]!; - if (gid == Global.gid || method.startsWith('account')) { - try { - callbacks[0](params); - } catch (e) { - print('function is unvalid'); - } - } else if (callbacks[1] != null && callbacks[1]) { - _notice!(gid); + try { + callbacks[0](params); + } catch (e) { + print('function is unvalid'); } } else { print("has no this " + method); diff --git a/lib/security.dart b/lib/security.dart index c3fcea3..72af420 100644 --- a/lib/security.dart +++ b/lib/security.dart @@ -31,6 +31,7 @@ class _SecurityPageState extends State { Map _accounts = {}; bool _loaded = false; bool _accountsLoaded = false; + bool _loading = false; String _selectedUserId = ''; @@ -106,7 +107,8 @@ class _SecurityPageState extends State { const SizedBox(height: 40.0), loginForm(color, lang), const SizedBox(height: 20.0), - ButtonText(text: lang.ok, enable: _accountsLoaded, + ButtonText(text: this._loading ? lang.waiting : lang.ok, + enable: _accountsLoaded && !this._loading, action: () => loginAction(lang.verifyPin, color, lang)), const SizedBox(height: 20.0), InkWell( @@ -175,9 +177,6 @@ class _SecurityPageState extends State { await rpc.init(Global.wsRpc); } - // init system info. - rpc.send('account-system-info', []); - // check if has logined. final loginedAccounts = await getLogined(); if (loginedAccounts.length != 0) { @@ -185,11 +184,11 @@ class _SecurityPageState extends State { final mainAccount = loginedAccounts[0]; Map accounts = {}; loginedAccounts.forEach((account) { - accounts[account.gid] = account; + accounts[account.pid] = account; }); - final res = await httpPost('account-login', [mainAccount.gid, ""]); + final res = await httpPost('account-login', [mainAccount.pid, ""]); if (res.isOk) { - _handleLogined(mainAccount.gid, "", accounts); + _handleLogined(mainAccount.pid, "", accounts); return; } else { showShadowDialog( @@ -197,10 +196,10 @@ class _SecurityPageState extends State { Icons.security_rounded, "PIN", PinWords( - gid: mainAccount.gid, + pid: mainAccount.pid, callback: (key) async { Navigator.of(context).pop(); - _handleLogined(mainAccount.gid, key, accounts); + _handleLogined(mainAccount.pid, key, accounts); return; }), 0.0 @@ -218,7 +217,7 @@ class _SecurityPageState extends State { if (this._accounts.length > 0) { final accountId = this._accounts.keys.first; - this._selectedUserId = this._accounts[accountId]!.gid; + this._selectedUserId = this._accounts[accountId]!.pid; this._accountsLoaded = true; } } else { @@ -231,10 +230,12 @@ class _SecurityPageState extends State { } void _verifyAfter(String lock) async { + setState(() { this._loading = true; }); final res = await httpPost('account-login', [this._selectedUserId, lock]); if (res.isOk) { _handleLogined(this._selectedUserId, lock, this._accounts); } else { + setState(() { this._loading = false; }); toast(context, res.error); } } @@ -245,7 +246,7 @@ class _SecurityPageState extends State { Icons.security_rounded, title, PinWords( - gid: this._selectedUserId, + pid: this._selectedUserId, callback: (pinWords) async { Navigator.of(context).pop(); _verifyAfter(pinWords); @@ -271,16 +272,16 @@ class _SecurityPageState extends State { iconEnabledColor: Color(0xFFADB0BB), isExpanded: true, value: this._selectedUserId, - onChanged: (String? gid) { - if (gid != null) { + onChanged: (String? pid) { + if (pid != null) { setState(() { - this._selectedUserId = gid; + this._selectedUserId = pid; }); } }, items: this._accounts.values.map((Account account) { return DropdownMenuItem( - value: account.gid, + value: account.pid, child: Row( children: [ Expanded( @@ -290,7 +291,7 @@ class _SecurityPageState extends State { style: TextStyle(fontSize: 16) ), ), - Text(" (${gidPrint(account.gid)})", style: TextStyle(fontSize: 16)), + Text(" (${pidPrint(account.pid)})", style: TextStyle(fontSize: 16)), ] ), ); diff --git a/lib/session.dart b/lib/session.dart index 32108d3..f2f1a09 100644 --- a/lib/session.dart +++ b/lib/session.dart @@ -41,7 +41,7 @@ enum OnlineType { class Session { int id; int fid; - String gid; + String pid; String addr; SessionType type; String name; @@ -147,7 +147,17 @@ class Session { } Avatar showAvatar({double width = 45.0}) { - final avatar = Global.avatarPath + this.gid + '.png'; + String avatar = Global.avatarPath; + switch (this.type) { + case SessionType.Chat: + avatar + this.pid + '.png'; + break; + case SessionType.Group: + avatar + 'group_' + this.pid + '.png'; + break; + default: + break; + } Color color; switch (this.online) { @@ -194,7 +204,7 @@ class Session { Session.fromList(List params) : this.id = params[0], this.fid = params[1], - this.gid = params[2], + this.pid = params[2], this.addr = params[3], this.type = SessionTypeExtension.fromInt(params[4]), this.name = params[5], diff --git a/lib/utils/better_print.dart b/lib/utils/better_print.dart index 35a1750..882b76d 100644 --- a/lib/utils/better_print.dart +++ b/lib/utils/better_print.dart @@ -1,16 +1,16 @@ -String gidText(String? gid, [String pre='EH']) { - if (gid == null) { +String pidText(String? pid, [String pre='EH']) { + if (pid == null) { return ''; } - return pre + gid.toUpperCase(); + return pre + pid.toUpperCase(); } -String gidPrint(String? gid, [String pre='EH', int n = 4]) { - if (gid == null) { +String pidPrint(String? pid, [String pre='EH', int n = 6]) { + if (pid == null) { return ''; } - final info = gid.toUpperCase(); + final info = pid.toUpperCase(); final len = info.length; if (len > n+n) { return pre + info.substring(0, n) + '...' + info.substring(len - n, len); @@ -19,11 +19,11 @@ String gidPrint(String? gid, [String pre='EH', int n = 4]) { } } -String gidParse(String gid, [String pre='EH']) { - if (gid.length > 2 && gid.substring(0, 2) == pre) { - return gid.substring(2); +String pidParse(String pid, [String pre='EH']) { + if (pid.length > 2 && pid.substring(0, 2) == pre) { + return pid.substring(2); } else { - return gid; + return pid; } } diff --git a/lib/utils/logined_cache.dart b/lib/utils/logined_cache.dart index 6fade09..0e367b5 100644 --- a/lib/utils/logined_cache.dart +++ b/lib/utils/logined_cache.dart @@ -14,7 +14,7 @@ Future> getLogined() async { final fields = prefs.getStringList(id); if (fields != null && fields.length == 5) { accounts.add(Account( - fields[0], // gid + fields[0], // pid fields[1], // name fields[2], // avatar false, @@ -28,7 +28,7 @@ Future> getLogined() async { return accounts; } -initLogined(String gid, List accounts) async { +initLogined(String pid, List accounts) async { SharedPreferences prefs = await SharedPreferences.getInstance(); final ids = prefs.getStringList(LOGINED_CACHE_NAME); if (ids != null) { @@ -37,19 +37,19 @@ initLogined(String gid, List accounts) async { }); } - List newIds = [gid]; + List newIds = [pid]; accounts.forEach((account) { final List fields = [ - account.gid, + account.pid, account.name, account.encodeAvatar(), ]; - if (account.gid != gid) { - newIds.add(account.gid); + if (account.pid != pid) { + newIds.add(account.pid); } - prefs.setStringList(account.gid, fields); + prefs.setStringList(account.pid, fields); }); prefs.setStringList(LOGINED_CACHE_NAME, newIds); @@ -64,44 +64,44 @@ updateLogined(Account account) async { } - if (!ids.contains(account.gid)) { - ids.add(account.gid); + if (!ids.contains(account.pid)) { + ids.add(account.pid); prefs.setStringList(LOGINED_CACHE_NAME, ids); } final List fields = [ - account.gid, + account.pid, account.name, account.encodeAvatar(), ]; - prefs.setStringList(account.gid, fields); + prefs.setStringList(account.pid, fields); } /// change main logined account. -mainLogined(String gid) async { +mainLogined(String pid) async { SharedPreferences prefs = await SharedPreferences.getInstance(); List? ids = prefs.getStringList(LOGINED_CACHE_NAME); if (ids == null) { ids = []; } - ids.remove(gid); - ids.insert(0, gid); + ids.remove(pid); + ids.insert(0, pid); prefs.setStringList(LOGINED_CACHE_NAME, ids); } /// remove auto-login accounts. -removeLogined(String gid) async { +removeLogined(String pid) async { SharedPreferences prefs = await SharedPreferences.getInstance(); - prefs.remove(gid); + prefs.remove(pid); List? ids = prefs.getStringList(LOGINED_CACHE_NAME); if (ids == null) { ids = []; } - if (ids.contains(gid)) { - ids.remove(gid); + if (ids.contains(pid)) { + ids.remove(pid); prefs.setStringList(LOGINED_CACHE_NAME, ids); } } diff --git a/lib/widgets/chat_message.dart b/lib/widgets/chat_message.dart index 1920a7e..ba1e7d3 100644 --- a/lib/widgets/chat_message.dart +++ b/lib/widgets/chat_message.dart @@ -22,13 +22,13 @@ import 'package:esse/apps/wallet/models.dart' show NetworkExtension, Network, To class ChatMessage extends StatelessWidget { final Widget? avatar; - final String fgid; + final String fpid; final String name; final BaseMessage message; - const ChatMessage({Key? key, required this.fgid, required this.name, required this.message, this.avatar}): super(key: key); + const ChatMessage({Key? key, required this.fpid, required this.name, required this.message, this.avatar}): super(key: key); - Widget _showContactCard(Widget avatar, String gid, String name, String title, ColorScheme color, [String pre='EH']) { + Widget _showContactCard(Widget avatar, String pid, String name, String title, ColorScheme color, [String pre='EH']) { return Container( padding: const EdgeInsets.only(top: 10, bottom: 6.0, left: 10.0, right: 10.0), width: 200.0, @@ -41,7 +41,7 @@ class ChatMessage extends StatelessWidget { child: Column(children: [ Text(name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: color.onPrimary, fontSize: 16.0)), const SizedBox(height: 4.0), - Text(gidPrint(gid, pre), style: TextStyle(color: Colors.grey, fontSize: 12.0)), + Text(pidPrint(pid, pre), style: TextStyle(color: Colors.grey, fontSize: 12.0)), ]))]), const SizedBox(height: 5.0), const Divider(height: 1.0, color: Color(0x40ADB0BB)), @@ -220,7 +220,7 @@ class ChatMessage extends StatelessWidget { } Widget _showContact(context, lang, color, maxWidth) { - // contact [name, gid, addr, avatar] + // contact [name, pid, avatar] final infos = message.showContact(); if (infos[1].length > 0) { return GestureDetector( @@ -229,7 +229,7 @@ class ChatMessage extends StatelessWidget { Icons.person_rounded, lang.contactCard, UserInfo( - showQr: false, id: infos[1], addr: infos[2], name: infos[0], + showQr: false, id: infos[1], name: infos[0], remark: lang.fromContactCard(name), avatar: Avatar(width: 100.0, name: infos[0], avatarPath: infos[3]), callback: () { @@ -251,7 +251,7 @@ class ChatMessage extends StatelessWidget { } Widget _showInvite(context, lang, color, maxWidth) { - // contact [type, gid, addr, name, proof, key] + // contact [type, pid, addr, name, proof, key] final infos = message.showInvite(); if (infos[1].length > 0) { final GroupType gtype = infos[0]; @@ -260,7 +260,7 @@ class ChatMessage extends StatelessWidget { context, Icons.groups_rounded, lang.groupChat, - UserInfo(showQr: false, id: infos[1], addr: infos[2], name: infos[3], pre: 'EG', + UserInfo(showQr: false, id: infos[1], name: infos[3], pre: 'EG', title: gtype.lang(lang), avatar: Container(width: 100.0, height: 100.0, padding: const EdgeInsets.all(8.0), @@ -271,7 +271,7 @@ class ChatMessage extends StatelessWidget { Navigator.pop(context); // TOOD join invite. // Provider.of(context, listen: false).join( - // gtype, infos[1], infos[2], infos[3], fgid, infos[4], infos[5] + // gtype, infos[1], infos[2], infos[3], fpid, infos[4], infos[5] // ); }, ), diff --git a/lib/widgets/show_contact.dart b/lib/widgets/show_contact.dart index 4b50c97..0dbc745 100644 --- a/lib/widgets/show_contact.dart +++ b/lib/widgets/show_contact.dart @@ -40,7 +40,7 @@ class _ContactListState extends State { List offlines = []; res.params.forEach((params) { final friend = Friend.fromList(params); - if (!widget.filters.contains(friend.gid)) { + if (!widget.filters.contains(friend.pid)) { if (friend.online) { onlines.add(friend); } else { @@ -52,7 +52,7 @@ class _ContactListState extends State { } else { res.params.forEach((params) { final friend = Friend.fromList(params); - if (!widget.filters.contains(friend.gid)) { + if (!widget.filters.contains(friend.pid)) { this._friends.add(friend); } }); diff --git a/lib/widgets/show_pin.dart b/lib/widgets/show_pin.dart index d6ed2d8..1973275 100644 --- a/lib/widgets/show_pin.dart +++ b/lib/widgets/show_pin.dart @@ -56,9 +56,9 @@ Widget _keyboradInput(Color color, Color bg, String text, Function callback) { class PinWords extends StatefulWidget { final Function callback; - final String gid; + final String pid; - PinWords({Key? key, required this.gid, required this.callback}) : super(key: key); + PinWords({Key? key, required this.pid, required this.callback}) : super(key: key); @override _PinWordsState createState() => _PinWordsState(); @@ -71,7 +71,7 @@ class _PinWordsState extends State { _checkPin() async { bool check = false; - final res = await httpPost('account-pin-check', [widget.gid, _pinWords]); + final res = await httpPost('account-pin-check', [widget.pid, _pinWords]); if (res.isOk) { check = res.params[0]; } else { diff --git a/lib/widgets/transfer.dart b/lib/widgets/transfer.dart index d94b86c..82545f5 100644 --- a/lib/widgets/transfer.dart +++ b/lib/widgets/transfer.dart @@ -353,13 +353,13 @@ class _TransferState extends State { return; } final amount = restoreBalance(a, this._selectedToken.decimal); - final gid = context.read().activedAccount.gid; + final pid = context.read().activedAccount.pid; showShadowDialog( context, Icons.security_rounded, lang.verifyPin, PinWords( - gid: gid, + pid: pid, callback: (key) async { if (this._main.length < 2) { return; diff --git a/lib/widgets/user_info.dart b/lib/widgets/user_info.dart index 8f91aec..e2e2d45 100644 --- a/lib/widgets/user_info.dart +++ b/lib/widgets/user_info.dart @@ -11,7 +11,6 @@ class UserInfo extends StatefulWidget { final String? app; final String id; final String name; - final String addr; final String? title; final String? remark; final String? bio; @@ -23,7 +22,6 @@ class UserInfo extends StatefulWidget { UserInfo({Key? key, required this.id, - required this.addr, required this.name, this.app, this.remark, @@ -37,7 +35,7 @@ class UserInfo extends StatefulWidget { if (this.showQr) { this.qrInfo = { "app": this.app, - "params": [gidText(this.id, this.pre), addrText(this.addr), this.name], + "params": [pidText(this.id, this.pre), this.name], }; } } @@ -48,7 +46,6 @@ class UserInfo extends StatefulWidget { class _UserInfoState extends State { bool idCopy = false; - bool addrCopy = false; @override Widget build(BuildContext context) { @@ -57,7 +54,7 @@ class _UserInfoState extends State { Color idColor = idCopy ? color.primary : color.onPrimary; - Color addrColor = addrCopy ? color.primary : color.onPrimary; + print(pidText(widget.id)); return Column( mainAxisAlignment: MainAxisAlignment.center, @@ -109,52 +106,32 @@ class _UserInfoState extends State { ), if (widget.title != null) Text(widget.title!, style: TextStyle(fontSize: 16.0, fontStyle: FontStyle.italic)), - const SizedBox(height: 10), - const Divider(height: 1.0, color: Color(0x40ADB0BB)), - const SizedBox(height: 20), InkWell( onTap: () { - Clipboard.setData(ClipboardData(text: gidText(widget.id))); + Clipboard.setData(ClipboardData(text: pidText(widget.id))); setState(() { idCopy = true; - addrCopy = false; }); }, child: Container( - width: 250.0, + padding: const EdgeInsets.symmetric(vertical: 10.0), child: Row( children: [ - Icon(Icons.person, size: 20.0, color: color.primary), - Spacer(), - Text(gidPrint(widget.id, widget.pre), style: TextStyle(fontSize: 14, color: idColor)), - Spacer(), - Icon(idCopy ? Icons.file_copy : Icons.copy, size: 20.0, color: color.primary), + Expanded( + child: Text(pidText(widget.id, widget.pre), + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, color: idColor))), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Icon(idCopy ? Icons.file_copy : Icons.copy, + size: 20.0, color: color.primary), + ), ] ), ) ), + const Divider(height: 1.0, color: Color(0x40ADB0BB)), const SizedBox(height: 16), - InkWell( - onTap: () { - Clipboard.setData(ClipboardData(text: addrText(widget.addr))); - setState(() { - idCopy = false; - addrCopy = true; - }); - }, - child: Container( - width: 250.0, - child: Row( - children: [ - Icon(Icons.location_on, size: 20.0, color: color.primary), - Spacer(), - Text(addrPrint(widget.addr), style: TextStyle(fontSize: 14, color: addrColor)), - Spacer(), - Icon(addrCopy ? Icons.file_copy : Icons.copy, size: 20.0, color: color.primary), - ] - ), - ) - ), if (widget.remark != null) Container( width: 250.0, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1136c38..cfd2ffa 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,6 +6,7 @@ import FlutterMacOS import Foundation import audio_session +import device_info_plus_macos import esse_core import file_selector_macos import just_audio @@ -15,6 +16,7 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) EsseCorePlugin.register(with: registry.registrar(forPlugin: "EsseCorePlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 1be3b9e..ef98561 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,13 +15,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.8.0" - ansicolor: - dependency: transitive - description: - name: ansicolor - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" archive: dependency: transitive description: @@ -78,6 +71,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + cli_dialog: + dependency: transitive + description: + name: cli_dialog + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.0" cli_util: dependency: transitive description: @@ -141,6 +141,55 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.1" + dart_console: + dependency: transitive + description: + name: dart_console + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.2" + device_info_plus_linux: + dependency: transitive + description: + name: device_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + device_info_plus_macos: + dependency: transitive + description: + name: device_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.2" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0+1" + device_info_plus_web: + dependency: transitive + description: + name: device_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_windows: + dependency: transitive + description: + name: device_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" diff_match_patch: dependency: transitive description: @@ -189,20 +238,20 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.4.0" file_selector: dependency: "direct main" description: name: file_selector url: "https://pub.dartlang.org" source: hosted - version: "0.8.2+1" + version: "0.8.3" file_selector_linux: dependency: "direct main" description: path: "plugins/file_selector/file_selector_linux" ref: HEAD - resolved-ref: c339fe7dd2e17a80f7bb839bfad89d21a6e084ba + resolved-ref: "89c350f787e1d7bff12b3517e5671146211ee70e" url: "git://github.com/google/flutter-desktop-embedding.git" source: git version: "0.0.2+1" @@ -211,7 +260,7 @@ packages: description: path: "plugins/file_selector/file_selector_macos" ref: HEAD - resolved-ref: c339fe7dd2e17a80f7bb839bfad89d21a6e084ba + resolved-ref: "89c350f787e1d7bff12b3517e5671146211ee70e" url: "git://github.com/google/flutter-desktop-embedding.git" source: git version: "0.0.4+1" @@ -221,23 +270,21 @@ packages: name: file_selector_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" file_selector_web: dependency: transitive description: name: file_selector_web url: "https://pub.dartlang.org" source: hosted - version: "0.8.1+2" + version: "0.8.1+3" file_selector_windows: - dependency: "direct main" + dependency: transitive description: - path: "plugins/file_selector/file_selector_windows" - ref: HEAD - resolved-ref: c339fe7dd2e17a80f7bb839bfad89d21a6e084ba - url: "git://github.com/google/flutter-desktop-embedding.git" - source: git - version: "0.0.2+1" + name: file_selector_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.2" flutter: dependency: "direct main" description: flutter @@ -268,7 +315,7 @@ packages: name: flutter_keyboard_visibility url: "https://pub.dartlang.org" source: hosted - version: "5.1.0" + version: "5.2.0" flutter_keyboard_visibility_platform_interface: dependency: transitive description: @@ -315,7 +362,7 @@ packages: name: flutter_native_splash url: "https://pub.dartlang.org" source: hosted - version: "1.3.3" + version: "2.0.5" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -329,7 +376,7 @@ packages: name: flutter_quill url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "4.0.5" flutter_test: dependency: "direct dev" description: flutter @@ -352,6 +399,13 @@ packages: description: flutter source: sdk version: "0.0.0" + gallery_saver: + dependency: transitive + description: + name: gallery_saver + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.2" gettext_parser: dependency: transitive description: @@ -400,28 +454,28 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.3" image_picker: dependency: "direct main" description: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+4" + version: "0.8.4+9" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.6" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.4.2" + version: "2.4.4" image_save: dependency: "direct main" description: @@ -429,13 +483,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.0.0" - injector: - dependency: transitive - description: - name: injector - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" integration_test: dependency: "direct dev" description: flutter @@ -461,21 +508,21 @@ packages: name: just_audio url: "https://pub.dartlang.org" source: hosted - version: "0.9.18" + version: "0.9.20" just_audio_platform_interface: dependency: transitive description: name: just_audio_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.0" just_audio_web: dependency: transitive description: name: just_audio_web url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.4" lints: dependency: transitive description: @@ -490,6 +537,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -503,7 +557,7 @@ packages: name: msix url: "https://pub.dartlang.org" source: hosted - version: "2.8.0" + version: "3.2.0" nested: dependency: transitive description: @@ -538,7 +592,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" path_provider_android: dependency: transitive description: @@ -559,28 +613,28 @@ packages: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" pedantic: dependency: transitive description: @@ -594,14 +648,28 @@ packages: name: percent_indicator url: "https://pub.dartlang.org" source: hosted - version: "3.4.0" + version: "4.0.0" permission_handler: dependency: "direct main" description: name: permission_handler url: "https://pub.dartlang.org" source: hosted - version: "8.3.0" + version: "9.2.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.2" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.2" permission_handler_platform_interface: dependency: transitive description: @@ -609,6 +677,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.7.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" petitparser: dependency: transitive description: @@ -629,14 +704,14 @@ packages: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.2" process: dependency: transitive description: @@ -671,7 +746,7 @@ packages: name: qr_code_scanner url: "https://pub.dartlang.org" source: hosted - version: "0.6.1" + version: "0.7.0" qr_flutter: dependency: "direct main" description: @@ -720,35 +795,35 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.13" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.11" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.0" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" shared_preferences_platform_interface: dependency: transitive description: @@ -762,14 +837,14 @@ packages: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.0" sky_engine: dependency: transitive description: flutter @@ -837,7 +912,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" tuple: dependency: transitive description: @@ -872,35 +947,35 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.17" + version: "6.0.20" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.0.15" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.0.15" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.0" url_launcher_platform_interface: dependency: transitive description: @@ -914,21 +989,21 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.8" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.0" uuid: dependency: transitive description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" vector_math: dependency: transitive description: @@ -942,28 +1017,42 @@ packages: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.2.10" + version: "2.2.18" + video_player_android: + dependency: transitive + description: + name: video_player_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "5.0.1" + version: "5.1.0" video_player_web: dependency: transitive description: name: video_player_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.7" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.3.0" + version: "7.5.0" watcher: dependency: transitive description: @@ -991,14 +1080,14 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.3.3" + version: "2.4.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.0+1" xml: dependency: transitive description: @@ -1022,4 +1111,4 @@ packages: version: "8.0.0" sdks: dart: ">=2.15.1 <3.0.0" - flutter: ">=2.5.3" + flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index b3d6963..5d125fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,10 +35,6 @@ dependencies: git: url: git://github.com/google/flutter-desktop-embedding.git path: plugins/file_selector/file_selector_macos - file_selector_windows: - git: - url: git://github.com/google/flutter-desktop-embedding.git - path: plugins/file_selector/file_selector_windows open_file: any # open file in mobile. crop: any unorm_dart: any diff --git a/src/account.rs b/src/account.rs index c1d2d72..1db897b 100644 --- a/src/account.rs +++ b/src/account.rs @@ -2,12 +2,14 @@ use rand::Rng; use serde::{Deserialize, Serialize}; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::{EventId, GroupId}, - primitive::{PeerId, Result}, + group::EventId, + primitives::{PeerId, PeerKey, Result}, }; -use tdn_did::{generate_id, Keypair, Language}; +use tdn_did::{generate_peer, Language}; use tdn_storage::local::{DStorage, DsValue}; +use esse_primitives::{id_from_str, id_to_str}; + use crate::utils::crypto::{ check_pin, decrypt, decrypt_key, encrypt_key, encrypt_multiple, hash_pin, }; @@ -45,7 +47,7 @@ pub fn lang_from_i64(u: i64) -> Language { pub(crate) struct Account { pub id: i64, - pub gid: GroupId, + pub pid: PeerId, pub index: i64, pub lang: i64, pub mnemonic: Vec, // encrypted value. @@ -56,7 +58,7 @@ pub(crate) struct Account { pub secret: Vec, // encrypted value. pub encrypt: Vec, // encrypted encrypt key. pub wallet: String, // main wallet info. - pub pub_height: i64, // public information height. + pub pub_height: u64, // public information height. pub own_height: u64, // own data consensus height. pub event: EventId, pub datetime: i64, @@ -65,7 +67,7 @@ pub(crate) struct Account { impl Account { pub fn new( - gid: GroupId, + pid: PeerId, index: i64, lang: i64, pass: String, @@ -89,7 +91,7 @@ impl Account { own_height: 0, wallet: String::new(), event: EventId::default(), - gid, + pid, index, lang, pass, @@ -117,8 +119,8 @@ impl Account { name: &str, lock: &str, avatar: Vec, - ) -> Result<(Account, Keypair)> { - let (gid, sk) = generate_id( + ) -> Result<(Account, PeerKey)> { + let sk = generate_peer( lang_from_i64(lang), mnemonic, index, @@ -128,15 +130,19 @@ impl Account { let key = rand::thread_rng().gen::<[u8; 32]>(); let ckey = encrypt_key(salt, lock, &key)?; - let mut ebytes = - encrypt_multiple(salt, lock, &ckey, vec![&sk.to_bytes(), mnemonic.as_bytes()])?; + let mut ebytes = encrypt_multiple( + salt, + lock, + &ckey, + vec![&sk.to_db_bytes(), mnemonic.as_bytes()], + )?; let mnemonic = ebytes.pop().unwrap_or(vec![]); let secret = ebytes.pop().unwrap_or(vec![]); let index = index as i64; Ok(( Account::new( - gid, + sk.peer_id(), index, lang, pass.to_string(), @@ -186,10 +192,10 @@ impl Account { String::from_utf8(pbytes).or(Err(anyhow!("mnemonic unlock invalid."))) } - pub fn secret(&self, salt: &[u8], lock: &str) -> Result { + pub fn secret(&self, salt: &[u8], lock: &str) -> Result { self.check_lock(lock)?; let pbytes = decrypt(salt, lock, &self.encrypt, &self.secret)?; - Keypair::from_bytes(&pbytes).or(Err(anyhow!("secret unlock invalid."))) + PeerKey::from_db_bytes(&pbytes).or(Err(anyhow!("secret unlock invalid."))) } /// here is zero-copy and unwrap is safe. checked. @@ -198,7 +204,7 @@ impl Account { datetime: v.pop().unwrap().as_i64(), event: EventId::from_hex(v.pop().unwrap().as_str()).unwrap_or(EventId::default()), own_height: v.pop().unwrap().as_i64() as u64, - pub_height: v.pop().unwrap().as_i64(), + pub_height: v.pop().unwrap().as_i64() as u64, wallet: v.pop().unwrap().as_string(), avatar: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), encrypt: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), @@ -209,16 +215,16 @@ impl Account { pass: v.pop().unwrap().as_string(), lang: v.pop().unwrap().as_i64(), index: v.pop().unwrap().as_i64(), - gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()), + pid: id_from_str(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), id: v.pop().unwrap().as_i64(), plainkey: vec![], } } - pub fn get(db: &DStorage, gid: &GroupId) -> Result { + pub fn get(db: &DStorage, pid: &PeerId) -> Result { let sql = format!( - "SELECT id, gid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts WHERE gid = '{}'", - gid.to_hex() + "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts WHERE pid = '{}'", + id_to_str(pid) ); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { @@ -231,7 +237,7 @@ impl Account { pub fn all(db: &DStorage) -> Result> { let matrix = db.query( - "SELECT id, gid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts ORDER BY datetime DESC", + "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts ORDER BY datetime DESC", )?; let mut accounts = vec![]; for values in matrix { @@ -242,16 +248,16 @@ impl Account { pub fn insert(&mut self, db: &DStorage) -> Result<()> { let mut unique_check = db.query(&format!( - "SELECT id from accounts WHERE gid = '{}'", - self.gid.to_hex() + "SELECT id from accounts WHERE pid = '{}'", + id_to_str(&self.pid) ))?; if unique_check.len() > 0 { let id = unique_check.pop().unwrap().pop().unwrap().as_i64(); self.id = id; self.update(db)?; } else { - let sql = format!("INSERT INTO accounts (gid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime) VALUES ('{}', {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', {}, {}, '{}', {})", - self.gid.to_hex(), + let sql = format!("INSERT INTO accounts (pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime) VALUES ('{}', {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', {}, {}, '{}', {})", + id_to_str(&self.pid), self.index, self.lang, self.pass, @@ -321,26 +327,17 @@ impl Account { #[derive(Serialize, Deserialize, Clone)] pub(crate) struct User { - pub id: GroupId, - pub addr: PeerId, + pub id: PeerId, pub name: String, pub wallet: String, - pub height: i64, + pub height: u64, pub avatar: Vec, } impl User { - pub fn new( - id: GroupId, - addr: PeerId, - name: String, - avatar: Vec, - wallet: String, - height: i64, - ) -> Self { + pub fn new(id: PeerId, name: String, avatar: Vec, wallet: String, height: u64) -> Self { Self { id, - addr, name, avatar, wallet, @@ -348,10 +345,9 @@ impl User { } } - pub fn info(name: String, wallet: String, height: i64, avatar: Vec) -> Self { + pub fn info(name: String, wallet: String, height: u64, avatar: Vec) -> Self { Self { - id: GroupId::default(), - addr: PeerId::default(), + id: PeerId::default(), name, wallet, height, diff --git a/src/apps.rs b/src/apps.rs index 98e8a32..f4ed69a 100644 --- a/src/apps.rs +++ b/src/apps.rs @@ -1,14 +1,20 @@ +use chat_types::CHAT_ID; +use cloud_types::CLOUD_ID; +use dao_types::DAO_ID; +use domain_types::DOMAIN_ID; +use group_types::{GroupChatId, GROUP_CHAT_ID}; +use std::collections::HashMap; use std::sync::Arc; use tdn::types::{ group::GroupId, message::RecvType, - primitive::{HandleResult, Result}, + primitives::{HandleResult, Result}, rpc::RpcHandler, }; -use tokio::sync::RwLock; -use crate::layer::Layer; -use crate::rpc::RpcState; +use crate::global::Global; +use crate::rpc::session_lost; +use crate::storage::group_db; pub(crate) mod chat; pub(crate) mod cloud; @@ -17,10 +23,10 @@ pub(crate) mod domain; pub(crate) mod file; pub(crate) mod group; pub(crate) mod jarvis; -//pub(crate) mod dao; pub(crate) mod wallet; +//pub(crate) mod dao; -pub(crate) fn app_rpc_inject(handler: &mut RpcHandler) { +pub(crate) fn app_rpc_inject(handler: &mut RpcHandler) { device::new_rpc_handler(handler); chat::new_rpc_handler(handler); jarvis::new_rpc_handler(handler); @@ -28,30 +34,75 @@ pub(crate) fn app_rpc_inject(handler: &mut RpcHandler) { file::new_rpc_handler(handler); group::new_rpc_handler(handler); wallet::new_rpc_handler(handler); - //dao::new_rpc_handler(handler); cloud::new_rpc_handler(handler); + //dao::new_rpc_handler(handler); } pub(crate) async fn app_layer_handle( - layer: &Arc>, fgid: GroupId, - mgid: GroupId, + tgid: GroupId, msg: RecvType, + global: &Arc, ) -> Result { - match (fgid, mgid) { - (group::GROUP_ID, _) => group::handle_peer(layer, mgid, msg).await, - (_, group::GROUP_ID) => group::handle_server(layer, fgid, msg).await, - //(dao::GROUP_ID, _) => dao::handle(layer, fgid, mgid, false, msg).await, - (domain::GROUP_ID, _) => domain::handle(layer, mgid, msg).await, - (cloud::GROUP_ID, _) => cloud::handle(layer, mgid, msg).await, - _ => chat::handle(layer, fgid, mgid, msg).await, - } -} + debug!("TODO GOT LAYER MESSAGE: ====== {} -> {} ===== ", fgid, tgid); + match (fgid, tgid) { + (CHAT_ID, 0) | (0, CHAT_ID) => chat::handle(msg, global).await, + (GROUP_CHAT_ID, 0) | (0, GROUP_CHAT_ID) => group::handle(msg, global).await, + (DOMAIN_ID, 0) | (0, DOMAIN_ID) => domain::handle(msg, global).await, + (CLOUD_ID, 0) | (0, CLOUD_ID) => cloud::handle(msg, global).await, + (DAO_ID, 0) | (0, DAO_ID) => chat::handle(msg, global).await, + _ => match msg { + RecvType::Leave(peer) => { + debug!("Peer leaved: {}", peer.id.to_hex()); + let mut results = HandleResult::new(); + let mut layer = global.layer.write().await; -pub(crate) fn _app_group_handle() -> Result { - todo!() -} + if let Some(session) = layer.chats.remove(&peer.id) { + results.rpcs.push(session_lost(&session.s_id)); + } + + let mut delete: HashMap> = HashMap::new(); + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = group_db(&global.base, &pid, &db_key)?; + + for (gid, session) in &layer.groups { + for (index, addr) in session.addrs.iter().enumerate() { + if addr == &peer.id { + delete + .entry(*gid) + .and_modify(|f| f.push(index)) + .or_insert(vec![index]); + if index == 0 { + results.rpcs.push(session_lost(&session.s_id)); + } else { + if let Ok(mid) = group::Member::get_id(&db, &session.db_id, addr) { + results + .rpcs + .push(group::rpc::member_offline(session.db_id, mid)); + } + } + } + } + } -pub(crate) fn _app_migrate() -> Result<()> { - todo!() + for (gid, mut indexs) in delete { + if indexs[0] == 0 { + let _ = layer.groups.remove(&gid); + } else { + indexs.reverse(); + for i in indexs { + let _ = layer.group_del_member(&gid, i); + } + } + } + + Ok(results) + } + _ => { + warn!("LAYER MISSING: {:?}", msg); + Err(anyhow!("nothing!")) + } + }, + } } diff --git a/src/apps/chat/layer.rs b/src/apps/chat/layer.rs index 93f4993..8f1f078 100644 --- a/src/apps/chat/layer.rs +++ b/src/apps/chat/layer.rs @@ -1,485 +1,348 @@ +use chat_types::{MessageType, NetworkMessage, CHAT_ID}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; use std::sync::Arc; use tdn::types::{ - group::{EventId, GroupId}, + group::EventId, message::{RecvType, SendType}, - primitive::{DeliveryType, HandleResult, Peer, PeerId, Result}, + primitives::{DeliveryType, HandleResult, Peer, PeerId, Result}, }; -use tdn_did::Proof; use tdn_storage::local::DStorage; -use tokio::sync::RwLock; - -use chat_types::{MessageType, NetworkMessage}; use crate::account::{Account, User}; -use crate::event::InnerEvent; -use crate::group::Group; -use crate::layer::{Layer, Online}; -use crate::migrate::consensus::{FRIEND_TABLE_PATH, MESSAGE_TABLE_PATH, REQUEST_TABLE_PATH}; +use crate::global::Global; use crate::rpc::{ notice_menu, session_connect, session_create, session_last, session_lost, session_suspend, session_update_name, }; use crate::session::{connect_session, Session, SessionType}; -use crate::storage::write_avatar_sync; +use crate::storage::{account_db, chat_db, session_db, write_avatar_sync}; -use super::models::{handle_nmsg, raw_to_network_message, Friend, Message, Request}; +use super::models::{handle_nmsg, Friend, Message, Request}; use super::rpc; /// Chat connect data structure. -/// params: Friend about me height, connect_proof. -#[derive(Serialize, Deserialize)] -pub struct LayerConnect(pub i64, pub Proof); +/// params: Friend about me height +//#[derive(Serialize, Deserialize)] +//pub struct LayerConnect(pub i64); /// ESSE chat layer Event. #[derive(Serialize, Deserialize)] pub(crate) enum LayerEvent { /// offline. extend BaseLayerEvent. - Offline(GroupId), + Offline, /// suspend. extend BaseLayerEvent. - Suspend(GroupId), + Suspend, /// actived. extend BaseLayerEvent. - Actived(GroupId), + Actived, /// make friendship request. - /// params is name, remark, proof. - Request(String, String, Proof), + /// params is name, remark. + Request(String, String), /// agree friendship request. /// params is gid. - Agree(Proof), + Agree, /// reject friendship request. Reject, /// receiver gid, sender gid, message. Message(EventId, NetworkMessage), /// request user info. - InfoReq(i64), + InfoReq(u64), /// user full info. InfoRes(User), /// close friendship. Close, } -pub(crate) async fn handle( - arc_layer: &Arc>, - fgid: GroupId, - mgid: GroupId, - msg: RecvType, -) -> Result { +pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { debug!("---------DEBUG--------- GOT CHAT EVENT"); let mut results = HandleResult::new(); - let mut layer = arc_layer.write().await; + let pid = global.pid().await; match msg { - RecvType::Leave(addr) => { - for (mgid, running) in &mut layer.runnings { - for sid in running.peer_leave(&addr) { - results.rpcs.push(session_lost(*mgid, &sid)); - } - } - } - RecvType::Connect(addr, data) | RecvType::ResultConnect(addr, data) => { + RecvType::Connect(peer, _) | RecvType::ResultConnect(peer, _) => { // ESSE chat layer connect date structure. - if let Ok(height) = - handle_connect(&mgid, &fgid, &addr, data, &mut layer, &mut results).await - { - let peer_id = addr.id; - let proof = layer.group.read().await.prove_addr(&mgid, &addr.id)?; - let data = bincode::serialize(&proof).unwrap_or(vec![]); - let msg = SendType::Result(0, addr, true, false, data); - results.layers.push((mgid, fgid, msg)); + if let Ok(height) = handle_connect(pid, &peer, global, &mut results).await { + let peer_id = peer.id; + let msg = SendType::Result(0, peer, true, false, vec![]); + results.layers.push((CHAT_ID, msg)); let info = LayerEvent::InfoReq(height); let data = bincode::serialize(&info).unwrap_or(vec![]); let msg = SendType::Event(0, peer_id, data); - results.layers.push((mgid, fgid, msg)); + results.layers.push((CHAT_ID, msg)); } else { - let msg = SendType::Result(0, addr, false, false, vec![]); - results.layers.push((mgid, fgid, msg)); + let msg = SendType::Result(0, peer, false, false, vec![]); + results.layers.push((CHAT_ID, msg)); } } - RecvType::Result(addr, is_ok, data) => { + RecvType::Result(peer, is_ok, _) => { // ESSE chat layer result date structure. if is_ok { - if let Ok(height) = - handle_connect(&mgid, &fgid, &addr, data, &mut layer, &mut results).await - { + if let Ok(height) = handle_connect(pid, &peer, global, &mut results).await { let info = LayerEvent::InfoReq(height); let data = bincode::serialize(&info).unwrap_or(vec![]); - let msg = SendType::Event(0, addr.id, data); - results.layers.push((mgid, fgid, msg)); + let msg = SendType::Event(0, peer.id, data); + results.layers.push((CHAT_ID, msg)); } else { - let msg = SendType::Result(0, addr, false, false, vec![]); - results.layers.push((mgid, fgid, msg)); + let msg = SendType::Result(0, peer, false, false, vec![]); + results.layers.push((CHAT_ID, msg)); } } else { - let db = layer.group.read().await.chat_db(&mgid)?; - let friend = Friend::get_id(&db, &fgid)?; - if friend.contains_addr(&addr.id) { - results.rpcs.push(rpc::friend_close(mgid, friend.id)); - friend.close(&db)?; - } + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + let friend = Friend::get_id(&db, &peer.id)?; + results.rpcs.push(rpc::friend_close(friend.id)); + friend.close(&db)?; } } - RecvType::Event(addr, bytes) => { - return LayerEvent::handle(fgid, mgid, &mut layer, addr, bytes).await; - } - RecvType::Stream(_uid, _stream, _bytes) => { - // TODO stream + RecvType::Event(fpid, bytes) => { + return LayerEvent::handle(pid, fpid, global, bytes).await; } RecvType::Delivery(t, tid, is_ok) => { - debug!("delivery: tid: {}, is_ok: {}", tid, is_ok); - // TODO maybe send failure need handle. - if is_ok { - if let Some((gid, db_id)) = layer.delivery.remove(&tid) { - let db = layer.group.read().await.chat_db(&mgid)?; - let resp = match t { - DeliveryType::Event => { - Message::delivery(&db, db_id, true)?; - rpc::message_delivery(gid, db_id, true) - } - DeliveryType::Connect => { - // request. - Request::delivery(&db, db_id, true)?; - rpc::request_delivery(gid, db_id, true) - } - DeliveryType::Result => { - // response. TODO better for it. - Request::delivery(&db, db_id, true)?; - rpc::request_delivery(gid, db_id, true) - } - }; - drop(db); - results.rpcs.push(resp); + let mut layer = global.layer.write().await; + let id = layer.delivery.remove(&tid).ok_or(anyhow!("delivery err"))?; + drop(layer); + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + let resp = match t { + DeliveryType::Event => { + Message::delivery(&db, id, is_ok)?; + rpc::message_delivery(id, is_ok) } - } + DeliveryType::Connect => { + // request. + Request::delivery(&db, id, is_ok)?; + rpc::request_delivery(id, is_ok) + } + DeliveryType::Result => { + // response. TODO better for agree send. + Request::delivery(&db, id, is_ok)?; + rpc::request_delivery(id, is_ok) + } + }; + drop(db); + results.rpcs.push(resp); + } + RecvType::Stream(_uid, _stream, _bytes) => { + // TODO stream } + RecvType::Leave(..) => {} // nerver here. } Ok(results) } async fn handle_connect( - mgid: &GroupId, - fgid: &GroupId, - addr: &Peer, - data: Vec, - layer: &mut Layer, + pid: PeerId, + peer: &Peer, + global: &Arc, results: &mut HandleResult, -) -> Result { - // 0. deserialize connect data. - let proof: Proof = bincode::deserialize(&data)?; +) -> Result { + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; - // 1. check verify. - proof.verify(fgid, &addr.id, &layer.addr)?; - - // 2. check friendship. - let friend = update_friend(&layer.group.read().await.chat_db(mgid)?, fgid, &addr.id); + // 1. check friendship. + let friend = Friend::get_id(&db, &peer.id); if friend.is_err() { return Err(anyhow!("not friend")); } let f = friend.unwrap(); // safe. - // 3. get session. - let session_some = connect_session( - &layer.group.read().await.session_db(mgid)?, - &SessionType::Chat, - &f.id, - &addr.id, - )?; + // 2. get session. + let s_db = session_db(&global.base, &pid, &db_key)?; + let session_some = connect_session(&s_db, &SessionType::Chat, &f.id, &peer.id)?; if session_some.is_none() { return Err(anyhow!("not friend")); } let sid = session_some.unwrap().id; + // 3. session online to UI. + results.rpcs.push(session_connect(&sid, &peer.id)); + // 4. active this session. - layer - .running_mut(mgid)? - .check_add_online(*fgid, Online::Direct(addr.id), sid, f.id)?; + global.layer.write().await.chat_add(peer.id, sid, f.id, 0); - // 5. session online to UI. - results.rpcs.push(session_connect(*mgid, &sid, &addr.id)); - Ok(f.height) + Ok(f.height as u64) } impl LayerEvent { pub async fn handle( - fgid: GroupId, - mgid: GroupId, - layer: &mut Layer, - addr: PeerId, + pid: PeerId, + fpid: PeerId, + global: &Arc, bytes: Vec, ) -> Result { let event: LayerEvent = bincode::deserialize(&bytes)?; let mut results = HandleResult::new(); match event { - LayerEvent::Offline(_) => { - let (sid, _fid) = layer.get_running_remote_id(&mgid, &fgid)?; - layer.running_mut(&mgid)?.check_offline(&fgid, &addr); - results.rpcs.push(session_lost(mgid, &sid)); + LayerEvent::Offline => { + let mut layer = global.layer.write().await; + let (sid, _fid) = layer.chat_session(&fpid)?; + let _ = layer.chat_rm_online(&fpid); + results.rpcs.push(session_lost(&sid)); } - LayerEvent::Suspend(_) => { - let (sid, _fid) = layer.get_running_remote_id(&mgid, &fgid)?; - if layer.running_mut(&mgid)?.suspend(&fgid, false, false)? { - results.rpcs.push(session_suspend(mgid, &sid)); - } + LayerEvent::Suspend => { + let mut layer = global.layer.write().await; + let (sid, _fid) = layer.chat_session(&fpid)?; + let _ = layer.chat_suspend(&fpid, false, false)?; + results.rpcs.push(session_suspend(&sid)); } - LayerEvent::Actived(_) => { - let (sid, _fid) = layer.get_running_remote_id(&mgid, &fgid)?; - let _ = layer.running_mut(&mgid)?.active(&fgid, false); - results.rpcs.push(session_connect(mgid, &sid, &addr)); + LayerEvent::Actived => { + let mut layer = global.layer.write().await; + let (sid, _fid) = layer.chat_session(&fpid)?; + let _ = layer.chat_active(&fpid, false); + results.rpcs.push(session_connect(&sid, &fpid)); } - LayerEvent::Request(name, remark, proof) => { - // 1. check verify. - proof.verify(&fgid, &addr, &layer.addr)?; + LayerEvent::Request(name, remark) => { + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; - if load_friend(&layer.group.read().await.chat_db(&mgid)?, &fgid).is_err() { + if Friend::get_id(&db, &fpid).is_err() { // check if exist request. - let db = layer.group.read().await.chat_db(&mgid)?; - if let Ok(req) = Request::get_id(&db, &fgid) { + if let Ok(req) = Request::get_id(&db, &fpid) { Request::delete(&db, &req.id)?; // delete the old request. - results.rpcs.push(rpc::request_delete(mgid, req.id)); + results.rpcs.push(rpc::request_delete(req.id)); } - let mut request = Request::new(fgid, addr, name, remark, false, true); + let mut request = Request::new(fpid, name, remark, false, true); // save to db. request.insert(&db)?; drop(db); - results.rpcs.push(rpc::request_create(mgid, &request)); - results.rpcs.push(notice_menu(mgid, &SessionType::Chat)); + results.rpcs.push(rpc::request_create(&request)); + results.rpcs.push(notice_menu(&SessionType::Chat)); return Ok(results); } else { - let proof = layer.group.read().await.prove_addr(&mgid, &addr)?; - let msg = agree_message(proof, addr)?; - results.layers.push((mgid, fgid, msg)); + let data = bincode::serialize(&LayerEvent::Agree).unwrap_or(vec![]); + let msg = SendType::Event(0, fpid, data); + results.layers.push((CHAT_ID, msg)); } } - LayerEvent::Agree(proof) => { - // 0. check verify. - proof.verify(&fgid, &addr, &layer.addr)?; + LayerEvent::Agree => { + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + // 1. check friendship. - if load_friend(&layer.group.read().await.chat_db(&mgid)?, &fgid).is_err() { + if Friend::get_id(&db, &fpid).is_err() { // 2. agree request for friend. - let db = layer.group.read().await.chat_db(&mgid)?; - if let Ok(mut r) = Request::get_id(&db, &fgid) { + if let Ok(mut r) = Request::get_id(&db, &fpid) { r.is_over = true; r.is_ok = true; r.update(&db)?; - let friend = Friend::from_remote(&db, fgid, r.name, addr, "".to_owned())?; - results.rpcs.push(rpc::request_agree(mgid, r.id, &friend)); + let friend = Friend::from_remote(&db, fpid, r.name, "".to_owned())?; + results.rpcs.push(rpc::request_agree(r.id, &friend)); // ADD NEW SESSION. - let s_db = layer.group.read().await.session_db(&mgid)?; + let s_db = session_db(&global.base, &pid, &db_key)?; let mut session = friend.to_session(); session.insert(&s_db)?; - results.rpcs.push(session_create(mgid, &session)); + results.rpcs.push(session_create(&session)); } drop(db); } } LayerEvent::Reject => { - let db = layer.group.read().await.chat_db(&mgid)?; - if let Ok(mut request) = Request::get_id(&db, &fgid) { - layer.group.write().await.broadcast( - &mgid, - InnerEvent::SessionRequestHandle(request.gid, false, vec![]), - REQUEST_TABLE_PATH, - request.id, - &mut results, - )?; + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + + if let Ok(mut request) = Request::get_id(&db, &fpid) { request.is_over = true; request.is_ok = false; request.update(&db)?; - results.rpcs.push(rpc::request_reject(mgid, request.id)); + results.rpcs.push(rpc::request_reject(request.id)); } - drop(db); } LayerEvent::Message(hash, m) => { - let (_sid, fid) = layer.get_running_remote_id(&mgid, &fgid)?; - let db = layer.group.read().await.chat_db(&mgid)?; + let (_sid, fid) = global.layer.read().await.chat_session(&fpid)?; + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + if !Message::exist(&db, &hash)? { let msg = handle_nmsg( - &layer.group, + &pid, + &global.base, + &db_key, m.clone(), false, - mgid, - &layer.base, &db, fid, hash, &mut results, ) .await?; - layer.group.write().await.broadcast( - &mgid, - InnerEvent::SessionMessageCreate(fgid, false, hash, m), - MESSAGE_TABLE_PATH, - msg.id, - &mut results, - )?; - results.rpcs.push(rpc::message_create(mgid, &msg)); + results.rpcs.push(rpc::message_create(&msg)); // UPDATE SESSION. - if let Ok(s_db) = layer.group.read().await.session_db(&mgid) { - update_session(&s_db, &mgid, &fid, &msg, &mut results); - } + let s_db = session_db(&global.base, &pid, &db_key)?; + update_session(&s_db, &fid, &msg, &mut results); } } LayerEvent::InfoReq(height) => { // check sync remote height. - if let Ok(account) = Account::get(&layer.group.read().await.account_db()?, &mgid) { - if account.pub_height > height { - let info = LayerEvent::InfoRes(User::info( - account.name, - account.wallet, - account.pub_height, - account.avatar, - )); - let data = bincode::serialize(&info).unwrap_or(vec![]); - let msg = SendType::Event(0, addr, data); - results.layers.push((mgid, fgid, msg)); - } + let a_db = account_db(&global.base, &global.secret)?; + let account = Account::get(&a_db, &pid)?; + if account.pub_height > height { + let info = LayerEvent::InfoRes(User::info( + account.name, + account.wallet, + account.pub_height, + account.avatar, + )); + let data = bincode::serialize(&info).unwrap_or(vec![]); + let msg = SendType::Event(0, fpid, data); + results.layers.push((CHAT_ID, msg)); } } LayerEvent::InfoRes(remote) => { - let (sid, fid) = layer.get_running_remote_id(&mgid, &fgid)?; - let avatar = remote.avatar.clone(); - let db = layer.group.read().await.chat_db(&mgid)?; + let (sid, fid) = global.layer.read().await.chat_session(&fpid)?; + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + let mut f = Friend::get(&db, &fid)?; let name = remote.name.clone(); f.name = remote.name; f.wallet = remote.wallet; - f.height = remote.height; + f.height = remote.height as i64; f.remote_update(&db)?; drop(db); - write_avatar_sync(&layer.base, &mgid, &remote.id, remote.avatar)?; - results.rpcs.push(rpc::friend_info(mgid, &f)); - let _ = - Session::update_name(&layer.group.read().await.session_db(&mgid)?, &sid, &name); - results.rpcs.push(session_update_name(mgid, &sid, &name)); + write_avatar_sync(&global.base, &pid, &remote.id, remote.avatar)?; + results.rpcs.push(rpc::friend_info(&f)); - layer.group.write().await.broadcast( - &mgid, - InnerEvent::SessionFriendInfo(f.gid, f.addr, f.name.clone(), avatar), - FRIEND_TABLE_PATH, - f.id, - &mut results, - )?; + let s_db = session_db(&global.base, &pid, &db_key)?; + let _ = Session::update_name(&s_db, &sid, &name); + results.rpcs.push(session_update_name(&sid, &name)); } LayerEvent::Close => { - let (_sid, fid) = layer.get_running_remote_id(&mgid, &fgid)?; - layer.group.write().await.broadcast( - &mgid, - InnerEvent::SessionFriendClose(fgid), - FRIEND_TABLE_PATH, - fid, - &mut results, - )?; - layer.remove_online(&mgid, &fgid); - let db = layer.group.read().await.chat_db(&mgid)?; + let mut layer = global.layer.write().await; + let _ = layer.chat_rm_online(&fpid); + let (sid, fid) = global.layer.read().await.chat_session(&fpid)?; + let keep = layer.is_addr_online(&fpid); + drop(layer); + + let db_key = global.group.read().await.db_key(&pid)?; + let db = chat_db(&global.base, &pid, &db_key)?; + Friend::id_close(&db, fid)?; drop(db); - results.rpcs.push(rpc::friend_close(mgid, fid)); - if !layer.is_addr_online(&addr) { - results - .layers - .push((mgid, fgid, SendType::Disconnect(addr))) + results.rpcs.push(rpc::friend_close(fid)); + if !keep { + results.layers.push((CHAT_ID, SendType::Disconnect(fpid))) } + // TODO close session } } Ok(results) } - - pub async fn from_message( - group: &Arc>, - base: &PathBuf, - mgid: GroupId, - fid: i64, - m_type: MessageType, - content: &str, - ) -> std::result::Result<(Message, NetworkMessage), tdn::types::rpc::RpcError> { - // handle message's type. - let db = group.read().await.chat_db(&mgid)?; - let (nm_type, raw) = raw_to_network_message(group, base, &mgid, &m_type, content).await?; - let mut msg = Message::new(&mgid, fid, true, m_type, raw, false); - msg.insert(&db)?; - Ok((msg, nm_type)) - } -} - -#[inline] -fn load_friend(db: &DStorage, fgid: &GroupId) -> Result { - Friend::get_id(&db, fgid) } -#[inline] -fn update_friend(db: &DStorage, fgid: &GroupId, addr: &PeerId) -> Result { - let friend = Friend::get_id(&db, fgid)?; - if &friend.addr != addr { - let _ = Friend::addr_update(&db, friend.id, addr); - } - Ok(friend) -} - -pub(super) fn req_message( - layer: &mut Layer, - gid: GroupId, - name: String, - proof: Proof, - request: Request, -) -> SendType { - // update delivery. - let uid = layer.delivery.len() as u64 + 1; - layer.delivery.insert(uid, (gid, request.id)); - let req = LayerEvent::Request(name, request.remark, proof); - let data = bincode::serialize(&req).unwrap_or(vec![]); - SendType::Event(uid, request.addr, data) -} - -pub(super) fn reject_message(layer: &mut Layer, tid: i64, addr: PeerId, gid: GroupId) -> SendType { - let data = bincode::serialize(&LayerEvent::Reject).unwrap_or(vec![]); - let uid = layer.delivery.len() as u64 + 1; - layer.delivery.insert(uid, (gid, tid)); - SendType::Event(uid, addr, data) -} - -pub(crate) fn event_message( - layer: &mut Layer, - tid: i64, - me_id: GroupId, - addr: PeerId, - event: &LayerEvent, -) -> SendType { - let data = bincode::serialize(event).unwrap_or(vec![]); - let uid = layer.delivery.len() as u64 + 1; - layer.delivery.insert(uid, (me_id, tid)); - SendType::Event(uid, addr, data) -} - -pub(crate) fn chat_conn(proof: Proof, addr: Peer) -> SendType { - let data = bincode::serialize(&proof).unwrap_or(vec![]); - SendType::Connect(0, addr, data) -} - -pub(super) fn agree_message(proof: Proof, addr: PeerId) -> Result { - let data = bincode::serialize(&LayerEvent::Agree(proof)).unwrap_or(vec![]); - Ok(SendType::Event(0, addr, data)) -} - -// maybe need if gid or addr in blocklist. -fn _res_reject() -> Vec { - bincode::serialize(&LayerEvent::Reject).unwrap_or(vec![]) +pub(crate) fn chat_conn(pid: PeerId, results: &mut HandleResult) { + results + .layers + .push((CHAT_ID, SendType::Connect(0, Peer::peer(pid), vec![]))); } // UPDATE SESSION. -pub(crate) fn update_session( - s_db: &DStorage, - gid: &GroupId, - id: &i64, - msg: &Message, - results: &mut HandleResult, -) { +pub(crate) fn update_session(s_db: &DStorage, id: &i64, msg: &Message, results: &mut HandleResult) { let scontent = match msg.m_type { MessageType::String => { format!("{}:{}", msg.m_type.to_int(), msg.content) @@ -497,6 +360,6 @@ pub(crate) fn update_session( ) { results .rpcs - .push(session_last(*gid, &sid, &msg.datetime, &scontent, false)); + .push(session_last(&sid, &msg.datetime, &scontent, false)); } } diff --git a/src/apps/chat/mod.rs b/src/apps/chat/mod.rs index d5e3e8c..43adf82 100644 --- a/src/apps/chat/mod.rs +++ b/src/apps/chat/mod.rs @@ -2,9 +2,7 @@ mod layer; mod models; pub(crate) mod rpc; -pub(crate) use layer::handle; -pub(crate) use layer::LayerEvent; -pub(crate) use layer::{chat_conn, event_message, update_session}; +pub(crate) use layer::{chat_conn, handle, update_session, LayerEvent}; pub(crate) use models::{ from_model, from_network_message, raw_to_network_message, to_network_message, Friend, InviteType, Message, Request, diff --git a/src/apps/chat/models.rs b/src/apps/chat/models.rs index f752160..1fc641f 100644 --- a/src/apps/chat/models.rs +++ b/src/apps/chat/models.rs @@ -7,44 +7,40 @@ pub(crate) use self::message::{from_model, handle_nmsg, Message}; pub(crate) use self::request::Request; use chat_types::{MessageType, NetworkMessage}; +use esse_primitives::{id_from_str, id_to_str}; +use group_types::GroupChatId; use std::path::PathBuf; -use std::sync::Arc; -use tdn::types::{ - group::GroupId, - primitive::{HandleResult, PeerId, Result}, -}; -use tokio::sync::RwLock; +use tdn::types::primitives::{HandleResult, PeerId, Result}; -use crate::apps::group::GroupChat; -use crate::group::Group; +//use crate::apps::group::GroupChat; use crate::rpc::session_create; use crate::storage::{ - read_avatar, read_db_file, read_file, read_image, read_record, write_avatar_sync, write_file, - write_file_sync, write_image, write_image_sync, write_record_sync, + chat_db, group_db, read_avatar, read_db_file, read_file, read_image, read_record, session_db, + write_avatar_sync, write_file, write_file_sync, write_image, write_image_sync, + write_record_sync, }; pub(crate) async fn from_network_message( - group: &Arc>, - nmsg: NetworkMessage, + own: &PeerId, base: &PathBuf, - ogid: &GroupId, + db_key: &str, + nmsg: NetworkMessage, results: &mut HandleResult, ) -> Result<(MessageType, String)> { match nmsg { NetworkMessage::String(content) => Ok((MessageType::String, content)), NetworkMessage::Transfer(content) => Ok((MessageType::Transfer, content)), NetworkMessage::Image(bytes) => { - let image_name = write_image_sync(base, ogid, bytes)?; + let image_name = write_image_sync(base, own, bytes)?; Ok((MessageType::Image, image_name)) } NetworkMessage::File(old_name, bytes) => { - let filename = write_file_sync(base, ogid, &old_name, bytes)?; + let filename = write_file_sync(base, own, &old_name, bytes)?; Ok((MessageType::File, filename)) } - NetworkMessage::Contact(name, rgid, addr, avatar_bytes) => { - write_avatar_sync(base, ogid, &rgid, avatar_bytes)?; - let tmp_name = name.replace(";", "-;"); - let contact_values = format!("{};;{};;{}", tmp_name, rgid.to_hex(), addr.to_hex()); + NetworkMessage::Contact(pid, name, avatar_bytes) => { + write_avatar_sync(base, own, &pid, avatar_bytes)?; + let contact_values = format!("{};;{}", id_to_str(&pid), name); Ok((MessageType::Contact, contact_values)) } NetworkMessage::Emoji => { @@ -52,7 +48,7 @@ pub(crate) async fn from_network_message( Ok((MessageType::Emoji, "".to_owned())) } NetworkMessage::Record(bytes, time) => { - let record_name = write_record_sync(base, ogid, time, bytes)?; + let record_name = write_record_sync(base, own, time, bytes)?; Ok((MessageType::Record, record_name)) } NetworkMessage::Invite(content) => { @@ -61,15 +57,15 @@ pub(crate) async fn from_network_message( match itype { InviteType::Group(gcd, addr, name) => { // 1 add group chat. - let db = group.read().await.group_db(&ogid)?; - let mut g = GroupChat::from(gcd, 0, addr, name); - g.insert(&db)?; + let db = group_db(base, own, db_key)?; + //let mut g = GroupChat::from(gcd, 0, addr, name); + //g.insert(&db)?; // 2 add new session. - let mut session = g.to_session(); - let s_db = group.read().await.session_db(&ogid)?; - session.insert(&s_db)?; - results.rpcs.push(session_create(*ogid, &session)); + //let mut session = g.to_session(); + //let s_db = session_db(base, own, db_key)?; + //session.insert(&s_db)?; + //results.rpcs.push(session_create(&session)); } } @@ -87,9 +83,9 @@ pub(crate) async fn from_network_message( } pub(crate) async fn raw_to_network_message( - group: &Arc>, + own: &PeerId, base: &PathBuf, - ogid: &GroupId, + db_key: &str, mtype: &MessageType, content: &str, ) -> Result<(NetworkMessage, String)> { @@ -100,7 +96,7 @@ pub(crate) async fn raw_to_network_message( )), MessageType::Image => { let bytes = read_file(&PathBuf::from(content)).await?; - let image_name = write_image(base, ogid, &bytes).await?; + let image_name = write_image(base, own, &bytes).await?; Ok((NetworkMessage::Image(bytes), image_name)) } MessageType::File => { @@ -111,31 +107,25 @@ pub(crate) async fn raw_to_network_message( .and_then(|s| s.to_str()) .unwrap_or("") .to_owned(); - let filename = write_file(base, ogid, &old_name, &bytes).await?; + let filename = write_file(base, own, &old_name, &bytes).await?; Ok((NetworkMessage::File(filename.clone(), bytes), filename)) } MessageType::Contact => { let cid: i64 = content.parse()?; - let db = group.read().await.chat_db(ogid)?; + let db = chat_db(base, own, db_key)?; let contact = Friend::get(&db, &cid)?; drop(db); - let avatar_bytes = read_avatar(base, ogid, &contact.gid).await?; - let tmp_name = contact.name.replace(";", "-;"); - let contact_values = format!( - "{};;{};;{}", - tmp_name, - contact.gid.to_hex(), - contact.addr.to_hex() - ); + let avatar_bytes = read_avatar(base, own, &contact.pid).await?; + let contact_values = format!("{};;{}", id_to_str(&contact.pid), contact.name); Ok(( - NetworkMessage::Contact(contact.name, contact.gid, contact.addr, avatar_bytes), + NetworkMessage::Contact(contact.pid, contact.name, avatar_bytes), contact_values, )) } MessageType::Record => { let (bytes, time) = if let Some(i) = content.find('-') { let time = content[0..i].parse().unwrap_or(0); - let bytes = read_record(base, ogid, &content[i + 1..]).await?; + let bytes = read_record(base, own, &content[i + 1..]).await?; (bytes, time) } else { (vec![], 0) @@ -166,8 +156,8 @@ pub(crate) async fn raw_to_network_message( } pub(crate) async fn to_network_message( + own: &PeerId, base: &PathBuf, - gid: &GroupId, mtype: MessageType, content: String, ) -> Result { @@ -175,28 +165,28 @@ pub(crate) async fn to_network_message( match mtype { MessageType::String => Ok(NetworkMessage::String(content)), MessageType::Image => { - let bytes = read_image(base, gid, &content).await?; + let bytes = read_image(base, own, &content).await?; Ok(NetworkMessage::Image(bytes)) } MessageType::File => { - let bytes = read_db_file(base, gid, &content).await?; + let bytes = read_db_file(base, own, &content).await?; Ok(NetworkMessage::File(content, bytes)) } MessageType::Contact => { - let v: Vec<&str> = content.split(";;").collect(); - if v.len() != 3 { + let index = content.find(";;").ok_or(anyhow!("message is invalid"))?; + if content.len() < index + 2 { return Err(anyhow!("message is invalid")); } - let cname = v[0].to_owned(); - let cgid = GroupId::from_hex(v[1])?; - let caddr = PeerId::from_hex(v[2])?; - let avatar_bytes = read_avatar(base, gid, &cgid).await?; - Ok(NetworkMessage::Contact(cname, cgid, caddr, avatar_bytes)) + let cpid = id_from_str(&content[0..index])?; + let cname = content[index + 2..].to_owned(); + + let avatar_bytes = read_avatar(base, own, &cpid).await?; + Ok(NetworkMessage::Contact(cpid, cname, avatar_bytes)) } MessageType::Record => { let (bytes, time) = if let Some(i) = content.find('-') { let time = content[0..i].parse().unwrap_or(0); - let bytes = read_record(base, gid, &content[i + 1..]).await?; + let bytes = read_record(base, own, &content[i + 1..]).await?; (bytes, time) } else { (vec![], 0) @@ -211,25 +201,22 @@ pub(crate) async fn to_network_message( } } -pub(crate) async fn _clear_message( - _base: &PathBuf, - _ogid: &GroupId, - _mtype: &MessageType, - _content: &str, -) -> Result<()> { +/// clear a message. +pub(crate) async fn _clear_message() -> Result<()> { todo!() } /// Invite types. pub(crate) enum InviteType { - Group(GroupId, PeerId, String), + Group(GroupChatId, PeerId, String), } impl InviteType { pub fn serialize(&self) -> String { match self { - InviteType::Group(gcd, addr, name) => { - format!("0;;{};;{};;{}", gcd.to_hex(), addr.to_hex(), name) + InviteType::Group(gid, addr, name) => { + let gcd = hex::encode(&gid.to_le_bytes()); + format!("0;;{};;{};;{}", gcd, addr.to_hex(), name) } } } @@ -237,13 +224,16 @@ impl InviteType { pub fn deserialize(s: &str) -> Result { match &s[0..3] { "0;;" => { - if s.len() < 134 { + if s.len() < 103 { + // 16(gid) + 64(pid) + 7 Err(anyhow!("invite invalid")) } else { - let gcd = GroupId::from_hex(&s[3..67])?; - let addr = PeerId::from_hex(&s[69..133])?; - let name = s[135..].to_owned(); - Ok(InviteType::Group(gcd, addr, name)) + let mut gid_bytes = [0u8; 8]; + gid_bytes.copy_from_slice(&hex::decode(&s[3..19])?); + let gid = GroupChatId::from_le_bytes(gid_bytes); + let addr = PeerId::from_hex(&s[22..86])?; + let name = s[88..].to_owned(); + Ok(InviteType::Group(gid, addr, name)) } } _ => Err(anyhow!("invite invalid")), diff --git a/src/apps/chat/models/friend.rs b/src/apps/chat/models/friend.rs index c909c92..33ef7e6 100644 --- a/src/apps/chat/models/friend.rs +++ b/src/apps/chat/models/friend.rs @@ -1,7 +1,7 @@ +use esse_primitives::{id_from_str, id_to_str}; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::GroupId, - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; @@ -12,8 +12,7 @@ use super::Message; pub(crate) struct Friend { pub id: i64, - pub gid: GroupId, - pub addr: PeerId, + pub pid: PeerId, pub name: String, pub wallet: String, pub height: i64, @@ -23,14 +22,7 @@ pub(crate) struct Friend { } impl Friend { - pub fn new( - gid: GroupId, - addr: PeerId, - name: String, - wallet: String, - remark: String, - height: i64, - ) -> Friend { + pub fn new(pid: PeerId, name: String, wallet: String, remark: String, height: i64) -> Friend { let start = SystemTime::now(); let datetime = start .duration_since(UNIX_EPOCH) @@ -39,8 +31,7 @@ impl Friend { Friend { id: 0, - gid, - addr, + pid, name, wallet, height, @@ -50,10 +41,6 @@ impl Friend { } } - pub fn contains_addr(&self, addr: &PeerId) -> bool { - &self.addr == addr - } - /// here is zero-copy and unwrap is safe. fn from_values(mut v: Vec) -> Friend { Friend { @@ -63,28 +50,20 @@ impl Friend { height: v.pop().unwrap().as_i64(), wallet: v.pop().unwrap().as_string(), name: v.pop().unwrap().as_string(), - addr: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), - gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()), + pid: id_from_str(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), id: v.pop().unwrap().as_i64(), } } - pub fn from_remote( - db: &DStorage, - gid: GroupId, - name: String, - addr: PeerId, - wallet: String, - ) -> Result { - if let Ok(mut friend) = Friend::get_id(&db, &gid) { + pub fn from_remote(db: &DStorage, pid: PeerId, name: String, wallet: String) -> Result { + if let Ok(mut friend) = Friend::get_id(&db, &pid) { friend.name = name; - friend.addr = addr; friend.wallet = wallet; friend.is_closed = false; friend.remote_update(&db)?; Ok(friend) } else { - let mut friend = Friend::new(gid, addr, name, wallet, "".to_owned(), 0); + let mut friend = Friend::new(pid, name, wallet, "".to_owned(), 0); friend.insert(&db)?; Ok(friend) } @@ -93,8 +72,8 @@ impl Friend { pub fn to_session(&self) -> Session { Session::new( self.id, - self.gid, - self.addr, + id_to_str(&self.pid), + self.pid, SessionType::Chat, self.name.clone(), self.datetime, @@ -104,8 +83,7 @@ impl Friend { pub fn to_rpc(&self) -> RpcParam { json!([ self.id, - self.gid.to_hex(), - self.addr.to_hex(), + id_to_str(&self.pid), self.name, self.wallet, self.remark, @@ -117,8 +95,7 @@ impl Friend { pub fn to_rpc_online(&self, online: bool) -> RpcParam { json!([ self.id, - self.gid.to_hex(), - self.addr.to_hex(), + id_to_str(&self.pid), self.name, self.wallet, self.remark, @@ -128,8 +105,8 @@ impl Friend { ]) } - pub fn get_id(db: &DStorage, gid: &GroupId) -> Result { - let sql = format!("SELECT id, gid, addr, name, wallet, height, remark, is_closed, datetime FROM friends WHERE gid = '{}'", gid.to_hex()); + pub fn get_id(db: &DStorage, pid: &PeerId) -> Result { + let sql = format!("SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends WHERE pid = '{}'", id_to_str(pid)); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Friend::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -139,7 +116,7 @@ impl Friend { } pub fn get(db: &DStorage, id: &i64) -> Result { - let sql = format!("SELECT id, gid, addr, name, wallet, height, remark, is_closed, datetime FROM friends WHERE id = {}", id); + let sql = format!("SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends WHERE id = {}", id); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Friend::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -151,7 +128,7 @@ impl Friend { /// use in rpc when load account friends. pub fn list(db: &DStorage) -> Result> { let matrix = db.query( - "SELECT id, gid, addr, name, wallet, height, remark, is_closed, datetime FROM friends", + "SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends", )?; let mut friends = vec![]; for values in matrix { @@ -161,9 +138,8 @@ impl Friend { } pub fn insert(&mut self, db: &DStorage) -> Result<()> { - let sql = format!("INSERT INTO friends (gid, addr, name, wallet, height, remark, is_closed, datetime) VALUES ('{}', '{}', '{}', '{}', {}, '{}', {}, {})", - self.gid.to_hex(), - self.addr.to_hex(), + let sql = format!("INSERT INTO friends (pid, name, wallet, height, remark, is_closed, datetime) VALUES ('{}', '{}', '{}', {}, '{}', {}, {})", + id_to_str(&self.pid), self.name, self.wallet, self.height, @@ -177,8 +153,7 @@ impl Friend { } pub fn update(&self, db: &DStorage) -> Result { - let sql = format!("UPDATE friends SET addr = '{}', name = '{}', wallet = '{}', height={}, remark = '{}', is_closed = {} WHERE id = {}", - self.addr.to_hex(), + let sql = format!("UPDATE friends SET name = '{}', wallet = '{}', height={}, remark = '{}', is_closed = {} WHERE id = {}", self.name, self.wallet, self.height, @@ -197,23 +172,10 @@ impl Friend { db.update(&sql) } - pub fn addr_update(db: &DStorage, id: i64, addr: &PeerId) -> Result { - let sql = format!( - "UPDATE friends SET addr='{}' WHERE id = {}", - addr.to_hex(), - id, - ); - db.update(&sql) - } - pub fn remote_update(&self, db: &DStorage) -> Result { let sql = format!( - "UPDATE friends SET addr='{}', name='{}', wallet='{}', height={}, is_closed = false WHERE id = {}", - self.addr.to_hex(), - self.name, - self.wallet, - self.height, - self.id, + "UPDATE friends SET name='{}', wallet='{}', height={}, is_closed = false WHERE id = {}", + self.name, self.wallet, self.height, self.id, ); db.update(&sql) } @@ -235,10 +197,10 @@ impl Friend { Message::delete_by_fid(&db, id) } - pub fn is_friend(db: &DStorage, gid: &GroupId) -> Result { + pub fn is_friend(db: &DStorage, pid: &PeerId) -> Result { let sql = format!( - "SELECT id FROM friends WHERE is_closed = false and gid = '{}'", - gid.to_hex() + "SELECT id FROM friends WHERE is_closed = false and pid = '{}'", + id_to_str(pid) ); let matrix = db.query(&sql)?; Ok(matrix.len() > 0) diff --git a/src/apps/chat/models/message.rs b/src/apps/chat/models/message.rs index 312149e..8dbfe17 100644 --- a/src/apps/chat/models/message.rs +++ b/src/apps/chat/models/message.rs @@ -1,44 +1,39 @@ +use chat_types::{MessageType, NetworkMessage}; use std::path::PathBuf; -use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::{EventId, GroupId}, - primitive::{HandleResult, Result}, + group::EventId, + primitives::{HandleResult, PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; -use tokio::sync::RwLock; - -use chat_types::{MessageType, NetworkMessage}; - -use crate::group::Group; use super::{from_network_message, to_network_message}; pub(crate) async fn handle_nmsg( - group: &Arc>, + own: &PeerId, + base: &PathBuf, + db_key: &str, nmsg: NetworkMessage, is_me: bool, - gid: GroupId, - base: &PathBuf, db: &DStorage, fid: i64, hash: EventId, results: &mut HandleResult, ) -> Result { // handle event. - let (m_type, raw) = from_network_message(group, nmsg, base, &gid, results).await?; + let (m_type, raw) = from_network_message(own, base, db_key, nmsg, results).await?; let mut msg = Message::new_with_id(hash, fid, is_me, m_type, raw, true); msg.insert(db)?; Ok(msg) } pub(crate) async fn from_model( + own: &PeerId, base: &PathBuf, - gid: &GroupId, model: Message, ) -> Result { - to_network_message(base, gid, model.m_type, model.content).await + to_network_message(own, base, model.m_type, model.content).await } pub(crate) struct Message { @@ -54,7 +49,7 @@ pub(crate) struct Message { impl Message { pub fn new( - gid: &GroupId, + pid: &PeerId, fid: i64, is_me: bool, m_type: MessageType, @@ -68,7 +63,7 @@ impl Message { .unwrap_or(0) as i64; // safe for all life. let mut bytes = [0u8; 32]; - bytes[0..8].copy_from_slice(&gid.0[0..8]); + bytes[0..8].copy_from_slice(&pid.0[0..8]); bytes[8..16].copy_from_slice(&(fid as u64).to_le_bytes()); // 8-bytes. bytes[16..24].copy_from_slice(&(datetime as u64).to_le_bytes()); // 8-bytes. let content_bytes = content.as_bytes(); diff --git a/src/apps/chat/models/request.rs b/src/apps/chat/models/request.rs index c5be5b1..56bec98 100644 --- a/src/apps/chat/models/request.rs +++ b/src/apps/chat/models/request.rs @@ -1,7 +1,7 @@ +use esse_primitives::{id_from_str, id_to_str}; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::GroupId, - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; @@ -9,8 +9,7 @@ use tdn_storage::local::{DStorage, DsValue}; #[derive(Clone)] pub(crate) struct Request { pub id: i64, - pub gid: GroupId, - pub addr: PeerId, + pub pid: PeerId, pub name: String, pub remark: String, pub is_me: bool, @@ -22,8 +21,7 @@ pub(crate) struct Request { impl Request { pub fn new( - gid: GroupId, - addr: PeerId, + pid: PeerId, name: String, remark: String, is_me: bool, @@ -37,8 +35,7 @@ impl Request { Request { id: 0, - gid, - addr, + pid, name, remark, is_me, @@ -59,8 +56,7 @@ impl Request { is_me: v.pop().unwrap().as_bool(), remark: v.pop().unwrap().as_string(), name: v.pop().unwrap().as_string(), - addr: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), - gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()), + pid: id_from_str(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), id: v.pop().unwrap().as_i64(), } } @@ -68,8 +64,7 @@ impl Request { pub fn to_rpc(&self) -> RpcParam { json!([ self.id, - self.gid.to_hex(), - self.addr.to_hex(), + id_to_str(&self.pid), self.name, self.remark, self.is_me, @@ -80,8 +75,8 @@ impl Request { ]) } - pub fn get_id(db: &DStorage, gid: &GroupId) -> Result { - let sql = format!("SELECT id, gid, addr, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests WHERE gid = '{}'", gid.to_hex()); + pub fn get_id(db: &DStorage, pid: &PeerId) -> Result { + let sql = format!("SELECT id, pid, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests WHERE pid = '{}'", id_to_str(pid)); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Request::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -91,7 +86,7 @@ impl Request { } pub fn get(db: &DStorage, id: &i64) -> Result { - let sql = format!("SELECT id, gid, addr, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests WHERE id = {}", id); + let sql = format!("SELECT id, pid, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests WHERE id = {}", id); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Request::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -101,7 +96,7 @@ impl Request { } pub fn list(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, gid, addr, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests ORDER BY id DESC")?; + let matrix = db.query("SELECT id, pid, name, remark, is_me, is_ok, is_over, is_delivery, datetime FROM requests ORDER BY id DESC")?; let mut requests = vec![]; for values in matrix { requests.push(Request::from_values(values)); @@ -110,9 +105,8 @@ impl Request { } pub fn insert(&mut self, db: &DStorage) -> Result<()> { - let sql = format!("INSERT INTO requests (gid, addr, name, remark, is_me, is_ok, is_over, is_delivery, datetime) VALUES ('{}', '{}', '{}', '{}', {}, {}, {}, {}, {})", - self.gid.to_hex(), - self.addr.to_hex(), + let sql = format!("INSERT INTO requests (pid, name, remark, is_me, is_ok, is_over, is_delivery, datetime) VALUES ('{}', '{}', '{}', {}, {}, {}, {}, {})", + id_to_str(&self.pid), self.name, self.remark, self.is_me, @@ -127,9 +121,8 @@ impl Request { } pub fn update(&self, db: &DStorage) -> Result { - let sql = format!("UPDATE requests SET gid='{}', addr='{}', name='{}', remark='{}', is_me={}, is_ok={}, is_over={}, is_delivery={}, datetime={} WHERE id = {}", - self.gid.to_hex(), - self.addr.to_hex(), + let sql = format!("UPDATE requests SET pid='{}', name='{}', remark='{}', is_me={}, is_ok={}, is_over={}, is_delivery={}, datetime={} WHERE id = {}", + id_to_str(&self.pid), self.name, self.remark, self.is_me, diff --git a/src/apps/chat/rpc.rs b/src/apps/chat/rpc.rs index 091fe28..48d545b 100644 --- a/src/apps/chat/rpc.rs +++ b/src/apps/chat/rpc.rs @@ -1,80 +1,78 @@ -use std::collections::HashMap; +use chat_types::{MessageType, CHAT_ID}; +use esse_primitives::id_from_str; use std::sync::Arc; use tdn::types::{ - group::GroupId, message::SendType, - primitive::{HandleResult, PeerId}, + primitives::{HandleResult, PeerId}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; -use chat_types::MessageType; +//use crate::event::InnerEvent; +use crate::global::Global; +use crate::rpc::session_create; +use crate::storage::{chat_db, delete_avatar, session_db}; -use crate::event::InnerEvent; -use crate::migrate::consensus::{FRIEND_TABLE_PATH, MESSAGE_TABLE_PATH, REQUEST_TABLE_PATH}; -use crate::rpc::{session_create, sleep_waiting_close_stable, RpcState}; -use crate::storage::delete_avatar; - -use super::layer::{agree_message, reject_message, req_message, update_session, LayerEvent}; -use super::{Friend, Message, Request}; +use super::layer::{update_session, LayerEvent}; +use super::{raw_to_network_message, Friend, Message, Request}; #[inline] -pub(crate) fn friend_info(mgid: GroupId, friend: &Friend) -> RpcParam { - rpc_response(0, "chat-friend-info", json!(friend.to_rpc()), mgid) +pub(crate) fn friend_info(friend: &Friend) -> RpcParam { + rpc_response(0, "chat-friend-info", json!(friend.to_rpc())) } #[inline] -pub(crate) fn friend_update(mgid: GroupId, fid: i64, remark: &str) -> RpcParam { - rpc_response(0, "chat-friend-update", json!([fid, remark]), mgid) +pub(crate) fn friend_update(fid: i64, remark: &str) -> RpcParam { + rpc_response(0, "chat-friend-update", json!([fid, remark])) } #[inline] -pub(crate) fn friend_close(mgid: GroupId, fid: i64) -> RpcParam { - rpc_response(0, "chat-friend-close", json!([fid]), mgid) +pub(crate) fn friend_close(fid: i64) -> RpcParam { + rpc_response(0, "chat-friend-close", json!([fid])) } #[inline] -pub(crate) fn friend_delete(mgid: GroupId, fid: i64) -> RpcParam { - rpc_response(0, "chat-friend-delete", json!([fid]), mgid) +pub(crate) fn friend_delete(fid: i64) -> RpcParam { + rpc_response(0, "chat-friend-delete", json!([fid])) } #[inline] -pub(crate) fn request_create(mgid: GroupId, req: &Request) -> RpcParam { - rpc_response(0, "chat-request-create", json!(req.to_rpc()), mgid) +pub(crate) fn request_create(req: &Request) -> RpcParam { + rpc_response(0, "chat-request-create", json!(req.to_rpc())) } #[inline] -pub(crate) fn request_delivery(mgid: GroupId, id: i64, is_d: bool) -> RpcParam { - rpc_response(0, "chat-request-delivery", json!([id, is_d]), mgid) +pub(crate) fn request_delivery(id: i64, is_d: bool) -> RpcParam { + rpc_response(0, "chat-request-delivery", json!([id, is_d])) } #[inline] -pub(crate) fn request_agree(mgid: GroupId, id: i64, friend: &Friend) -> RpcParam { - rpc_response(0, "chat-request-agree", json!([id, friend.to_rpc()]), mgid) +pub(crate) fn request_agree(id: i64, friend: &Friend) -> RpcParam { + rpc_response(0, "chat-request-agree", json!([id, friend.to_rpc()])) } #[inline] -pub(crate) fn request_reject(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "chat-request-reject", json!([id]), mgid) +pub(crate) fn request_reject(id: i64) -> RpcParam { + rpc_response(0, "chat-request-reject", json!([id])) } #[inline] -pub(crate) fn request_delete(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "chat-request-delete", json!([id]), mgid) +pub(crate) fn request_delete(id: i64) -> RpcParam { + rpc_response(0, "chat-request-delete", json!([id])) } #[inline] -pub(crate) fn message_create(mgid: GroupId, msg: &Message) -> RpcParam { - rpc_response(0, "chat-message-create", json!(msg.to_rpc()), mgid) +pub(crate) fn message_create(msg: &Message) -> RpcParam { + rpc_response(0, "chat-message-create", json!(msg.to_rpc())) } #[inline] -pub(crate) fn message_delivery(mgid: GroupId, id: i64, is_d: bool) -> RpcParam { - rpc_response(0, "chat-message-delivery", json!([id, is_d]), mgid) +pub(crate) fn message_delivery(id: i64, is_d: bool) -> RpcParam { + rpc_response(0, "chat-message-delivery", json!([id, is_d])) } #[inline] -pub(crate) fn message_delete(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "chat-message-delete", json!([id]), mgid) +pub(crate) fn message_delete(id: i64) -> RpcParam { + rpc_response(0, "chat-message-delete", json!([id])) } #[inline] @@ -104,24 +102,27 @@ fn detail_list(friend: Friend, messages: Vec) -> RpcParam { json!([friend.to_rpc(), message_results]) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { - handler.add_method("chat-echo", |_, params, _| async move { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { + handler.add_method("chat-echo", |params, _| async move { Ok(HandleResult::rpc(json!(params))) }); handler.add_method( "chat-friend-list", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let need_online = params[0].as_bool().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let friends = Friend::list(&db)?; let mut results = vec![]; let layer_lock = state.layer.read().await; if need_online { for friend in friends { - let online = layer_lock.is_online(&gid, &friend.gid); + let online = layer_lock.chat_is_online(&friend.pid); results.push(friend.to_rpc_online(online)); } } else { @@ -137,59 +138,65 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-friend-update", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let remark = params[1].as_str().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let mut f = Friend::get(&db, &id)?; f.remark = remark.to_owned(); f.me_update(&db)?; drop(db); - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionFriendUpdate(f.gid, f.remark), - FRIEND_TABLE_PATH, - f.id, - &mut results, - )?; + + // state.group.write().await.broadcast( + // &gid, + // InnerEvent::SessionFriendUpdate(f.gid, f.remark), + // FRIEND_TABLE_PATH, + // f.id, + // &mut results, + // )?; + Ok(results) }, ); handler.add_method( "chat-friend-close", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; - let db = state.group.read().await.chat_db(&gid)?; let friend = Friend::get(&db, &id)?; friend.close(&db)?; drop(db); - let online = state.layer.write().await.remove_online(&gid, &friend.gid); - + let online = state.layer.write().await.chat_rm_online(&friend.pid); if let Some(faddr) = online { - let mut addrs: HashMap = HashMap::new(); - addrs.insert(faddr, friend.gid); - let sender = state.group.read().await.sender(); - tokio::spawn(sleep_waiting_close_stable(sender, HashMap::new(), addrs)); + let data = bincode::serialize(&LayerEvent::Close)?; + results + .layers + .push((CHAT_ID, SendType::Event(0, friend.pid, data))); + + results + .layers + .push((CHAT_ID, SendType::Disconnect(friend.pid))); } - let data = bincode::serialize(&LayerEvent::Close)?; - let msg = SendType::Event(0, friend.addr, data); - results.layers.push((gid, friend.gid, msg)); - - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionFriendClose(friend.gid), - FRIEND_TABLE_PATH, - friend.id, - &mut results, - )?; + // state.group.write().await.broadcast( + // &gid, + // InnerEvent::SessionFriendClose(friend.gid), + // FRIEND_TABLE_PATH, + // friend.id, + // &mut results, + // )?; Ok(results) }, @@ -197,39 +204,39 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-friend-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; - let db = state.group.read().await.chat_db(&gid)?; let friend = Friend::get(&db, &id)?; Friend::delete(&db, &id)?; drop(db); - let mut layer_lock = state.layer.write().await; - let online = layer_lock.remove_online(&gid, &friend.gid); - delete_avatar(layer_lock.base(), &gid, &friend.gid).await?; - drop(layer_lock); + let online = state.layer.write().await.chat_rm_online(&friend.pid); + delete_avatar(&state.base, &pid, &friend.pid).await?; if let Some(faddr) = online { - let mut addrs: HashMap = HashMap::new(); - addrs.insert(faddr, friend.gid); - let sender = state.group.read().await.sender(); - tokio::spawn(sleep_waiting_close_stable(sender, HashMap::new(), addrs)); + let data = bincode::serialize(&LayerEvent::Close)?; + results + .layers + .push((CHAT_ID, SendType::Event(0, friend.pid, data))); + + results + .layers + .push((CHAT_ID, SendType::Disconnect(friend.pid))); } - let data = bincode::serialize(&LayerEvent::Close)?; - let msg = SendType::Event(0, friend.addr, data); - results.layers.push((gid, friend.gid, msg)); - - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionFriendDelete(friend.gid), - FRIEND_TABLE_PATH, - friend.id, - &mut results, - )?; + // state.group.write().await.broadcast( + // &gid, + // InnerEvent::SessionFriendDelete(friend.gid), + // FRIEND_TABLE_PATH, + // friend.id, + // &mut results, + // )?; Ok(results) }, @@ -237,8 +244,10 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-request-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.chat_db(&gid)?; + |_params: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; let requests = Request::list(&db)?; drop(db); Ok(HandleResult::rpc(request_list(requests))) @@ -247,50 +256,37 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-request-create", - |gid: GroupId, params: Vec, state: Arc| async move { - let remote_gid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; - let remote_addr = PeerId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; - let remote_name = params[2].as_str().ok_or(RpcError::ParseError)?.to_string(); - let remark = params[3].as_str().ok_or(RpcError::ParseError)?.to_string(); - - let mut request = Request::new( - remote_gid, - remote_addr, - remote_name.clone(), - remark.clone(), - true, - false, - ); - - let group_lock = state.group.read().await; - let name = group_lock.username(&gid)?; - let proof = group_lock.prove_addr(&gid, &remote_addr)?; - drop(group_lock); - - let db = state.group.read().await.chat_db(&gid)?; - let mut layer_lock = state.layer.write().await; - if Friend::is_friend(&db, &request.gid)? { - debug!("had friend."); - drop(layer_lock); + |params: Vec, state: Arc| async move { + let remote_pid = id_from_str(params[0].as_str().ok_or(RpcError::ParseError)?)?; + let remote_name = params[1].as_str().ok_or(RpcError::ParseError)?.to_string(); + let remark = params[2].as_str().ok_or(RpcError::ParseError)?.to_string(); + + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + + if Friend::is_friend(&db, &remote_pid)? { + debug!("Had friend."); return Ok(HandleResult::new()); } - if let Ok(req) = Request::get_id(&db, &request.gid) { - debug!("Had this request."); + if let Ok(req) = Request::get_id(&db, &remote_pid) { + debug!("Had request."); Request::delete(&db, &req.id)?; } + + let mut request = + Request::new(remote_pid, remote_name.clone(), remark.clone(), true, false); request.insert(&db)?; drop(db); let mut results = HandleResult::rpc(json!(request.to_rpc())); - results.layers.push(( - gid, - remote_gid, - req_message(&mut layer_lock, gid, name, proof, request), - )); - - drop(layer_lock); + let name = state.group.read().await.account(&pid)?.name.clone(); + let req = LayerEvent::Request(name, request.remark); + let data = bincode::serialize(&req).unwrap_or(vec![]); + let msg = SendType::Event(0, request.pid, data); + results.layers.push((CHAT_ID, msg)); Ok(results) }, @@ -298,38 +294,39 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-request-agree", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let mut group_lock = state.group.write().await; - let db = group_lock.chat_db(&gid)?; - let mut request = Request::get(&db, &id)?; let mut results = HandleResult::new(); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + + let mut request = Request::get(&db, &id)?; - group_lock.broadcast( - &gid, - InnerEvent::SessionRequestHandle(request.gid, true, vec![]), - REQUEST_TABLE_PATH, - request.id, - &mut results, - )?; + // group_lock.broadcast( + // &gid, + // InnerEvent::SessionRequestHandle(request.gid, true, vec![]), + // REQUEST_TABLE_PATH, + // request.id, + // &mut results, + // )?; request.is_ok = true; request.is_over = true; request.update(&db)?; - let friend = - Friend::from_remote(&db, request.gid, request.name, request.addr, "".to_owned())?; + let friend = Friend::from_remote(&db, request.pid, request.name, "".to_owned())?; results.rpcs.push(json!([id, friend.to_rpc()])); // ADD NEW SESSION. - let s_db = group_lock.session_db(&gid)?; + let s_db = session_db(&state.base, &pid, &db_key)?; let mut session = friend.to_session(); session.insert(&s_db)?; - results.rpcs.push(session_create(gid, &session)); + results.rpcs.push(session_create(&session)); - let proof = group_lock.prove_addr(&gid, &friend.addr)?; - let msg = agree_message(proof, friend.addr)?; - results.layers.push((gid, friend.gid, msg)); + let data = bincode::serialize(&LayerEvent::Agree).unwrap_or(vec![]); + let msg = SendType::Event(0, friend.pid, data); + results.layers.push((CHAT_ID, msg)); Ok(results) }, @@ -337,67 +334,73 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-request-reject", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let mut req = Request::get(&db, &id)?; req.is_ok = false; req.is_over = true; req.update(&db)?; drop(db); - let mut layer_lock = state.layer.write().await; - let msg = reject_message(&mut layer_lock, id, req.addr, gid); - drop(layer_lock); - let mut results = HandleResult::layer(gid, req.gid, msg); - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionRequestHandle(req.gid, false, vec![]), - REQUEST_TABLE_PATH, - req.id, - &mut results, - )?; + let data = bincode::serialize(&LayerEvent::Reject).unwrap_or(vec![]); + let msg = SendType::Event(0, req.pid, data); + let mut results = HandleResult::layer(CHAT_ID, msg); + + // state.group.write().await.broadcast( + // &gid, + // InnerEvent::SessionRequestHandle(req.gid, false, vec![]), + // REQUEST_TABLE_PATH, + // req.id, + // &mut results, + // )?; Ok(results) }, ); handler.add_method( "chat-request-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let db = group_lock.chat_db(&gid)?; - let base = group_lock.base().clone(); - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let req = Request::get(&db, &id)?; Request::delete(&db, &id)?; // delete avatar. check had friend. - if Friend::get_id(&db, &req.gid).is_err() { - delete_avatar(&base, &gid, &req.gid).await?; + if Friend::get_id(&db, &req.pid).is_err() { + delete_avatar(&state.base, &pid, &req.pid).await?; } drop(db); - let mut results = HandleResult::new(); - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionRequestDelete(req.gid), - REQUEST_TABLE_PATH, - req.id, - &mut results, - )?; + let results = HandleResult::new(); + // state.group.write().await.broadcast( + // &gid, + // InnerEvent::SessionRequestDelete(req.gid), + // REQUEST_TABLE_PATH, + // req.id, + // &mut results, + // )?; Ok(results) }, ); handler.add_method( "chat-detail", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let friend = Friend::get(&db, &id)?; let messages = Message::get_by_fid(&db, &id)?; drop(db); @@ -408,10 +411,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-message-list", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let fid = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let messages = Message::get_by_fid(&db, &fid)?; drop(db); Ok(HandleResult::rpc(message_list(messages))) @@ -420,42 +426,33 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-message-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let fid = params[0].as_i64().ok_or(RpcError::ParseError)?; - let fgid = GroupId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; + let fpid = id_from_str(params[1].as_str().ok_or(RpcError::ParseError)?)?; let m_type = MessageType::from_int(params[2].as_i64().ok_or(RpcError::ParseError)?); let content = params[3].as_str().ok_or(RpcError::ParseError)?; - let mut layer_lock = state.layer.write().await; - let base = layer_lock.base().clone(); - let faddr = layer_lock.running(&gid)?.online(&fgid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; - let (msg, nw) = - LayerEvent::from_message(&state.group, &base, gid, fid, m_type, content).await?; - let event = LayerEvent::Message(msg.hash, nw); - let s = super::layer::event_message(&mut layer_lock, msg.id, gid, faddr, &event); - drop(layer_lock); + let (nm, raw) = + raw_to_network_message(&pid, &state.base, &db_key, &m_type, content).await?; + let mut msg = Message::new(&pid, fid, true, m_type, raw, false); + msg.insert(&db)?; let mut results = HandleResult::rpc(json!(msg.to_rpc())); - results.layers.push((gid, fgid, s)); - // UPDATE SESSION. - if let Ok(s_db) = state.group.read().await.session_db(&gid) { - update_session(&s_db, &gid, &fid, &msg, &mut results); - } + let tid = state.layer.write().await.delivery(msg.id); + let event = LayerEvent::Message(msg.hash, nm); + let data = bincode::serialize(&event).unwrap_or(vec![]); + results + .layers + .push((CHAT_ID, SendType::Event(tid, fpid, data))); - match event { - LayerEvent::Message(hash, nw) => { - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionMessageCreate(fgid, true, hash, nw), - MESSAGE_TABLE_PATH, - msg.id, - &mut results, - )?; - } - _ => {} - } + // UPDATE SESSION. + let s_db = session_db(&state.base, &pid, &db_key)?; + update_session(&s_db, &fid, &msg, &mut results); Ok(results) }, @@ -463,22 +460,18 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "chat-message-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.chat_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = chat_db(&state.base, &pid, &db_key)?; + let msg = Message::get(&db, &id)?; Message::delete(&db, &id)?; drop(db); - let mut results = HandleResult::new(); - state.group.write().await.broadcast( - &gid, - InnerEvent::SessionMessageDelete(msg.hash), - MESSAGE_TABLE_PATH, - msg.id, - &mut results, - )?; - Ok(results) + + Ok(HandleResult::new()) }, ); } diff --git a/src/apps/cloud/layer.rs b/src/apps/cloud/layer.rs index 5330c33..771ff8c 100644 --- a/src/apps/cloud/layer.rs +++ b/src/apps/cloud/layer.rs @@ -1,20 +1,13 @@ +use cloud_types::LayerServerEvent; use std::sync::Arc; use tdn::types::{ - group::GroupId, message::RecvType, - primitive::{HandleResult, Result}, + primitives::{HandleResult, Result}, }; -use tokio::sync::RwLock; - -use cloud_types::LayerServerEvent; -use crate::layer::Layer; +use crate::global::Global; -pub(crate) async fn handle( - _layer: &Arc>, - _ogid: GroupId, - msg: RecvType, -) -> Result { +pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { let results = HandleResult::new(); match msg { @@ -26,7 +19,7 @@ pub(crate) async fn handle( info!("cloud message nerver to here.") } RecvType::Event(_addr, bytes) => { - let LayerServerEvent(_event, _proof) = bincode::deserialize(&bytes)?; + let LayerServerEvent(_event) = bincode::deserialize(&bytes)?; } RecvType::Delivery(_t, _tid, _is_ok) => { // MAYBE diff --git a/src/apps/cloud/mod.rs b/src/apps/cloud/mod.rs index 57f6e6b..3d318ee 100644 --- a/src/apps/cloud/mod.rs +++ b/src/apps/cloud/mod.rs @@ -1,30 +1,6 @@ mod layer; mod models; -pub use cloud_types::CLOUD_ID as GROUP_ID; -use cloud_types::{LayerPeerEvent, PeerEvent}; -use tdn::types::{ - group::GroupId, - message::SendType, - primitive::{HandleResult, PeerId, Result}, -}; -use tdn_did::Proof; - -/// Send to domain service. -#[inline] -pub(crate) fn add_layer( - results: &mut HandleResult, - addr: PeerId, - event: PeerEvent, - ogid: GroupId, -) -> Result<()> { - let proof = Proof::default(); - let data = bincode::serialize(&LayerPeerEvent(event, proof))?; - let s = SendType::Event(0, addr, data); - results.layers.push((ogid, GROUP_ID, s)); - Ok(()) -} - pub(crate) mod rpc; pub(crate) use layer::handle; pub(crate) use rpc::new_rpc_handler; diff --git a/src/apps/cloud/rpc.rs b/src/apps/cloud/rpc.rs index 8669e6f..b8aab6f 100644 --- a/src/apps/cloud/rpc.rs +++ b/src/apps/cloud/rpc.rs @@ -1,16 +1,15 @@ use std::sync::Arc; use tdn::types::{ - group::GroupId, - primitive::HandleResult, + primitives::HandleResult, rpc::{json, RpcHandler, RpcParam}, }; -use crate::rpc::RpcState; +use crate::global::Global; -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "cloud-echo", - |_gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { Ok(HandleResult::rpc(json!(params))) }, ); diff --git a/src/apps/device/models.rs b/src/apps/device/models.rs index f86c2d0..69fe73e 100644 --- a/src/apps/device/models.rs +++ b/src/apps/device/models.rs @@ -1,6 +1,5 @@ -use std::collections::HashMap; use std::time::{SystemTime, UNIX_EPOCH}; -use tdn::types::primitive::{Peer, PeerId, Result}; +use tdn::types::primitives::{Peer, Result}; use tdn::types::rpc::{json, RpcParam}; use tdn_storage::local::{DStorage, DsValue}; @@ -8,13 +7,13 @@ pub(crate) struct Device { pub id: i64, pub name: String, pub info: String, - pub addr: PeerId, + pub peer: Peer, pub lasttime: i64, pub online: bool, } impl Device { - pub fn new(name: String, info: String, addr: PeerId) -> Self { + pub fn new(name: String, info: String, peer: Peer) -> Self { let start = SystemTime::now(); let lasttime = start .duration_since(UNIX_EPOCH) @@ -22,10 +21,10 @@ impl Device { .unwrap_or(0) as i64; // safe for all life. Self { - addr, lasttime, info, name, + peer, id: 0, online: true, } @@ -35,7 +34,7 @@ impl Device { fn from_values(mut v: Vec) -> Device { Device { lasttime: v.pop().unwrap().as_i64(), - addr: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), + peer: Peer::from_string(v.pop().unwrap().as_str()).unwrap_or(Peer::default()), info: v.pop().unwrap().as_string(), name: v.pop().unwrap().as_string(), id: v.pop().unwrap().as_i64(), @@ -48,7 +47,7 @@ impl Device { self.id, self.name, self.info, - self.addr.to_hex(), + self.peer.to_string(), self.lasttime, if self.online { "1" } else { "0" }, ]) @@ -56,49 +55,20 @@ impl Device { /// load account devices. pub fn list(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, name, info, addr, lasttime FROM devices")?; + let matrix = db.query("SELECT id, name, info, peer, lasttime FROM devices")?; let mut devices = vec![]; for values in matrix { - if values.len() == 5 { - devices.push(Device::from_values(values)); - } + devices.push(Device::from_values(values)); } Ok(devices) } - pub fn distributes(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, addr FROM devices")?; - let mut devices = HashMap::new(); - for mut values in matrix { - if values.len() == 2 { - let addr = - PeerId::from_hex(values.pop().unwrap().as_str()).unwrap_or(PeerId::default()); - let id = values.pop().unwrap().as_i64(); - devices.insert(addr, (Peer::peer(addr), id, false)); - } - } - Ok(devices) - } - - pub fn device_info(db: &DStorage) -> Result<(String, String)> { - let mut matrix = db.query("SELECT name, info FROM devices ORDER BY id LIMIT 1")?; - if matrix.len() > 0 { - let mut values = matrix.pop().unwrap(); // safe unwrap() - if values.len() == 2 { - let info = values.pop().unwrap().as_string(); - let name = values.pop().unwrap().as_string(); - return Ok((name, info)); - } - } - Ok((String::new(), String::new())) - } - pub fn insert(&mut self, db: &DStorage) -> Result<()> { let sql = format!( - "INSERT INTO devices (name, info, addr, lasttime) VALUES ('{}', '{}', '{}', {})", + "INSERT INTO devices (name, info, peer, lasttime) VALUES ('{}', '{}', '{}', {})", self.name, self.info, - self.addr.to_hex(), + self.peer.to_string(), self.lasttime, ); let id = db.insert(&sql)?; diff --git a/src/apps/device/rpc.rs b/src/apps/device/rpc.rs index 4341e46..eb3bd67 100644 --- a/src/apps/device/rpc.rs +++ b/src/apps/device/rpc.rs @@ -1,39 +1,37 @@ use std::sync::Arc; use tdn::types::{ - group::GroupId, - primitive::{HandleResult, Peer, PeerId}, + primitives::HandleResult, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; -use crate::group::GroupEvent; -use crate::rpc::RpcState; +use crate::global::Global; +//use crate::group::GroupEvent; use crate::utils::device_status::device_status as local_device_status; use super::Device; #[inline] -pub(crate) fn device_create(mgid: GroupId, device: &Device) -> RpcParam { - rpc_response(0, "device-create", json!(device.to_rpc()), mgid) +pub(crate) fn device_create(device: &Device) -> RpcParam { + rpc_response(0, "device-create", json!(device.to_rpc())) } #[inline] -pub(crate) fn _device_remove(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "device-remove", json!([id]), mgid) +pub(crate) fn _device_remove(id: i64) -> RpcParam { + rpc_response(0, "device-remove", json!([id])) } #[inline] -pub(crate) fn device_online(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "device-online", json!([id]), mgid) +pub(crate) fn device_online(id: i64) -> RpcParam { + rpc_response(0, "device-online", json!([id])) } #[inline] -pub(crate) fn device_offline(mgid: GroupId, id: i64) -> RpcParam { - rpc_response(0, "device-offline", json!([id]), mgid) +pub(crate) fn device_offline(id: i64) -> RpcParam { + rpc_response(0, "device-offline", json!([id])) } #[inline] pub(crate) fn device_status( - mgid: GroupId, cpu: u32, memory: u32, swap: u32, @@ -48,12 +46,11 @@ pub(crate) fn device_status( 0, "device-status", json!([cpu, memory, swap, disk, cpu_p, memory_p, swap_p, disk_p, uptime]), - mgid, ) } #[inline] -fn device_list(devices: Vec) -> RpcParam { +fn device_list(devices: &[Device]) -> RpcParam { let mut results = vec![]; for device in devices { results.push(device.to_rpc()); @@ -61,30 +58,27 @@ fn device_list(devices: Vec) -> RpcParam { json!(results) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { - handler.add_method("device-echo", |_, params, _| async move { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { + handler.add_method("device-echo", |params, _| async move { Ok(HandleResult::rpc(json!(params))) }); handler.add_method( "device-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.consensus_db(&gid)?; - let devices = Device::list(&db)?; - drop(db); - let online_devices = state.group.read().await.online_devices(&gid, devices); - Ok(HandleResult::rpc(device_list(online_devices))) + |_params: Vec, state: Arc| async move { + let devices = &state.group.read().await.distributes; + Ok(HandleResult::rpc(device_list(devices))) }, ); handler.add_method( "device-status", - |gid: GroupId, params: Vec, state: Arc| async move { - let addr = PeerId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; + |params: Vec, state: Arc| async move { + let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let group_lock = state.group.read().await; - if &addr == group_lock.addr() { - let uptime = group_lock.uptime(&gid)?; + if id == group_lock.device()?.id { + let uptime = group_lock.uptime; let (cpu, memory, swap, disk, cpu_p, memory_p, swap_p, disk_p) = local_device_status(); return Ok(HandleResult::rpc(json!([ @@ -93,47 +87,24 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { } drop(group_lock); - let msg = state - .group - .write() - .await - .event_message(addr, &GroupEvent::StatusRequest)?; - - Ok(HandleResult::group(gid, msg)) - }, - ); - - handler.add_method( - "device-create", - |gid: GroupId, params: Vec, state: Arc| async move { - let addr = PeerId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; - - let msg = state - .group - .read() - .await - .create_message(&gid, Peer::peer(addr))?; - Ok(HandleResult::group(gid, msg)) + //let msg = state.group.write().await.event_message(addr, &GroupEvent::StatusRequest)?; + //Ok(HandleResult::group(msg)) + Ok(HandleResult::new()) }, ); handler.add_method( - "device-connect", - |gid: GroupId, params: Vec, state: Arc| async move { - let addr = PeerId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; - - let msg = state - .group - .read() - .await - .connect_message(&gid, Peer::peer(addr))?; - Ok(HandleResult::group(gid, msg)) + "device-search", + |_params: Vec, state: Arc| async move { + //let msg = state.group.read().await.create_message(&gid, Peer::peer(addr))?; + //Ok(HandleResult::group(gid, msg)) + Ok(HandleResult::new()) }, ); handler.add_method( "device-delete", - |_gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let _id = params[0].as_i64().ok_or(RpcError::ParseError)?; // TODO delete a device. Ok(HandleResult::new()) diff --git a/src/apps/domain/layer.rs b/src/apps/domain/layer.rs index e4d845d..77c4667 100644 --- a/src/apps/domain/layer.rs +++ b/src/apps/domain/layer.rs @@ -1,23 +1,17 @@ +use domain_types::LayerServerEvent; use std::sync::Arc; use tdn::types::{ - group::GroupId, message::RecvType, - primitive::{HandleResult, Result}, + primitives::{HandleResult, Result}, }; -use tokio::sync::RwLock; -use domain_types::{LayerServerEvent, ServerEvent}; - -use crate::layer::Layer; +use crate::global::Global; +use crate::storage::domain_db; use super::models::{Name, Provider}; use super::rpc; -pub(crate) async fn handle( - layer: &Arc>, - ogid: GroupId, - msg: RecvType, -) -> Result { +pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { let mut results = HandleResult::new(); match msg { @@ -30,17 +24,19 @@ pub(crate) async fn handle( } RecvType::Event(addr, bytes) => { // server & client handle it. - let LayerServerEvent(event, _proof) = bincode::deserialize(&bytes)?; + let event: LayerServerEvent = bincode::deserialize(&bytes)?; - let db = layer.read().await.group.read().await.domain_db(&ogid)?; + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = domain_db(&global.base, &pid, &db_key)?; match event { - ServerEvent::Status(name, support_request) => { + LayerServerEvent::Status(name, support_request) => { let mut provider = Provider::get_by_addr(&db, &addr)?; provider.ok(&db, name, support_request)?; - results.rpcs.push(rpc::add_provider(ogid, &provider)); + results.rpcs.push(rpc::add_provider(&provider)); } - ServerEvent::Result(name, is_ok) => { + LayerServerEvent::Result(name, is_ok) => { let provider = Provider::get_by_addr(&db, &addr)?; let mut user = Name::get_by_name_provider(&db, &name, &provider.id)?; @@ -48,39 +44,39 @@ pub(crate) async fn handle( Name::active(&db, &user.id, true)?; user.is_ok = true; user.is_actived = true; - results.rpcs.push(rpc::register_success(ogid, &user)); + results.rpcs.push(rpc::register_success(&user)); } else { user.delete(&db)?; - results.rpcs.push(rpc::register_failure(ogid, &name)); + results.rpcs.push(rpc::register_failure(&name)); } } - ServerEvent::Info(uname, ugid, uaddr, ubio, uavatar) => { - results.rpcs.push(rpc::search_result( - ogid, &uname, &ugid, &uaddr, &ubio, &uavatar, - )); + LayerServerEvent::Info(upid, uname, ubio, uavatar) => { + results + .rpcs + .push(rpc::search_result(&upid, &uname, &ubio, &uavatar)); } - ServerEvent::None(uname) => { - results.rpcs.push(rpc::search_none(ogid, &uname)); + LayerServerEvent::None(uname) => { + results.rpcs.push(rpc::search_none(&uname)); } - ServerEvent::Actived(uname, is_actived) => { + LayerServerEvent::Actived(uname, is_actived) => { let provider = Provider::get_by_addr(&db, &addr)?; let name = Name::get_by_name_provider(&db, &uname, &provider.id)?; Name::active(&db, &name.id, is_actived)?; let ps = Provider::list(&db)?; let names = Name::list(&db)?; - results.rpcs.push(rpc::domain_list(ogid, &ps, &names)); + results.rpcs.push(rpc::domain_list(&ps, &names)); } - ServerEvent::Deleted(uname) => { + LayerServerEvent::Deleted(uname) => { let provider = Provider::get_by_addr(&db, &addr)?; let name = Name::get_by_name_provider(&db, &uname, &provider.id)?; name.delete(&db)?; let ps = Provider::list(&db)?; let names = Name::list(&db)?; - results.rpcs.push(rpc::domain_list(ogid, &ps, &names)); + results.rpcs.push(rpc::domain_list(&ps, &names)); } - ServerEvent::Response(_ugid, _uname, _is_ok) => {} + LayerServerEvent::Response(_ugid, _uname, _is_ok) => {} } } RecvType::Delivery(_t, _tid, _is_ok) => { diff --git a/src/apps/domain/mod.rs b/src/apps/domain/mod.rs index b4b5ee5..3d318ee 100644 --- a/src/apps/domain/mod.rs +++ b/src/apps/domain/mod.rs @@ -1,30 +1,6 @@ mod layer; mod models; -pub use domain_types::DOMAIN_ID as GROUP_ID; -use domain_types::{LayerPeerEvent, PeerEvent}; -use tdn::types::{ - group::GroupId, - message::SendType, - primitive::{HandleResult, PeerId, Result}, -}; -use tdn_did::Proof; - -/// Send to domain service. -#[inline] -pub(crate) fn add_layer( - results: &mut HandleResult, - addr: PeerId, - event: PeerEvent, - ogid: GroupId, -) -> Result<()> { - let proof = Proof::default(); - let data = bincode::serialize(&LayerPeerEvent(event, proof))?; - let s = SendType::Event(0, addr, data); - results.layers.push((ogid, GROUP_ID, s)); - Ok(()) -} - pub(crate) mod rpc; pub(crate) use layer::handle; pub(crate) use rpc::new_rpc_handler; diff --git a/src/apps/domain/models.rs b/src/apps/domain/models.rs index a7684ec..3a79ed0 100644 --- a/src/apps/domain/models.rs +++ b/src/apps/domain/models.rs @@ -1,5 +1,5 @@ use tdn::types::{ - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; diff --git a/src/apps/domain/rpc.rs b/src/apps/domain/rpc.rs index b6b7791..62dc6b8 100644 --- a/src/apps/domain/rpc.rs +++ b/src/apps/domain/rpc.rs @@ -1,56 +1,47 @@ +use domain_types::{LayerPeerEvent, DOMAIN_ID}; +use esse_primitives::id_to_str; use std::sync::Arc; use tdn::types::{ - group::GroupId, - primitive::{HandleResult, PeerId}, + message::SendType, + primitives::{HandleResult, PeerId}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; -use domain_types::PeerEvent; +use crate::global::Global; +use crate::storage::domain_db; -use super::{ - add_layer, - models::{Name, Provider}, -}; -use crate::rpc::RpcState; +use super::models::{Name, Provider}; #[inline] -pub(crate) fn add_provider(mgid: GroupId, provider: &Provider) -> RpcParam { - rpc_response(0, "domain-provider-add", json!(provider.to_rpc()), mgid) +pub(crate) fn add_provider(provider: &Provider) -> RpcParam { + rpc_response(0, "domain-provider-add", json!(provider.to_rpc())) } #[inline] -pub(crate) fn register_success(mgid: GroupId, name: &Name) -> RpcParam { - rpc_response(0, "domain-register-success", json!(name.to_rpc()), mgid) +pub(crate) fn register_success(name: &Name) -> RpcParam { + rpc_response(0, "domain-register-success", json!(name.to_rpc())) } #[inline] -pub(crate) fn register_failure(mgid: GroupId, name: &str) -> RpcParam { - rpc_response(0, "domain-register-failure", json!([name]), mgid) +pub(crate) fn register_failure(name: &str) -> RpcParam { + rpc_response(0, "domain-register-failure", json!([name])) } #[inline] -pub(crate) fn domain_list(mgid: GroupId, providers: &[Provider], names: &[Name]) -> RpcParam { +pub(crate) fn domain_list(providers: &[Provider], names: &[Name]) -> RpcParam { let providers: Vec = providers.iter().map(|p| p.to_rpc()).collect(); let names: Vec = names.iter().map(|p| p.to_rpc()).collect(); - rpc_response(0, "domain-list", json!([providers, names]), mgid) + rpc_response(0, "domain-list", json!([providers, names])) } #[inline] -pub(crate) fn search_result( - mgid: GroupId, - name: &str, - gid: &GroupId, - addr: &PeerId, - bio: &str, - avatar: &Vec, -) -> RpcParam { +pub(crate) fn search_result(pid: &PeerId, name: &str, bio: &str, avatar: &Vec) -> RpcParam { rpc_response( 0, "domain-search", json!([ name, - gid.to_hex(), - addr.to_hex(), + id_to_str(pid), bio, if avatar.len() > 0 { base64::encode(avatar) @@ -58,20 +49,21 @@ pub(crate) fn search_result( "".to_owned() } ]), - mgid, ) } #[inline] -pub(crate) fn search_none(mgid: GroupId, name: &str) -> RpcParam { - rpc_response(0, "domain-search", json!([name]), mgid) +pub(crate) fn search_none(name: &str) -> RpcParam { + rpc_response(0, "domain-search", json!([name])) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.domain_db(&gid)?; + |_params: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = domain_db(&state.base, &pid, &db_key)?; // list providers. let providers: Vec = @@ -86,25 +78,33 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-provider-add", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let provider = PeerId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; let mut results = HandleResult::new(); - let db = state.group.read().await.domain_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = domain_db(&state.base, &pid, &db_key)?; + let mut p = Provider::prepare(provider); p.insert(&db)?; - add_layer(&mut results, provider, PeerEvent::Check, gid)?; + let data = bincode::serialize(&LayerPeerEvent::Check)?; + let msg = SendType::Event(0, provider, data); + results.layers.push((DOMAIN_ID, msg)); Ok(results) }, ); handler.add_method( "domain-provider-default", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.domain_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = domain_db(&state.base, &pid, &db_key)?; + let provider = Provider::get(&db, &id)?; if let Ok(default) = Provider::get_default(&db) { if default.id == provider.id { @@ -120,10 +120,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-provider-remove", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.domain_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = domain_db(&state.base, &pid, &db_key)?; + let names = Name::get_by_provider(&db, &id)?; if names.len() == 0 { Provider::delete(&db, &id)?; @@ -135,71 +138,80 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-register", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let provider = params[0].as_i64().ok_or(RpcError::ParseError)?; let addr = PeerId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; let name = params[2].as_str().ok_or(RpcError::ParseError)?.to_string(); let bio = params[3].as_str().ok_or(RpcError::ParseError)?.to_string(); - let me = state.group.read().await.clone_user(&gid)?; - // save to db. let mut results = HandleResult::new(); - let db = state.group.read().await.domain_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = domain_db(&state.base, &pid, &db_key)?; + + let me = state.group.read().await.clone_user(&pid)?; + let mut u = Name::prepare(name, bio, provider); u.insert(&db)?; // send to server. - let event = PeerEvent::Register(u.name, u.bio, me.avatar); - add_layer(&mut results, addr, event, gid)?; + let data = bincode::serialize(&LayerPeerEvent::Register(u.name, u.bio, me.avatar))?; + let msg = SendType::Event(0, addr, data); + results.layers.push((DOMAIN_ID, msg)); Ok(results) }, ); handler.add_method( "domain-active", - |gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let name = params[0].as_str().ok_or(RpcError::ParseError)?.to_owned(); let provider = PeerId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; let active = params[2].as_bool().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); let event = if active { - PeerEvent::Active(name) + LayerPeerEvent::Active(name) } else { - PeerEvent::Suspend(name) + LayerPeerEvent::Suspend(name) }; - add_layer(&mut results, provider, event, gid)?; + let data = bincode::serialize(&event)?; + let msg = SendType::Event(0, provider, data); + results.layers.push((DOMAIN_ID, msg)); Ok(results) }, ); handler.add_method( "domain-remove", - |gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let name = params[0].as_str().ok_or(RpcError::ParseError)?.to_owned(); let provider = PeerId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; let mut results = HandleResult::new(); - let event = PeerEvent::Delete(name); - add_layer(&mut results, provider, event, gid)?; - + let event = LayerPeerEvent::Delete(name); + let data = bincode::serialize(&event)?; + let msg = SendType::Event(0, provider, data); + results.layers.push((DOMAIN_ID, msg)); Ok(results) }, ); handler.add_method( "domain-search", - |gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let addr = PeerId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; let name = params[1].as_str().ok_or(RpcError::ParseError)?.to_owned(); let mut results = HandleResult::new(); // send to server. - let event = PeerEvent::Search(name); - add_layer(&mut results, addr, event, gid)?; + let event = LayerPeerEvent::Search(name); + let data = bincode::serialize(&event)?; + let msg = SendType::Event(0, addr, data); + results.layers.push((DOMAIN_ID, msg)); Ok(results) }, ); diff --git a/src/apps/file/models.rs b/src/apps/file/models.rs index 4c974c8..f2f6fb0 100644 --- a/src/apps/file/models.rs +++ b/src/apps/file/models.rs @@ -2,7 +2,7 @@ use rand::Rng; use serde::{Deserialize, Serialize}; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - primitive::Result, + primitives::Result, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; diff --git a/src/apps/file/rpc.rs b/src/apps/file/rpc.rs index 4cebc68..15024e6 100644 --- a/src/apps/file/rpc.rs +++ b/src/apps/file/rpc.rs @@ -1,28 +1,30 @@ use std::path::PathBuf; use std::sync::Arc; use tdn::types::{ - group::GroupId, - primitive::HandleResult, + primitives::HandleResult, rpc::{json, RpcError, RpcHandler, RpcParam}, }; -use crate::rpc::RpcState; -use crate::storage::{copy_file, write_file}; +use crate::global::Global; +use crate::storage::{copy_file, file_db, write_file}; use super::models::{File, RootDirectory}; -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { - handler.add_method("dc-echo", |_, params, _| async move { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { + handler.add_method("dc-echo", |params, _| async move { Ok(HandleResult::rpc(json!(params))) }); handler.add_method( "dc-list", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let root = RootDirectory::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let parent = params[1].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.file_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + let files: Vec = File::list(&db, &root, &parent)? .iter() .map(|p| p.to_rpc()) @@ -34,28 +36,28 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-file-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let root = RootDirectory::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let parent = params[1].as_i64().ok_or(RpcError::ParseError)?; let name = params[2].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let db = group_lock.file_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + // genereate new file. let mut file = File::generate(root, parent, name); file.insert(&db)?; // create file on disk. - let _ = write_file(&base, &gid, &file.storage_name(), &[]).await?; + let _ = write_file(&state.base, &pid, &file.storage_name(), &[]).await?; Ok(HandleResult::rpc(file.to_rpc())) }, ); handler.add_method( "dc-file-upload", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let root = RootDirectory::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let parent = params[1].as_i64().ok_or(RpcError::ParseError)?; let path = params[2].as_str().ok_or(RpcError::ParseError)?; @@ -68,13 +70,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { .ok_or(RpcError::ParseError)? .to_owned(); - let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let db = group_lock.file_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + let mut file = File::generate(root, parent, name); file.insert(&db)?; - copy_file(&file_path, &base, &gid, &file.storage_name()).await?; + copy_file(&file_path, &state.base, &pid, &file.storage_name()).await?; Ok(HandleResult::rpc(file.to_rpc())) }, @@ -82,13 +84,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-folder-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let root = RootDirectory::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let parent = params[1].as_i64().ok_or(RpcError::ParseError)?; let name = params[2].as_str().ok_or(RpcError::ParseError)?.to_owned(); // create new folder. - let db = state.group.read().await.file_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + let mut file = File::generate(root, parent, name); file.insert(&db)?; @@ -98,13 +103,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-file-update", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let root = RootDirectory::from_i64(params[1].as_i64().ok_or(RpcError::ParseError)?); let parent = params[2].as_i64().ok_or(RpcError::ParseError)?; let name = params[3].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let db = state.group.read().await.file_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + let mut file = File::get(&db, &id)?; file.root = root; file.parent = parent; @@ -117,11 +125,14 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-file-star", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let starred = params[1].as_bool().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.file_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + File::star(&db, &id, starred)?; Ok(HandleResult::new()) }, @@ -129,12 +140,15 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-file-trash", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + // TODO trash a directory. - let db = state.group.read().await.file_db(&gid)?; File::trash(&db, &id)?; Ok(HandleResult::new()) }, @@ -142,12 +156,15 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "dc-file-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = file_db(&state.base, &pid, &db_key)?; + // TODO deleted file & directory. - let db = state.group.read().await.file_db(&gid)?; File::delete(&db, &id)?; Ok(HandleResult::new()) }, diff --git a/src/apps/group/layer.rs b/src/apps/group/layer.rs index d42626e..f68fb98 100644 --- a/src/apps/group/layer.rs +++ b/src/apps/group/layer.rs @@ -1,366 +1,385 @@ +use chat_types::MessageType; +use group_types::{Event, GroupChatId, LayerConnect, LayerEvent, LayerResult, GROUP_CHAT_ID}; use std::sync::Arc; use tdn::types::{ - group::GroupId, message::{RecvType, SendType}, - primitive::{HandleResult, Peer, PeerId, Result}, + primitives::{HandleResult, Peer, PeerId, Result}, }; -use tokio::sync::RwLock; - -use chat_types::MessageType; -use group_types::{Event, LayerConnect, LayerEvent, LayerResult}; -use tdn_did::Proof; use tdn_storage::local::DStorage; use crate::apps::chat::Friend; -use crate::layer::{Layer, Online}; +use crate::global::Global; use crate::rpc::{ session_close, session_connect, session_last, session_lost, session_suspend, session_update_name, }; use crate::session::{connect_session, Session, SessionType}; -use crate::storage::{delete_avatar, write_avatar_sync}; +use crate::storage::{chat_db, delete_avatar, group_db, session_db, write_avatar_sync}; use super::models::{handle_network_message, GroupChat, Member, Message}; -use super::{add_layer, add_server_layer, rpc}; +use super::rpc; // variable statement: -// gcd: Group Chat ID. -// fgid: where is event come from. -// ogid: my account ID. if server is group owner. if client is my. -// mgid: member account ID. +// gid: Group Chat ID. +// pid: my account ID. +// mpid: member account ID. // id: Group Chat database Id. +// sid: Group Chat Session Id. // mid: member database Id. -pub(crate) async fn handle_server( - layer: &Arc>, - fgid: GroupId, - msg: RecvType, -) -> Result { +pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { let mut results = HandleResult::new(); match msg { - RecvType::Connect(addr, data) => { - let LayerConnect(gcd, _proof) = bincode::deserialize(&data)?; - - if handle_server_connect(layer, gcd, fgid, &addr, &mut results) + RecvType::Connect(peer, data) => { + // SERVER + let LayerConnect(gid) = bincode::deserialize(&data)?; + if handle_connect(global, &peer, gid, &mut results) .await .is_err() { - let data = bincode::serialize(&gcd)?; - let s = SendType::Result(0, addr, false, false, data); - add_server_layer(&mut results, fgid, s); + let data = bincode::serialize(&gid)?; + let msg = SendType::Result(0, peer, false, false, data); + results.layers.push((GROUP_CHAT_ID, msg)); } } - RecvType::Leave(_addr) => { - // only server handle it. IMPORTANT !!! fgid IS mgid. - // TODO - } - RecvType::Event(addr, bytes) => { - debug!("----------- DEBUG GROUP CHAT: SERVER GOT LAYER EVENT"); - let event: LayerEvent = bincode::deserialize(&bytes)?; - handle_server_event(fgid, addr, event, layer, &mut results).await?; - debug!("----------- DEBUG GROUP CHAT: SERVER OVER LAYER EVENT"); - } - RecvType::Stream(_uid, _stream, _bytes) => { - // TODO stream - } - RecvType::Result(..) => {} - RecvType::ResultConnect(..) => {} - RecvType::Delivery(..) => {} - } - - Ok(results) -} - -async fn handle_server_connect( - layer: &Arc>, - gcd: GroupId, - fgid: GroupId, - addr: &Peer, - results: &mut HandleResult, -) -> Result<()> { - let (ogid, height, id) = layer.read().await.running(&gcd)?.owner_height_id(); - // check is member. - let db = layer.read().await.group.read().await.group_db(&ogid)?; - let g = GroupChat::get(&db, &id)?; - let mdid = Member::get_id(&db, &id, &fgid)?; - - let res = LayerResult(gcd, g.g_name, height); - let data = bincode::serialize(&res).unwrap_or(vec![]); - let s = SendType::Result(0, addr.clone(), true, false, data); - add_server_layer(results, fgid, s); - - layer.write().await.running_mut(&gcd)?.check_add_online( - fgid, - Online::Direct(addr.id), - id, - mdid, - )?; - - let _ = Member::addr_update(&db, &id, &fgid, &addr.id); - results - .rpcs - .push(rpc::member_online(ogid, id, mdid, &addr.id)); - - let new_data = bincode::serialize(&LayerEvent::MemberOnline(gcd, fgid, addr.id))?; - - for (mid, maddr) in layer.read().await.running(&gcd)?.onlines() { - let s = SendType::Event(0, *maddr, new_data.clone()); - add_server_layer(results, *mid, s); - } - Ok(()) -} - -pub(crate) async fn handle_peer( - layer: &Arc>, - ogid: GroupId, - msg: RecvType, -) -> Result { - let mut results = HandleResult::new(); - - match msg { - RecvType::Result(addr, is_ok, data) => { + RecvType::Result(peer, is_ok, data) => { + // PEER if is_ok { - let mut layer_lock = layer.write().await; - handle_connect(ogid, &addr, data, &mut layer_lock, &mut results).await?; + handle_result(global, &peer, data, &mut results).await?; } else { // close the group chat. - let gcd: GroupId = bincode::deserialize(&data)?; + let gid: GroupChatId = bincode::deserialize(&data)?; - let layer_lock = layer.read().await; - let group_lock = layer_lock.group.read().await; - let db = group_lock.group_db(&ogid)?; - let s_db = group_lock.session_db(&ogid)?; - drop(group_lock); - drop(layer_lock); + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = group_db(&global.base, &pid, &db_key)?; + let s_db = session_db(&global.base, &pid, &db_key)?; - let group = GroupChat::close(&db, &gcd)?; + let group = GroupChat::close_id(&db, &gid, &peer.id)?; let sid = Session::close(&s_db, &group.id, &SessionType::Group)?; - results.rpcs.push(session_close(ogid, &sid)); + results.rpcs.push(session_close(&sid)); } } - RecvType::ResultConnect(addr, data) => { - let mut layer_lock = layer.write().await; - if handle_connect(ogid, &addr, data, &mut layer_lock, &mut results) + RecvType::ResultConnect(peer, data) => { + // PEER + if handle_result(global, &peer, data, &mut results) .await .is_err() { - let msg = SendType::Result(0, addr, true, false, vec![]); - add_layer(&mut results, ogid, msg); + let msg = SendType::Result(0, peer, true, false, vec![]); + results.layers.push((GROUP_CHAT_ID, msg)); } } RecvType::Event(addr, bytes) => { - debug!("----------- DEBUG GROUP CHAT: PEER GOT LAYER EVENT"); + // PEER & SERVER let event: LayerEvent = bincode::deserialize(&bytes)?; - handle_peer_event(ogid, addr, event, layer, &mut results).await?; - debug!("----------- DEBUG GROUP CHAT: PEER OVER LAYER EVENT"); + handle_event(addr, event, global, &mut results).await?; } + RecvType::Delivery(..) => {} RecvType::Stream(_uid, _stream, _bytes) => { // TODO stream } - RecvType::Delivery(_t, _tid, _is_ok) => { - // TODO - } - _ => { - error!("group chat peer handle layer nerver here") - } + RecvType::Leave(..) => {} // nerver here. } Ok(results) } async fn handle_connect( - ogid: GroupId, - addr: &Peer, + global: &Arc, + peer: &Peer, + gid: GroupChatId, + results: &mut HandleResult, +) -> Result<()> { + let (height, _, id, _) = global.layer.read().await.group(&gid)?.info(); + + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = group_db(&global.base, &pid, &db_key)?; + + // check is member. + let g = GroupChat::get(&db, &id)?; + let mid = Member::get_id(&db, &id, &peer.id)?; + + let res = LayerResult(gid, g.name, height); + let data = bincode::serialize(&res).unwrap_or(vec![]); + let s = SendType::Result(0, peer.clone(), true, false, data); + results.layers.push((GROUP_CHAT_ID, s)); + + global.layer.write().await.group_add_member(&gid, peer.id); + results.rpcs.push(rpc::member_online(id, mid)); + + let data = LayerEvent::MemberOnline(gid, peer.id); + broadcast(&gid, global, &data, results).await?; + Ok(()) +} + +async fn handle_result( + global: &Arc, + peer: &Peer, data: Vec, - layer: &mut Layer, results: &mut HandleResult, ) -> Result<()> { // 0. deserialize result. - let LayerResult(gcd, gname, height) = bincode::deserialize(&data)?; + let LayerResult(gid, name, height) = bincode::deserialize(&data)?; + + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = group_db(&global.base, &pid, &db_key)?; + let s_db = session_db(&global.base, &pid, &db_key)?; // 1. check group. - let db = layer.group.read().await.group_db(&ogid)?; - let group = GroupChat::get_id(&db, &gcd)?; + let group = GroupChat::get_id(&db, &gid, &peer.id)?; // 1.0 check address. - if group.g_addr != addr.id { + if group.addr != peer.id { return Err(anyhow!("invalid group chat address.")); } - let _ = GroupChat::update_name(&db, &group.id, &gname); - results.rpcs.push(rpc::group_name(ogid, &group.id, &gname)); + let _ = GroupChat::update_name(&db, &group.id, &name); + results.rpcs.push(rpc::group_name(&group.id, &name)); // 1.1 get session. - let s_db = layer.group.read().await.session_db(&ogid)?; - let session_some = connect_session(&s_db, &SessionType::Group, &group.id, &addr.id)?; + let session_some = connect_session(&s_db, &SessionType::Group, &group.id, &peer.id)?; if session_some.is_none() { return Err(anyhow!("invalid group chat address.")); } let sid = session_some.unwrap().id; - let _ = Session::update_name(&s_db, &sid, &gname); - results.rpcs.push(session_update_name(ogid, &sid, &gname)); + let _ = Session::update_name(&s_db, &sid, &name); + results.rpcs.push(session_update_name(&sid, &name)); // 1.2 online this group. - layer - .running_mut(&ogid)? - .check_add_online(gcd, Online::Direct(addr.id), sid, group.id)?; + global + .layer + .write() + .await + .group_add(gid, peer.id, sid, group.id, height); // 1.3 online to UI. - results.rpcs.push(session_connect(ogid, &sid, &addr.id)); + results.rpcs.push(session_connect(&sid, &peer.id)); debug!("will sync remote: {}, my: {}", height, group.height); // 1.4 sync group height. if group.height < height { - add_layer(results, ogid, sync(gcd, addr.id, group.height)); + results + .layers + .push((GROUP_CHAT_ID, sync(gid, peer.id, group.height))); } else { // sync online members. - add_layer(results, ogid, sync_online(gcd, addr.id)); + results + .layers + .push((GROUP_CHAT_ID, sync_online(gid, peer.id))); } Ok(()) } -// variable statement: -// gcd: Group Chat ID. -// fgid: where is event come from. -// ogid: my account ID. if server is group owner. if client is my. -// mgid: member account ID. -// id: Group Chat database Id. -// mdid: member database Id. -// sid: session Id. -async fn handle_server_event( - fgid: GroupId, +async fn handle_event( addr: PeerId, event: LayerEvent, - layer: &Arc>, + global: &Arc, results: &mut HandleResult, ) -> Result<()> { - let gcd = event.gcd(); - let base = layer.read().await.base().clone(); - let (ogid, height, id) = layer.read().await.running(gcd)?.owner_height_id(); - let db = layer.read().await.group.read().await.group_db(&ogid)?; + let gid = event.gid(); + let (height, sid, id, gaddr) = global.layer.read().await.group(&gid)?.info(); + let pid = global.pid().await; + let db_key = global.group.read().await.db_key(&pid)?; + let db = group_db(&global.base, &pid, &db_key)?; + let is_server = gaddr == pid; + if !is_server && gaddr != addr { + warn!("INVALID EVENT NOT FROM THE SERVER."); + return Err(anyhow!("NOT THE SERVER EVENT")); + } match event { - LayerEvent::Offline(gcd) => { - // 1. check member online. - if layer.write().await.remove_online(&gcd, &fgid).is_none() { - return Ok(()); - } + LayerEvent::Offline(gid) => { + // SERVER & PEER + if is_server { + // 1. check member online. + if !global.layer.write().await.group_del_online(&gid, &addr) { + return Ok(()); + } - // 2. UI: offline the member. - if let Ok(mid) = Member::get_id(&db, &id, &fgid) { - results.rpcs.push(rpc::member_offline(ogid, id, mid)); - } + // 2. UI: offline the member. + if let Ok(mid) = Member::get_id(&db, &id, &addr) { + results.rpcs.push(rpc::member_offline(id, mid)); + } + + // 3. broadcast offline event. + broadcast(&gid, global, &LayerEvent::MemberOffline(gid, addr), results).await?; + } else { + // 1. offline group chat. + global.layer.write().await.group_del(&gid); - // 3. broadcast offline event. - broadcast(&LayerEvent::MemberOffline(gcd, fgid), layer, &gcd, results).await?; + // 2. UI: offline the session. + results.rpcs.push(session_lost(&sid)); + } + } + LayerEvent::Suspend(gid) => { + // PEER + if global + .layer + .write() + .await + .group_mut(&gid)? + .suspend(false, true) + .is_some() + { + results.rpcs.push(session_suspend(&sid)); + } + } + LayerEvent::Actived(gid) => { + // PEER + let _ = global.layer.write().await.group_mut(&gid)?.active(false); + results.rpcs.push(session_connect(&sid, &addr)); } - LayerEvent::GroupName(gcd, name) => { + LayerEvent::MemberOnline(_gid, mpid) => { + // PEER + if let Ok(mid) = Member::get_id(&db, &id, &mpid) { + results.rpcs.push(rpc::member_online(id, mid)); + } + } + LayerEvent::MemberOffline(_gid, mpid) => { + // PEER + if let Ok(mid) = Member::get_id(&db, &id, &mpid) { + results.rpcs.push(rpc::member_offline(id, mid)); + } + } + LayerEvent::MemberOnlineSync(gid) => { + // SERVER + let onlines = global.layer.read().await.group(&gid)?.addrs.clone(); + let event = LayerEvent::MemberOnlineSyncResult(gid, onlines); + let data = bincode::serialize(&event).unwrap_or(vec![]); + let msg = SendType::Event(0, addr, data); + results.layers.push((GROUP_CHAT_ID, msg)); + } + LayerEvent::MemberOnlineSyncResult(_gid, onlines) => { + // PEER + for mpid in onlines { + if let Ok(mid) = Member::get_id(&db, &id, &mpid) { + results.rpcs.push(rpc::member_online(id, mid)); + } + } + } + LayerEvent::GroupName(gid, name) => { + // SERVER & PEER // 1. update group name let _ = GroupChat::update_name(&db, &id, &name)?; + // 2. UI: update - results.rpcs.push(rpc::group_name(ogid, &id, &name)); - if let Ok(sid) = Session::update_name_by_id( - &layer.read().await.group.read().await.session_db(&ogid)?, - &id, - &SessionType::Group, - &name, - ) { - results.rpcs.push(session_update_name(ogid, &sid, &name)); + results.rpcs.push(rpc::group_name(&id, &name)); + let s_db = session_db(&global.base, &pid, &db_key)?; + let _ = Session::update_name(&s_db, &sid, &name); + results.rpcs.push(session_update_name(&sid, &name)); + + if is_server { + // 3. broadcast + broadcast(&gid, global, &LayerEvent::GroupName(gid, name), results).await?; } - // 3. broadcast - broadcast(&LayerEvent::GroupName(gcd, name), layer, &gcd, results).await?; } - LayerEvent::Sync(gcd, _, event) => { + LayerEvent::GroupClose(gid) => { + // PEER + let group = GroupChat::close(&db, &id)?; + let s_db = session_db(&global.base, &pid, &db_key)?; + let sid = Session::close(&s_db, &group.id, &SessionType::Group)?; + results.rpcs.push(session_close(&sid)); + } + LayerEvent::Sync(gid, height, event) => { + // SERVER & PEER + debug!("Sync: handle is_server: {} height: {} ", is_server, height); match event { - Event::MemberJoin(mgid, maddr, mname, mavatar) => { - let mdid_res = Member::get_id(&db, &id, &mgid); - let h = layer.write().await.running_mut(&gcd)?.increased(); - let new_e = Event::MemberJoin(mgid, maddr, mname.clone(), mavatar.clone()); + Event::MemberJoin(mpid, mname, mavatar) => { + let mid_res = Member::get_id(&db, &id, &mpid); + let h = if is_server { + global.layer.write().await.group_mut(&gid)?.increased() + } else { + height + }; - if let Ok(mdid) = mdid_res { - Member::update(&db, &h, &mdid, &maddr, &mname)?; + if let Ok(mid) = mid_res { + Member::update(&db, &h, &mid, &mname)?; if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; + write_avatar_sync(&global.base, &pid, &mpid, mavatar.clone())?; } - let mem = Member::info(mdid, id, mgid, maddr, mname); - results.rpcs.push(rpc::member_join(ogid, &mem)); + let mem = Member::info(mid, id, mpid, mname.clone()); + results.rpcs.push(rpc::member_join(&mem)); } else { - let mut member = Member::new(h, id, mgid, maddr, mname); + let mut member = Member::new(h, id, mpid, mname.clone()); member.insert(&db)?; if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; + write_avatar_sync(&global.base, &pid, &mpid, mavatar.clone())?; } - results.rpcs.push(rpc::member_join(ogid, &member)); + results.rpcs.push(rpc::member_join(&member)); } - // broadcast GroupChat::add_height(&db, id, h)?; - broadcast(&LayerEvent::Sync(gcd, h, new_e), layer, &gcd, results).await?; + if is_server { + // broadcast + let new_e = Event::MemberJoin(mpid, mname, mavatar); + broadcast(&gid, global, &LayerEvent::Sync(gid, h, new_e), results).await?; + } } - Event::MemberLeave(mgid) => { - let mdid = Member::get_id(&db, &id, &mgid)?; - let h = layer.write().await.running_mut(&gcd)?.increased(); - Member::leave(&db, &mdid, &h)?; + Event::MemberLeave(mpid) => { + let mid = Member::get_id(&db, &id, &mpid)?; + let h = if is_server { + global.layer.write().await.group_mut(&gid)?.increased() + } else { + height + }; + Member::leave(&db, &mid, &h)?; // check mid is my chat friend. if not, delete avatar. - let s_db = &layer.read().await.group.read().await.chat_db(&ogid)?; - if Friend::get_id(&s_db, &mgid).is_err() { - let _ = delete_avatar(&base, &ogid, &mgid).await; + let c_db = chat_db(&global.base, &pid, &db_key)?; + if Friend::get_id(&c_db, &mpid).is_err() { + let _ = delete_avatar(&global.base, &pid, &mpid).await; } - results.rpcs.push(rpc::member_leave(ogid, id, mdid)); + results.rpcs.push(rpc::member_leave(id, mid)); // broadcast GroupChat::add_height(&db, id, h)?; - broadcast(&LayerEvent::Sync(gcd, h, event), layer, &gcd, results).await?; + if is_server { + broadcast(&gid, global, &LayerEvent::Sync(gid, h, event), results).await?; + } } - Event::MessageCreate(mgid, nmsg, mtime) => { + Event::MessageCreate(mpid, nmsg, mtime) => { debug!("Sync: create message start"); - let _mdid = Member::get_id(&db, &id, &mgid)?; - - let new_e = Event::MessageCreate(mgid, nmsg.clone(), mtime); - let new_h = layer.write().await.running_mut(&gcd)?.increased(); - broadcast(&LayerEvent::Sync(gcd, new_h, new_e), layer, &gcd, results).await?; - GroupChat::add_height(&db, id, new_h)?; + let _mid = Member::get_id(&db, &id, &mpid)?; + let h = if is_server { + global.layer.write().await.group_mut(&gid)?.increased() + } else { + height + }; let msg = handle_network_message( - &layer.read().await.group, - new_h, + &pid, + &global.base, + &db_key, + h, id, - mgid, - &ogid, - nmsg, + mpid, + nmsg.clone(), mtime, - &base, results, ) .await?; - results.rpcs.push(rpc::message_create(ogid, &msg)); + results.rpcs.push(rpc::message_create(&msg)); debug!("Sync: create message ok"); // UPDATE SESSION. - if let Ok(s_db) = layer.read().await.group.read().await.session_db(&ogid) { - update_session(&s_db, &ogid, &id, &msg, results); + let s_db = session_db(&global.base, &pid, &db_key)?; + update_session(&s_db, &id, &msg, results); + + GroupChat::add_height(&db, id, h)?; + if is_server { + let new_e = Event::MessageCreate(mpid, nmsg, mtime); + broadcast(&gid, global, &LayerEvent::Sync(gid, h, new_e), results).await?; } } } } - LayerEvent::MemberOnlineSync(gcd) => { - let onlines = layer - .read() - .await - .running(&gcd)? - .onlines() - .iter() - .map(|(g, a)| (**g, **a)) - .collect(); - let event = LayerEvent::MemberOnlineSyncResult(gcd, onlines); - let data = bincode::serialize(&event).unwrap_or(vec![]); - let s = SendType::Event(0, addr, data); - add_server_layer(results, fgid, s); - } - LayerEvent::SyncReq(gcd, from) => { + LayerEvent::SyncReq(gid, from) => { + // SERVER debug!("Got sync request. height: {} from: {}", height, from); if height >= from { @@ -370,233 +389,80 @@ async fn handle_server_event( height }; - let (members, leaves) = Member::sync(&base, &ogid, &db, &id, &from, &to).await?; - let messages = Message::sync(&base, &ogid, &db, &id, &from, &to).await?; - let event = LayerEvent::SyncRes(gcd, height, from, to, members, leaves, messages); + let (members, leaves) = + Member::sync(&global.base, &pid, &db, &id, &from, &to).await?; + let messages = Message::sync(&global.base, &pid, &db, &id, &from, &to).await?; + let event = LayerEvent::SyncRes(gid, height, from, to, members, leaves, messages); let data = bincode::serialize(&event).unwrap_or(vec![]); let s = SendType::Event(0, addr, data); - add_server_layer(results, fgid, s); + results.layers.push((GROUP_CHAT_ID, s)); debug!("Sended sync request results. from: {}, to: {}", from, to); } } - LayerEvent::Suspend(..) => {} - LayerEvent::Actived(..) => {} - _ => error!("group server handle event nerver here"), - } - - Ok(()) -} - -// variable statement: -// gcd: Group Chat ID. -// fgid: where is event come from. -// ogid: my account ID. if server is group owner. if client is my. -// mgid: member account ID. -// id: Group Chat database Id. -// mdid: member database Id. -// sid: session Id. -async fn handle_peer_event( - ogid: GroupId, - addr: PeerId, - event: LayerEvent, - layer: &Arc>, - results: &mut HandleResult, -) -> Result<()> { - let base = layer.read().await.base().clone(); - let gcd = event.gcd(); - let (sid, id) = layer.read().await.get_running_remote_id(&ogid, gcd)?; - let db = layer.read().await.group.read().await.group_db(&ogid)?; - - match event { - LayerEvent::Offline(gcd) => { - // 1. offline group chat. - layer - .write() - .await - .running_mut(&ogid)? - .check_offline(&gcd, &addr); - - // 2. UI: offline the session. - results.rpcs.push(session_lost(ogid, &sid)); - } - LayerEvent::Suspend(gcd) => { - if layer - .write() - .await - .running_mut(&ogid)? - .suspend(&gcd, false, true)? - { - results.rpcs.push(session_suspend(ogid, &sid)); - } - } - LayerEvent::Actived(gcd) => { - let _ = layer.write().await.running_mut(&ogid)?.active(&gcd, false); - results.rpcs.push(session_connect(ogid, &sid, &addr)); - } - LayerEvent::MemberOnline(_gcd, mgid, maddr) => { - if let Ok(mid) = Member::addr_update(&db, &id, &mgid, &maddr) { - results.rpcs.push(rpc::member_online(ogid, id, mid, &maddr)); - } - } - LayerEvent::MemberOffline(_gcd, mgid) => { - if let Ok(mid) = Member::get_id(&db, &id, &mgid) { - results.rpcs.push(rpc::member_offline(ogid, id, mid)); - } - } - LayerEvent::MemberOnlineSyncResult(_gcd, onlines) => { - for (mgid, maddr) in onlines { - if let Ok(mid) = Member::addr_update(&db, &id, &mgid, &maddr) { - results.rpcs.push(rpc::member_online(ogid, id, mid, &maddr)); - } - } - } - LayerEvent::GroupName(_gcd, name) => { - let _ = GroupChat::update_name(&db, &id, &name)?; - results.rpcs.push(rpc::group_name(ogid, &id, &name)); - let _ = Session::update_name( - &layer.read().await.group.read().await.session_db(&ogid)?, - &sid, - &name, - ); - results.rpcs.push(session_update_name(ogid, &sid, &name)); - } - LayerEvent::GroupClose(_gcd) => { - let group = GroupChat::close(&db, &gcd)?; - let sid = Session::close( - &layer.read().await.group.read().await.session_db(&ogid)?, - &group.id, - &SessionType::Group, - )?; - results.rpcs.push(session_close(ogid, &sid)); - } - LayerEvent::Sync(_gcd, height, event) => { - debug!("Sync: handle height: {}", height); - - match event { - Event::MemberJoin(mgid, maddr, mname, mavatar) => { - let mdid_res = Member::get_id(&db, &id, &mgid); - if let Ok(mdid) = mdid_res { - Member::update(&db, &height, &mdid, &maddr, &mname)?; - if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; - } - let mem = Member::info(mdid, id, mgid, maddr, mname); - results.rpcs.push(rpc::member_join(ogid, &mem)); - } else { - let mut member = Member::new(height, id, mgid, maddr, mname); - member.insert(&db)?; - if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; - } - results.rpcs.push(rpc::member_join(ogid, &member)); - } - - // save consensus. - GroupChat::add_height(&db, id, height)?; - } - Event::MemberLeave(mgid) => { - let mdid = Member::get_id(&db, &id, &mgid)?; - Member::leave(&db, &height, &mdid)?; - - // check mid is my chat friend. if not, delete avatar. - let s_db = &layer.read().await.group.read().await.chat_db(&ogid)?; - if Friend::get_id(&s_db, &mgid).is_err() { - let _ = delete_avatar(&base, &ogid, &mgid).await; - } - results.rpcs.push(rpc::member_leave(ogid, id, mdid)); - - // save consensus. - GroupChat::add_height(&db, id, height)?; - } - Event::MessageCreate(mgid, nmsg, mtime) => { - debug!("Sync: create message start"); - let _mdid = Member::get_id(&db, &id, &mgid)?; - - let msg = handle_network_message( - &layer.read().await.group, - height, - id, - mgid, - &ogid, - nmsg, - mtime, - &base, - results, - ) - .await?; - results.rpcs.push(rpc::message_create(ogid, &msg)); - - GroupChat::add_height(&db, id, height)?; - debug!("Sync: create message ok"); - - // UPDATE SESSION. - if let Ok(s_db) = layer.read().await.group.read().await.session_db(&ogid) { - update_session(&s_db, &ogid, &id, &msg, results); - } - } - } - } - LayerEvent::SyncRes(gcd, height, from, to, adds, leaves, messages) => { + LayerEvent::SyncRes(gid, height, from, to, adds, leaves, messages) => { + // PEER if to >= height { + results.layers.push((GROUP_CHAT_ID, sync_online(gid, addr))); // when last packed sync, start sync online members. - add_layer(results, ogid, sync_online(gcd, addr)); } debug!("Start handle sync packed... {}, {}, {}", height, from, to); let mut last_message = None; - for (height, mgid, maddr, mname, mavatar) in adds { - let mdid_res = Member::get_id(&db, &id, &mgid); - if let Ok(mdid) = mdid_res { - Member::update(&db, &height, &mdid, &maddr, &mname)?; + for (height, mpid, mname, mavatar) in adds { + let mid_res = Member::get_id(&db, &id, &mpid); + if let Ok(mid) = mid_res { + Member::update(&db, &height, &mid, &mname)?; if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; + write_avatar_sync(&global.base, &pid, &mpid, mavatar)?; } - let mem = Member::info(mdid, id, mgid, maddr, mname); - results.rpcs.push(rpc::member_join(ogid, &mem)); + let mem = Member::info(mid, id, mpid, mname); + results.rpcs.push(rpc::member_join(&mem)); } else { - let mut member = Member::new(height, id, mgid, maddr, mname); + let mut member = Member::new(height, id, mpid, mname); member.insert(&db)?; if mavatar.len() > 0 { - write_avatar_sync(&base, &ogid, &mgid, mavatar)?; + write_avatar_sync(&global.base, &pid, &mpid, mavatar)?; } - results.rpcs.push(rpc::member_join(ogid, &member)); + results.rpcs.push(rpc::member_join(&member)); } } - for (height, mgid) in leaves { - if let Ok(mdid) = Member::get_id(&db, &id, &mgid) { - Member::leave(&db, &height, &mdid)?; + let c_db = chat_db(&global.base, &pid, &db_key)?; + for (height, mpid) in leaves { + if let Ok(mid) = Member::get_id(&db, &id, &mpid) { + Member::leave(&db, &height, &mid)?; // check mid is my chat friend. if not, delete avatar. - let s_db = &layer.read().await.group.read().await.chat_db(&ogid)?; - if Friend::get_id(&s_db, &mgid).is_err() { - let _ = delete_avatar(&base, &ogid, &mgid).await; + if Friend::get_id(&c_db, &mpid).is_err() { + let _ = delete_avatar(&global.base, &pid, &mpid).await; } - results.rpcs.push(rpc::member_leave(ogid, id, mdid)); + results.rpcs.push(rpc::member_leave(id, mid)); } } - for (height, mgid, nm, time) in messages { + for (height, mpid, nm, time) in messages { if let Ok(msg) = handle_network_message( - &layer.read().await.group, + &pid, + &global.base, + &db_key, height, id, - mgid, - &ogid, + mpid, nm, time, - &base, results, ) .await { - results.rpcs.push(rpc::message_create(ogid, &msg)); + results.rpcs.push(rpc::message_create(&msg)); last_message = Some(msg); } } if to < height { - add_layer(results, ogid, sync(gcd, addr, to + 1)); + results + .layers + .push((GROUP_CHAT_ID, sync(gid, addr, to + 1))); } // update group chat height. @@ -604,43 +470,35 @@ async fn handle_peer_event( // UPDATE SESSION. if let Some(msg) = last_message { - if let Ok(s_db) = layer.read().await.group.read().await.session_db(&ogid) { - update_session(&s_db, &ogid, &id, &msg, results); - } + let s_db = session_db(&global.base, &pid, &db_key)?; + update_session(&s_db, &id, &msg, results); } debug!("Over handle sync packed... {}, {}, {}", height, from, to); } - _ => error!("group peer handle event nerver here"), } Ok(()) } pub(crate) async fn broadcast( + gid: &GroupChatId, + global: &Arc, event: &LayerEvent, - layer: &Arc>, - gcd: &GroupId, results: &mut HandleResult, ) -> Result<()> { - let new_data = bincode::serialize(&event)?; + let new_data = bincode::serialize(event)?; - for (mgid, maddr) in layer.read().await.running(&gcd)?.onlines() { - let s = SendType::Event(0, *maddr, new_data.clone()); - add_server_layer(results, *mgid, s); - debug!("--- DEBUG broadcast to: {:?}", mgid); + for mpid in global.layer.read().await.group(gid)?.addrs.iter().skip(1) { + let s = SendType::Event(0, *mpid, new_data.clone()); + results.layers.push((GROUP_CHAT_ID, s)); + debug!("--- DEBUG broadcast to: {:?}", mpid); } Ok(()) } // UPDATE SESSION. -pub(crate) fn update_session( - s_db: &DStorage, - gid: &GroupId, - id: &i64, - msg: &Message, - results: &mut HandleResult, -) { +pub(crate) fn update_session(s_db: &DStorage, id: &i64, msg: &Message, results: &mut HandleResult) { let scontent = match msg.m_type { MessageType::String => { format!("{}:{}", msg.m_type.to_int(), msg.content) @@ -658,21 +516,22 @@ pub(crate) fn update_session( ) { results .rpcs - .push(session_last(*gid, &sid, &msg.datetime, &scontent, false)); + .push(session_last(&sid, &msg.datetime, &scontent, false)); } } -pub(crate) fn group_conn(proof: Proof, addr: Peer, gid: GroupId) -> SendType { - let data = bincode::serialize(&LayerConnect(gid, proof)).unwrap_or(vec![]); - SendType::Connect(0, addr, data) +pub(crate) fn group_conn(addr: PeerId, gid: GroupChatId, results: &mut HandleResult) { + let data = bincode::serialize(&LayerConnect(gid)).unwrap_or(vec![]); + let msg = SendType::Connect(0, Peer::peer(addr), data); + results.layers.push((GROUP_CHAT_ID, msg)); } -fn sync(gcd: GroupId, addr: PeerId, height: i64) -> SendType { - let data = bincode::serialize(&LayerEvent::SyncReq(gcd, height + 1)).unwrap_or(vec![]); +fn sync(gid: GroupChatId, addr: PeerId, height: i64) -> SendType { + let data = bincode::serialize(&LayerEvent::SyncReq(gid, height + 1)).unwrap_or(vec![]); SendType::Event(0, addr, data) } -fn sync_online(gcd: GroupId, addr: PeerId) -> SendType { - let data = bincode::serialize(&LayerEvent::MemberOnlineSync(gcd)).unwrap_or(vec![]); +fn sync_online(gid: GroupChatId, addr: PeerId) -> SendType { + let data = bincode::serialize(&LayerEvent::MemberOnlineSync(gid)).unwrap_or(vec![]); SendType::Event(0, addr, data) } diff --git a/src/apps/group/mod.rs b/src/apps/group/mod.rs index 9d08e5f..460ce8b 100644 --- a/src/apps/group/mod.rs +++ b/src/apps/group/mod.rs @@ -1,22 +1,7 @@ mod layer; mod models; -pub use group_types::GROUP_CHAT_ID as GROUP_ID; -use tdn::types::{group::GroupId, message::SendType, primitive::HandleResult}; - -/// Send to group chat service. -#[inline] -pub(crate) fn add_layer(results: &mut HandleResult, gid: GroupId, msg: SendType) { - results.layers.push((gid, GROUP_ID, msg)); -} - -/// Send to group chat member. -#[inline] -pub fn add_server_layer(results: &mut HandleResult, gid: GroupId, msg: SendType) { - results.layers.push((GROUP_ID, gid, msg)); -} - pub(crate) mod rpc; -pub(crate) use layer::{group_conn, handle_peer, handle_server}; -pub(crate) use models::GroupChat; +pub(crate) use layer::{group_conn, handle}; +pub(crate) use models::{GroupChat, Member}; pub(crate) use rpc::new_rpc_handler; diff --git a/src/apps/group/models/group.rs b/src/apps/group/models/group.rs index 0c48a2d..97e8a79 100644 --- a/src/apps/group/models/group.rs +++ b/src/apps/group/models/group.rs @@ -1,8 +1,8 @@ +use group_types::GroupChatId; use rand::Rng; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::GroupId, - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; @@ -18,11 +18,11 @@ pub(crate) struct GroupChat { /// consensus height. pub height: i64, /// group chat id. - pub g_id: GroupId, + pub gid: GroupChatId, /// group chat server addresse. - pub g_addr: PeerId, + pub addr: PeerId, /// group chat name. - pub g_name: String, + pub name: String, /// group is delete by owner. pub close: bool, /// group is in my device. @@ -30,13 +30,13 @@ pub(crate) struct GroupChat { } impl GroupChat { - pub fn new(g_addr: PeerId, g_name: String) -> Self { - let g_id = GroupId(rand::thread_rng().gen::<[u8; 32]>()); + pub fn new(addr: PeerId, name: String) -> Self { + let gid = rand::thread_rng().gen::(); Self { - g_id, - g_addr, - g_name, + gid, + addr, + name, id: 0, height: 0, close: false, @@ -44,11 +44,11 @@ impl GroupChat { } } - pub fn from(g_id: GroupId, height: i64, g_addr: PeerId, g_name: String) -> Self { + pub fn from(gid: GroupChatId, height: i64, addr: PeerId, name: String) -> Self { Self { - g_id, - g_addr, - g_name, + gid, + addr, + name, height, close: false, local: false, @@ -65,10 +65,10 @@ impl GroupChat { Session::new( self.id, - self.g_id, - self.g_addr, + self.gid.to_string(), + self.addr, SessionType::Group, - self.g_name.clone(), + self.name.clone(), datetime, ) } @@ -76,9 +76,9 @@ impl GroupChat { pub fn to_rpc(&self) -> RpcParam { json!([ self.id, - self.g_id.to_hex(), - self.g_addr.to_hex(), - self.g_name, + self.gid, + self.addr.to_hex(), + self.name, self.close, self.local, ]) @@ -88,9 +88,9 @@ impl GroupChat { Self { local: v.pop().unwrap().as_bool(), close: v.pop().unwrap().as_bool(), - g_name: v.pop().unwrap().as_string(), - g_addr: PeerId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), - g_id: GroupId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), + name: v.pop().unwrap().as_string(), + addr: PeerId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), + gid: v.pop().unwrap().as_i64() as GroupChatId, height: v.pop().unwrap().as_i64(), id: v.pop().unwrap().as_i64(), } @@ -98,7 +98,7 @@ impl GroupChat { pub fn local(db: &DStorage) -> Result> { let matrix = db.query( - "SELECT id, height, gcd, addr, name, is_close, is_local FROM groups WHERE is_local = true", + "SELECT id, height, gid, addr, name, is_close, is_local FROM groups WHERE is_local = true", )?; let mut groups = vec![]; for values in matrix { @@ -109,7 +109,7 @@ impl GroupChat { pub fn all(db: &DStorage) -> Result> { let matrix = - db.query("SELECT id, height, gcd, addr, name, is_close, is_local FROM groups")?; + db.query("SELECT id, height, gid, addr, name, is_close, is_local FROM groups")?; let mut groups = vec![]; for values in matrix { groups.push(Self::from_values(values)); @@ -119,7 +119,7 @@ impl GroupChat { pub fn get(db: &DStorage, id: &i64) -> Result { let sql = format!( - "SELECT id, height, gcd, addr, name, is_close, is_local FROM groups WHERE id = {}", + "SELECT id, height, gid, addr, name, is_close, is_local FROM groups WHERE id = {}", id ); let mut matrix = db.query(&sql)?; @@ -131,11 +131,8 @@ impl GroupChat { } } - pub fn get_id(db: &DStorage, gid: &GroupId) -> Result { - let sql = format!( - "SELECT id, height, gcd, addr, name, is_close, is_local FROM groups WHERE gcd = '{}'", - gid.to_hex() - ); + pub fn get_id(db: &DStorage, gid: &GroupChatId, addr: &PeerId) -> Result { + let sql = format!("SELECT id, height, gid, addr, name, is_close, is_local FROM groups WHERE gid = {} AND addr = '{}'", gid, addr.to_hex()); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { let values = matrix.pop().unwrap(); // safe unwrap() @@ -147,27 +144,20 @@ impl GroupChat { pub fn insert(&mut self, db: &DStorage) -> Result<()> { let mut unique_check = db.query(&format!( - "SELECT id from groups WHERE gcd = '{}'", - self.g_id.to_hex() + "SELECT id from groups WHERE gid = {} AND addr = '{}'", + self.gid, + self.addr.to_hex() ))?; if unique_check.len() > 0 { - let id = unique_check.pop().unwrap().pop().unwrap().as_i64(); - self.id = id; - let sql = format!( - "UPDATE groups SET height = {}, addr='{}', name = '{}' WHERE id = {}", - self.height, - self.g_addr.to_hex(), - self.g_name, - self.id - ); - db.update(&sql)?; + self.gid += 1; + return self.insert(db); } else { let sql = format!( - "INSERT INTO groups (height, gcd, addr, name, is_close, is_local) VALUES ({}, '{}', '{}', '{}', {}, {})", + "INSERT INTO groups (height, gid, addr, name, is_close, is_local) VALUES ({}, {}, '{}', '{}', {}, {})", self.height, - self.g_id.to_hex(), - self.g_addr.to_hex(), - self.g_name, + self.gid, + self.addr.to_hex(), + self.name, self.close, self.local, ); @@ -187,8 +177,14 @@ impl GroupChat { db.update(&sql) } - pub fn close(db: &DStorage, gcd: &GroupId) -> Result { - let group = Self::get_id(db, gcd)?; + pub fn close(db: &DStorage, id: &i64) -> Result { + let sql = format!("UPDATE groups SET is_close = true WHERE id = {}", id); + db.update(&sql)?; + Self::get(db, id) + } + + pub fn close_id(db: &DStorage, gid: &GroupChatId, addr: &PeerId) -> Result { + let group = Self::get_id(db, gid, addr)?; let sql = format!("UPDATE groups SET is_close = true WHERE id = {}", group.id); db.update(&sql)?; Ok(group) diff --git a/src/apps/group/models/member.rs b/src/apps/group/models/member.rs index 930f5d4..685076f 100644 --- a/src/apps/group/models/member.rs +++ b/src/apps/group/models/member.rs @@ -1,7 +1,7 @@ +use esse_primitives::{id_from_str, id_to_str}; use std::path::PathBuf; use tdn::types::{ - group::GroupId, - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; @@ -16,36 +16,32 @@ pub(crate) struct Member { pub height: i64, /// group's db id. pub fid: i64, - /// member's Did(GroupId) - pub m_id: GroupId, - /// member's addresse. - pub m_addr: PeerId, + /// member's Did(PeerId) + pub pid: PeerId, /// member's name. - pub m_name: String, + pub name: String, /// if leave from group. pub leave: bool, } impl Member { - pub fn new(height: i64, fid: i64, m_id: GroupId, m_addr: PeerId, m_name: String) -> Self { + pub fn new(height: i64, fid: i64, pid: PeerId, name: String) -> Self { Self { height, fid, - m_id, - m_addr, - m_name, + pid, + name, leave: false, id: 0, } } - pub fn info(id: i64, fid: i64, m_id: GroupId, m_addr: PeerId, m_name: String) -> Self { + pub fn info(id: i64, fid: i64, pid: PeerId, name: String) -> Self { Self { id, fid, - m_id, - m_addr, - m_name, + pid, + name, leave: false, height: 0, } @@ -55,9 +51,8 @@ impl Member { json!([ self.id, self.fid, - self.m_id.to_hex(), - self.m_addr.to_hex(), - self.m_name, + id_to_str(&self.pid), + self.name, self.leave, ]) } @@ -65,9 +60,8 @@ impl Member { fn from_values(mut v: Vec) -> Self { Self { leave: v.pop().unwrap().as_bool(), - m_name: v.pop().unwrap().as_string(), - m_addr: PeerId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), - m_id: GroupId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), + name: v.pop().unwrap().as_string(), + pid: id_from_str(v.pop().unwrap().as_str()).unwrap_or(Default::default()), fid: v.pop().unwrap().as_i64(), height: v.pop().unwrap().as_i64(), id: v.pop().unwrap().as_i64(), @@ -76,7 +70,7 @@ impl Member { pub fn list(db: &DStorage, fid: &i64) -> Result> { let matrix = db.query(&format!( - "SELECT id, height, fid, mid, addr, name, leave FROM members WHERE fid = {}", + "SELECT id, height, fid, pid, name, leave FROM members WHERE fid = {}", fid ))?; let mut groups = vec![]; @@ -88,28 +82,24 @@ impl Member { pub fn insert(&mut self, db: &DStorage) -> Result<()> { let mut unique_check = db.query(&format!( - "SELECT id from members WHERE fid = {} AND mid = '{}'", + "SELECT id from members WHERE fid = {} AND pid = '{}'", self.fid, - self.m_id.to_hex() + id_to_str(&self.pid) ))?; if unique_check.len() > 0 { let id = unique_check.pop().unwrap().pop().unwrap().as_i64(); self.id = id; let sql = format!( - "UPDATE members SET height = {}, addr='{}', name = '{}', leave = false WHERE id = {}", - self.height, - self.m_addr.to_hex(), - self.m_name, - self.id, + "UPDATE members SET height = {}, name = '{}', leave = false WHERE id = {}", + self.height, self.name, self.id, ); db.update(&sql)?; } else { - let sql = format!("INSERT INTO members (height, fid, mid, addr, name, leave) VALUES ({}, {}, '{}', '{}', '{}', false)", + let sql = format!("INSERT INTO members (height, fid, pid, name, leave) VALUES ({}, {}, '{}', '{}', false)", self.height, self.fid, - self.m_id.to_hex(), - self.m_addr.to_hex(), - self.m_name, + id_to_str(&self.pid), + self.name, ); let id = db.insert(&sql)?; self.id = id; @@ -119,7 +109,7 @@ impl Member { pub fn _get(db: &DStorage, id: &i64) -> Result { let mut matrix = db.query(&format!( - "SELECT id, height, fid, mid, addr, name, leave FROM members WHERE id = {}", + "SELECT id, height, fid, pid, name, leave FROM members WHERE id = {}", id, ))?; if matrix.len() > 0 { @@ -129,11 +119,11 @@ impl Member { } } - pub fn get_id(db: &DStorage, fid: &i64, gid: &GroupId) -> Result { + pub fn get_id(db: &DStorage, fid: &i64, pid: &PeerId) -> Result { let mut matrix = db.query(&format!( - "SELECT id FROM members WHERE fid = {} AND mid = '{}'", + "SELECT id FROM members WHERE fid = {} AND pid = '{}'", fid, - gid.to_hex() + id_to_str(pid) ))?; if matrix.len() > 0 { Ok(matrix.pop().unwrap().pop().unwrap().as_i64()) // safe unwrap. @@ -142,31 +132,10 @@ impl Member { } } - pub fn addr_update(db: &DStorage, fid: &i64, mid: &GroupId, addr: &PeerId) -> Result { - let mdid = Self::get_id(db, fid, mid)?; + pub fn update(db: &DStorage, id: &i64, height: &i64, name: &str) -> Result { let sql = format!( - "UPDATE members SET addr='{}' WHERE fid = {} AND mid = '{}'", - addr.to_hex(), - fid, - mid.to_hex(), - ); - db.update(&sql)?; - Ok(mdid) - } - - pub fn update( - db: &DStorage, - id: &i64, - height: &i64, - addr: &PeerId, - name: &str, - ) -> Result { - let sql = format!( - "UPDATE members SET height = {}, addr='{}', name='{}' WHERE id = {}", - height, - addr.to_hex(), - name, - id, + "UPDATE members SET height = {}, name='{}' WHERE id = {}", + height, name, id, ); db.update(&sql) } @@ -186,26 +155,23 @@ impl Member { pub async fn sync( base: &PathBuf, - gid: &GroupId, + gid: &PeerId, db: &DStorage, fid: &i64, from: &i64, to: &i64, - ) -> Result<( - Vec<(i64, GroupId, PeerId, String, Vec)>, - Vec<(i64, GroupId)>, - )> { - let sql = format!("SELECT id, height, fid, mid, addr, name, leave FROM members WHERE fid = {} AND height BETWEEN {} AND {}", fid, from, to); + ) -> Result<(Vec<(i64, PeerId, String, Vec)>, Vec<(i64, PeerId)>)> { + let sql = format!("SELECT id, height, fid, pid, name, leave FROM members WHERE fid = {} AND height BETWEEN {} AND {}", fid, from, to); let matrix = db.query(&sql)?; let mut adds = vec![]; let mut leaves = vec![]; for values in matrix { let m = Self::from_values(values); if m.leave { - leaves.push((m.height, m.m_id)); + leaves.push((m.height, m.pid)); } else { - let mavatar = read_avatar(base, gid, &m.m_id).await.unwrap_or(vec![]); - adds.push((m.height, m.m_id, m.m_addr, m.m_name, mavatar)) + let mavatar = read_avatar(base, gid, &m.pid).await.unwrap_or(vec![]); + adds.push((m.height, m.pid, m.name, mavatar)) } } Ok((adds, leaves)) diff --git a/src/apps/group/models/message.rs b/src/apps/group/models/message.rs index 963a64f..99b49fe 100644 --- a/src/apps/group/models/message.rs +++ b/src/apps/group/models/message.rs @@ -1,19 +1,17 @@ +use esse_primitives::id_from_str; use std::collections::HashMap; use std::path::PathBuf; -use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - group::GroupId, - primitive::{HandleResult, Result}, + primitives::{HandleResult, PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; -use tokio::sync::RwLock; use chat_types::{MessageType, NetworkMessage}; use crate::apps::chat::{from_network_message, raw_to_network_message, to_network_message as tnm}; -use crate::group::Group; +use crate::storage::group_db; use super::Member; @@ -141,18 +139,17 @@ impl Message { pub async fn sync( base: &PathBuf, - gid: &GroupId, + own: &PeerId, db: &DStorage, fid: &i64, from: &i64, to: &i64, - ) -> Result> { - let sql = format!("SELECT id, mid FROM members WHERE fid = {}", fid); + ) -> Result> { + let sql = format!("SELECT id, pid FROM members WHERE fid = {}", fid); let m = db.query(&sql)?; let mut members = HashMap::new(); for mut v in m { - let m_s = v.pop().unwrap().as_string(); - let mid = GroupId::from_hex(m_s).unwrap_or(Default::default()); + let mid = id_from_str(v.pop().unwrap().as_str()).unwrap_or(Default::default()); let id = v.pop().unwrap().as_i64(); members.insert(id, mid); } @@ -162,8 +159,8 @@ impl Message { let mut messages = vec![]; for values in matrix { let msg = Message::from_values(values); - if let Ok(nmsg) = tnm(base, gid, msg.m_type, msg.content).await { - let mid = members.get(&msg.mid).cloned().unwrap_or(GroupId::default()); + if let Ok(nmsg) = tnm(own, base, msg.m_type, msg.content).await { + let mid = members.get(&msg.mid).cloned().unwrap_or(PeerId::default()); messages.push((msg.height, mid, nmsg, msg.datetime)) } } @@ -173,9 +170,9 @@ impl Message { } pub(crate) async fn to_network_message( - group: &Arc>, + own: &PeerId, base: &PathBuf, - gid: &GroupId, + db_key: &str, mtype: MessageType, content: &str, ) -> Result<(NetworkMessage, i64, String)> { @@ -185,26 +182,26 @@ pub(crate) async fn to_network_message( .map(|s| s.as_secs()) .unwrap_or(0) as i64; // safe for all life. - let (nmsg, raw) = raw_to_network_message(group, base, gid, &mtype, content).await?; + let (nmsg, raw) = raw_to_network_message(own, base, db_key, &mtype, content).await?; Ok((nmsg, datetime, raw)) } pub(crate) async fn handle_network_message( - group: &Arc>, + own: &PeerId, + base: &PathBuf, + db_key: &str, height: i64, - gdid: i64, - mid: GroupId, - mgid: &GroupId, + id: i64, + mid: PeerId, msg: NetworkMessage, datetime: i64, - base: &PathBuf, results: &mut HandleResult, ) -> Result { - let db = group.read().await.group_db(mgid)?; - let mdid = Member::get_id(&db, &gdid, &mid)?; - let is_me = &mid == mgid; - let (m_type, raw) = from_network_message(group, msg, base, mgid, results).await?; - let mut msg = Message::new_with_time(height, gdid, mdid, is_me, m_type, raw, datetime); + let db = group_db(base, own, db_key)?; + let mdid = Member::get_id(&db, &id, &mid)?; + let is_me = &mid == own; + let (m_type, raw) = from_network_message(own, base, db_key, msg, results).await?; + let mut msg = Message::new_with_time(height, id, mdid, is_me, m_type, raw, datetime); msg.insert(&db)?; Ok(msg) } diff --git a/src/apps/group/rpc.rs b/src/apps/group/rpc.rs index 812491c..3cef2a7 100644 --- a/src/apps/group/rpc.rs +++ b/src/apps/group/rpc.rs @@ -1,57 +1,49 @@ +use chat_types::{MessageType, CHAT_ID}; +use group_types::{Event, LayerEvent, GROUP_CHAT_ID}; use std::sync::Arc; use tdn::types::{ - group::GroupId, - message::{NetworkType, SendMessage, SendType}, - primitive::{HandleResult, PeerId}, + message::{RpcSendMessage, SendType}, + primitives::{HandleResult, PeerId}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; -use chat_types::MessageType; -use group_types::{Event, LayerEvent}; - -use crate::apps::chat::{Friend, InviteType}; -use crate::layer::Online; -use crate::rpc::{session_create, session_delete, session_update_name, RpcState}; +use crate::apps::chat::{raw_to_network_message, Friend, InviteType}; +use crate::global::Global; +use crate::rpc::{session_create, session_delete, session_update_name}; use crate::session::{Session, SessionType}; -use crate::storage::{read_avatar, write_avatar}; +use crate::storage::{chat_db, group_db, read_avatar, session_db, write_avatar}; use super::layer::{broadcast, update_session}; use super::models::{to_network_message, GroupChat, Member, Message}; -use super::{add_layer, add_server_layer}; #[inline] -pub(crate) fn member_join(mgid: GroupId, member: &Member) -> RpcParam { - rpc_response(0, "group-member-join", json!(member.to_rpc()), mgid) +pub(crate) fn member_join(member: &Member) -> RpcParam { + rpc_response(0, "group-member-join", json!(member.to_rpc())) } #[inline] -pub(crate) fn member_leave(mgid: GroupId, id: i64, mid: i64) -> RpcParam { - rpc_response(0, "group-member-leave", json!([id, mid]), mgid) +pub(crate) fn member_leave(id: i64, mid: i64) -> RpcParam { + rpc_response(0, "group-member-leave", json!([id, mid])) } #[inline] -pub(crate) fn member_online(mgid: GroupId, id: i64, mid: i64, maddr: &PeerId) -> RpcParam { - rpc_response( - 0, - "group-member-online", - json!([id, mid, maddr.to_hex()]), - mgid, - ) +pub(crate) fn member_online(id: i64, mid: i64) -> RpcParam { + rpc_response(0, "group-member-online", json!([id, mid])) } #[inline] -pub(crate) fn member_offline(mgid: GroupId, gid: i64, mid: i64) -> RpcParam { - rpc_response(0, "group-member-offline", json!([gid, mid]), mgid) +pub(crate) fn member_offline(id: i64, mid: i64) -> RpcParam { + rpc_response(0, "group-member-offline", json!([id, mid])) } #[inline] -pub(crate) fn group_name(mgid: GroupId, gid: &i64, name: &str) -> RpcParam { - rpc_response(0, "group-name", json!([gid, name]), mgid) +pub(crate) fn group_name(id: &i64, name: &str) -> RpcParam { + rpc_response(0, "group-name", json!([id, name])) } #[inline] -pub(crate) fn message_create(mgid: GroupId, msg: &Message) -> RpcParam { - rpc_response(0, "group-message-create", json!(msg.to_rpc()), mgid) +pub(crate) fn message_create(msg: &Message) -> RpcParam { + rpc_response(0, "group-message-create", json!(msg.to_rpc())) } #[inline] @@ -79,20 +71,26 @@ fn detail_list(group: GroupChat, members: Vec, messages: Vec) - json!([group.to_rpc(), member_results, message_results]) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.group_db(&gid)?; + |_params: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = group_db(&state.base, &pid, &db_key)?; + Ok(HandleResult::rpc(group_list(GroupChat::all(&db)?))) }, ); handler.add_method( "group-detail", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.group_db(&gid)?; + + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = group_db(&state.base, &pid, &db_key)?; let group = GroupChat::get(&db, &id)?; let members = Member::list(&db, &id)?; let messages = Message::list(&db, &id)?; @@ -102,65 +100,51 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let name = params[0].as_str().ok_or(RpcError::ParseError)?.to_owned(); + let pid = state.pid().await; let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let addr = group_lock.addr().clone(); - let sender = group_lock.sender(); - let me = group_lock.clone_user(&gid)?; - let db = group_lock.group_db(&gid)?; - let s_db = group_lock.session_db(&gid)?; + let db_key = group_lock.db_key(&pid)?; + let me = group_lock.clone_user(&pid)?; drop(group_lock); - let mut gc = GroupChat::new(addr, name); - let gcd = gc.g_id; - let gheight = gc.height + 1; // add first member. + let db = group_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; + + let mut gc = GroupChat::new(pid, name); + let gh = gc.height + 1; // add first member. // save db gc.insert(&db)?; - let gdid = gc.id; + let id = gc.id; + let gid = gc.gid; let mut results = HandleResult::new(); - let mut m = Member::new(gheight, gc.id, gid, me.addr, me.name); + let mut m = Member::new(gh, id, pid, me.name); m.insert(&db)?; - let mid = m.id; - let _ = write_avatar(&base, &gid, &gid, &me.avatar).await; + let _ = write_avatar(&state.base, &pid, &pid, &me.avatar).await; // Add new session. let mut session = gc.to_session(); session.insert(&s_db)?; let sid = session.id; + let sender = state.rpc_send.clone(); tokio::spawn(async move { let _ = sender - .send(SendMessage::Rpc(0, session_create(gid, &session), true)) + .send(RpcSendMessage(0, session_create(&session), true)) .await; }); // add to rpcs. - results.rpcs.push(json!([sid, gdid])); + results.rpcs.push(json!([sid, id])); // Add frist member join. - let mut layer_lock = state.layer.write().await; - layer_lock.add_running(&gcd, gid, gdid, gheight)?; - - // Add online to layers. - layer_lock - .running_mut(&gcd)? - .check_add_online(gid, Online::Direct(addr), gdid, mid)?; - layer_lock - .running_mut(&gid)? - .check_add_online(gcd, Online::Direct(addr), sid, gdid)?; - - drop(layer_lock); + state.layer.write().await.group_add(gid, pid, sid, id, gh); // Update consensus. - GroupChat::add_height(&db, gdid, gheight)?; - - // Online local group. - results.networks.push(NetworkType::AddGroup(gcd)); + GroupChat::add_height(&db, id, gh)?; Ok(results) }, @@ -168,65 +152,60 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-member-join", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let fid = params[1].as_i64().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let chat_db = group_lock.chat_db(&gid)?; - let group_db = group_lock.group_db(&gid)?; - let s_db = group_lock.session_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let group_db = group_db(&state.base, &pid, &db_key)?; + let chat_db = chat_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; + let f = Friend::get(&chat_db, &fid)?; let g = GroupChat::get(&group_db, &id)?; - let gcd = g.g_id; + let gid = g.gid; let mut results = HandleResult::new(); // handle invite message - let contact_values = InviteType::Group(gcd, g.g_addr, g.g_name).serialize(); - let (msg, nw) = crate::apps::chat::LayerEvent::from_message( - &state.group, - &base, - gid, - fid, - MessageType::Invite, - &contact_values, - ) - .await?; - let event = crate::apps::chat::LayerEvent::Message(msg.hash, nw); - let mut layer_lock = state.layer.write().await; - let s = crate::apps::chat::event_message(&mut layer_lock, msg.id, gid, f.addr, &event); - drop(layer_lock); - results.layers.push((gid, f.gid, s)); - crate::apps::chat::update_session(&s_db, &gid, &id, &msg, &mut results); + let contact = InviteType::Group(gid, g.addr, g.name).serialize(); + let m_type = MessageType::Invite; + let (nm, raw) = + raw_to_network_message(&pid, &state.base, &db_key, &m_type, &contact).await?; + let mut msg = crate::apps::chat::Message::new(&pid, f.id, true, m_type, raw, false); + msg.insert(&chat_db)?; + let event = crate::apps::chat::LayerEvent::Message(msg.hash, nm); + let tid = state.layer.write().await.delivery(msg.id); + let data = bincode::serialize(&event).unwrap_or(vec![]); + let lmsg = SendType::Event(tid, f.pid, data); + results.layers.push((CHAT_ID, lmsg)); + + // update session. + crate::apps::chat::update_session(&s_db, &id, &msg, &mut results); // handle group member - let avatar = read_avatar(&base, &gid, &f.gid).await.unwrap_or(vec![]); - let event = Event::MemberJoin(f.gid, f.addr, f.name.clone(), avatar); + let avatar = read_avatar(&state.base, &pid, &f.pid) + .await + .unwrap_or(vec![]); + let event = Event::MemberJoin(f.pid, f.name.clone(), avatar); if g.local { // local save. - let new_h = state.layer.write().await.running_mut(&gcd)?.increased(); + let new_h = state.layer.write().await.group_mut(&gid)?.increased(); - let mut mem = Member::new(new_h, g.id, f.gid, f.addr, f.name); + let mut mem = Member::new(new_h, g.id, f.pid, f.name); mem.insert(&group_db)?; results.rpcs.push(mem.to_rpc()); GroupChat::add_height(&group_db, id, new_h)?; // broadcast. - broadcast( - &LayerEvent::Sync(gcd, new_h, event), - &state.layer, - &gcd, - &mut results, - ) - .await?; + let data = LayerEvent::Sync(gid, new_h, event); + broadcast(&gid, &state, &data, &mut results).await?; } else { // send to server. - let data = bincode::serialize(&LayerEvent::Sync(gcd, 0, event))?; - let msg = SendType::Event(0, g.g_addr, data); - add_layer(&mut results, gid, msg); + let data = bincode::serialize(&LayerEvent::Sync(gid, 0, event))?; + let msg = SendType::Event(0, g.addr, data); + results.layers.push((GROUP_CHAT_ID, msg)); } Ok(results) @@ -235,29 +214,28 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-message-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let m_type = MessageType::from_int(params[1].as_i64().ok_or(RpcError::ParseError)?); let m_content = params[2].as_str().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let db = group_lock.group_db(&gid)?; - let s_db = group_lock.session_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = group_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; let group = GroupChat::get(&db, &id)?; - let gcd = group.g_id; - let mid = Member::get_id(&db, &id, &gid)?; + let gid = group.gid; + let mid = Member::get_id(&db, &id, &pid)?; let mut results = HandleResult::new(); let (nmsg, datetime, raw) = - to_network_message(&state.group, &base, &gid, m_type, m_content).await?; - let event = Event::MessageCreate(gid, nmsg, datetime); + to_network_message(&pid, &state.base, &db_key, m_type, m_content).await?; + let event = Event::MessageCreate(pid, nmsg, datetime); if group.local { // local save. - let new_h = state.layer.write().await.running_mut(&gcd)?.increased(); + let new_h = state.layer.write().await.group_mut(&gid)?.increased(); let mut msg = Message::new_with_time(new_h, id, mid, true, m_type, raw, datetime); msg.insert(&db)?; @@ -265,21 +243,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { GroupChat::add_height(&db, id, new_h)?; // UPDATE SESSION. - update_session(&s_db, &gid, &id, &msg, &mut results); + update_session(&s_db, &id, &msg, &mut results); // broadcast. - broadcast( - &LayerEvent::Sync(gcd, new_h, event), - &state.layer, - &gcd, - &mut results, - ) - .await?; + let data = LayerEvent::Sync(gid, new_h, event); + broadcast(&gid, &state, &data, &mut results).await?; } else { // send to server. - let data = bincode::serialize(&LayerEvent::Sync(gcd, 0, event))?; - let msg = SendType::Event(0, group.g_addr, data); - add_layer(&mut results, gid, msg); + let data = bincode::serialize(&LayerEvent::Sync(gid, 0, event))?; + let msg = SendType::Event(0, group.addr, data); + results.layers.push((GROUP_CHAT_ID, msg)); } Ok(results) @@ -288,35 +261,31 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-name", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let name = params[1].as_str().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); - let group_lock = state.group.read().await; - let db = group_lock.group_db(&gid)?; - let s_db = group_lock.session_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = group_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; let g = GroupChat::get(&db, &id)?; - let d = bincode::serialize(&LayerEvent::GroupName(g.g_id, name.to_owned()))?; + let data = LayerEvent::GroupName(g.gid, name.to_owned()); if g.local { if let Ok(sid) = Session::update_name_by_id(&s_db, &id, &SessionType::Group, &name) { - results.rpcs.push(session_update_name(gid, &sid, &name)); + results.rpcs.push(session_update_name(&sid, &name)); } results.rpcs.push(json!([id, name])); - // dissolve group. - for (mgid, maddr) in state.layer.read().await.running(&g.g_id)?.onlines() { - let s = SendType::Event(0, *maddr, d.clone()); - add_server_layer(&mut results, *mgid, s); - } + broadcast(&g.gid, &state, &data, &mut results).await?; } else { - // leave group. - let msg = SendType::Event(0, g.g_addr, d); - add_layer(&mut results, gid, msg); + let d = bincode::serialize(&data)?; + let msg = SendType::Event(0, g.addr, d); + results.layers.push((GROUP_CHAT_ID, msg)); } Ok(results) @@ -325,33 +294,33 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let mut results = HandleResult::new(); - - let group_lock = state.group.read().await; - let db = group_lock.group_db(&gid)?; - let s_db = group_lock.session_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = group_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; let g = GroupChat::delete(&db, &id)?; - let sid = Session::delete(&s_db, &id, &SessionType::Group)?; - results.rpcs.push(session_delete(gid, &sid)); + results.rpcs.push(session_delete(&sid)); if g.local { // dissolve group. - let d = bincode::serialize(&LayerEvent::GroupClose(g.g_id))?; - for (mgid, maddr) in state.layer.read().await.running(&g.g_id)?.onlines() { - let s = SendType::Event(0, *maddr, d.clone()); - add_server_layer(&mut results, *mgid, s); + let data = bincode::serialize(&LayerEvent::GroupClose(g.gid))?; + if let Some(addrs) = state.layer.write().await.group_del(&g.gid) { + for addr in addrs { + let s = SendType::Event(0, addr, data.clone()); + results.layers.push((GROUP_CHAT_ID, s)); + } } } else { // leave group. - let d = bincode::serialize(&LayerEvent::Sync(g.g_id, 0, Event::MemberLeave(gid)))?; - let msg = SendType::Event(0, g.g_addr, d); - add_layer(&mut results, gid, msg); + let d = bincode::serialize(&LayerEvent::Sync(g.gid, 0, Event::MemberLeave(pid)))?; + let msg = SendType::Event(0, g.addr, d); + results.layers.push((GROUP_CHAT_ID, msg)); } Ok(results) diff --git a/src/apps/jarvis/models.rs b/src/apps/jarvis/models.rs index 768f00a..a02ea1b 100644 --- a/src/apps/jarvis/models.rs +++ b/src/apps/jarvis/models.rs @@ -1,6 +1,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ - primitive::Result, + primitives::Result, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; diff --git a/src/apps/jarvis/rpc.rs b/src/apps/jarvis/rpc.rs index 4e9fcaa..58f8274 100644 --- a/src/apps/jarvis/rpc.rs +++ b/src/apps/jarvis/rpc.rs @@ -1,9 +1,8 @@ use rand::Rng; use std::sync::Arc; use tdn::types::{ - group::GroupId, - message::SendMessage, - primitive::{HandleResult, Result}, + message::RpcSendMessage, + primitives::{HandleResult, Result}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; use tdn_did::Language; @@ -14,15 +13,15 @@ use chat_types::MessageType; use crate::account::lang_from_i64; use crate::apps::chat::raw_to_network_message; -use crate::rpc::RpcState; +use crate::global::Global; +use crate::storage::jarvis_db; use crate::utils::answer::load_answer; use super::models::Message; async fn reply( - sender: Sender, + sender: Sender, db: DStorage, - gid: GroupId, lang: Language, msg: Message, ) -> Result<()> { @@ -43,16 +42,18 @@ async fn reply( let mut reply = Message::new(msg.m_type, content, false); reply.insert(&db)?; - let res = rpc_response(0, "jarvis-create", reply.to_rpc(), gid); - sender.send(SendMessage::Rpc(0, res, true)).await?; + let res = rpc_response(0, "jarvis-create", reply.to_rpc()); + sender.send(RpcSendMessage(0, res, true)).await?; Ok(()) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "jarvis-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.jarvis_db(&gid)?; + |_params: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = jarvis_db(&state.base, &pid, &db_key)?; let devices = Message::list(&db)?; db.close()?; let mut results = vec![]; @@ -65,24 +66,22 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "jarvis-create", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let lang = lang_from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let m_type = MessageType::from_int(params[1].as_i64().ok_or(RpcError::ParseError)?); let content = params[2].as_str().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let base = group_lock.base().clone(); - let sender = group_lock.sender(); - let db = group_lock.jarvis_db(&gid)?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = jarvis_db(&state.base, &pid, &db_key)?; let (_, raw) = - raw_to_network_message(&state.group, &base, &gid, &m_type, content).await?; + raw_to_network_message(&pid, &state.base, &db_key, &m_type, content).await?; let mut msg = Message::new(m_type, raw, true); msg.insert(&db)?; let results = HandleResult::rpc(msg.to_rpc()); - tokio::spawn(reply(sender, db, gid, lang, msg)); + tokio::spawn(reply(state.rpc_send.clone(), db, lang, msg)); Ok(results) }, @@ -90,9 +89,11 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "jarvis-delete", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.jarvis_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = jarvis_db(&state.base, &pid, &db_key)?; Message::delete(&db, id)?; db.close()?; Ok(HandleResult::new()) diff --git a/src/apps/wallet/models.rs b/src/apps/wallet/models.rs index 9c08903..e1cb894 100644 --- a/src/apps/wallet/models.rs +++ b/src/apps/wallet/models.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use tdn::types::{ - primitive::Result, + primitives::Result, rpc::{json, RpcParam}, }; diff --git a/src/apps/wallet/rpc.rs b/src/apps/wallet/rpc.rs index 1ae16b4..e269863 100644 --- a/src/apps/wallet/rpc.rs +++ b/src/apps/wallet/rpc.rs @@ -1,8 +1,7 @@ use std::sync::Arc; use tdn::types::{ - group::GroupId, - message::SendMessage, - primitive::{HandleResult, Result}, + message::RpcSendMessage, + primitives::{HandleResult, Result}, rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, }; use tdn_did::{generate_btc_account, generate_eth_account, secp256k1::SecretKey}; @@ -16,7 +15,9 @@ use web3::{ Web3, }; -use crate::rpc::RpcState; +use crate::global::Global; +use crate::storage::{account_db, wallet_db}; +use crate::utils::crypto::{decrypt, encrypt}; use super::{ models::{Address, Balance, ChainToken, Network, Token}, @@ -42,34 +43,25 @@ fn token_list(network: Network, tokens: Vec) -> RpcParam { } #[inline] -fn res_balance( - gid: GroupId, - address: &str, - network: &Network, - balance: &str, - token: Option<&Token>, -) -> RpcParam { +fn res_balance(address: &str, network: &Network, balance: &str, token: Option<&Token>) -> RpcParam { if let Some(t) = token { rpc_response( 0, "wallet-balance", json!([address, network.to_i64(), balance, t.to_rpc()]), - gid, ) } else { rpc_response( 0, "wallet-balance", json!([address, network.to_i64(), balance]), - gid, ) } } async fn loop_token( - sender: Sender, + sender: Sender, db: DStorage, - gid: GroupId, network: Network, address: String, c_token: Option, @@ -83,8 +75,8 @@ async fn loop_token( let transport = Http::new(node)?; let web3 = Web3::new(transport); let balance = token_balance(&web3, &token.contract, &address, &token.chain).await?; - let res = res_balance(gid, &address, &network, &balance, Some(&token)); - sender.send(SendMessage::Rpc(0, res, true)).await?; + let res = res_balance(&address, &network, &balance, Some(&token)); + sender.send(RpcSendMessage(0, res, true)).await?; } else { match chain { ChainToken::ETH => { @@ -93,19 +85,19 @@ async fn loop_token( let balance = web3.eth().balance(address.parse()?, None).await?; let balance = balance.to_string(); let _ = Address::update_balance(&db, &address, &network, &balance); - let res = res_balance(gid, &address, &network, &balance, None); - sender.send(SendMessage::Rpc(0, res, true)).await?; + let res = res_balance(&address, &network, &balance, None); + sender.send(RpcSendMessage(0, res, true)).await?; for token in tokens { //tokio::time::sleep(std::time::Duration::from_secs(1)).await; let balance = token_balance(&web3, &token.contract, &address, &token.chain).await?; - let res = res_balance(gid, &address, &network, &balance, Some(&token)); + let res = res_balance(&address, &network, &balance, Some(&token)); // update & clean balances. // TODO - sender.send(SendMessage::Rpc(0, res, true)).await?; + sender.send(RpcSendMessage(0, res, true)).await?; } } ChainToken::BTC => { @@ -119,9 +111,8 @@ async fn loop_token( } async fn token_check( - sender: Sender, + sender: Sender, db: DStorage, - gid: GroupId, chain: ChainToken, network: Network, address: String, @@ -160,8 +151,8 @@ async fn token_check( .query("balanceOf", (account,), None, Default::default(), None) .await?; let balance = balance.to_string(); - let res = res_balance(gid, &address, &network, &balance, Some(&token)); - sender.send(SendMessage::Rpc(0, res, true)).await?; + let res = res_balance(&address, &network, &balance, Some(&token)); + sender.send(RpcSendMessage(0, res, true)).await?; Ok(()) } @@ -320,15 +311,18 @@ async fn nft_check(node: &str, c_str: &str, hash: &str) -> Result { Ok(format!("{:?}", owner)) } -pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { - handler.add_method("wallet-echo", |_, params, _| async move { +pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { + handler.add_method("wallet-echo", |params, _| async move { Ok(HandleResult::rpc(json!(params))) }); handler.add_method( "wallet-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.wallet_db(&gid)?; + |_params: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; + let addresses = Address::list(&db)?; Ok(HandleResult::rpc(wallet_list(addresses))) }, @@ -336,17 +330,20 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-generate", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let lock = params[1].as_str().ok_or(RpcError::ParseError)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; + let group_lock = state.group.read().await; - let mnemonic = group_lock.mnemonic(&gid, lock)?; - let account = group_lock.account(&gid)?; + let mnemonic = group_lock.mnemonic(&pid, lock, &state.secret)?; + let account = group_lock.account(&pid)?; let lang = account.lang(); let pass = account.pass.to_string(); let account_index = account.index as u32; - let db = group_lock.wallet_db(&gid)?; drop(group_lock); let mut results = HandleResult::new(); @@ -373,16 +370,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { address.insert(&db)?; results.rpcs.push(address.to_rpc()); if address.main { + let a_db = account_db(&state.base, &state.secret)?; let mut group_lock = state.group.write().await; - let a_db = group_lock.account_db()?; - let account = group_lock.account_mut(&gid)?; + let account = group_lock.account_mut(&pid)?; account.wallet = address.chain.update_main(&address.address, &account.wallet); account.pub_height = account.pub_height + 1; account.update_info(&a_db)?; - let user = group_lock.clone_user(&gid)?; + let user = group_lock.clone_user(&pid)?; drop(group_lock); - // broadcast all friends. + // broadcast to all friends. state.layer.read().await.broadcast(user, &mut results); } Ok(results) @@ -391,7 +388,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-import", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let secret = params[1].as_str().ok_or(RpcError::ParseError)?; let lock = params[2].as_str().ok_or(RpcError::ParseError)?; @@ -399,11 +396,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { let sk: SecretKey = secret.parse().or(Err(RpcError::ParseError))?; let addr = format!("{:?}", (&sk).address()); + let pid = state.pid().await; + let group_lock = state.group.read().await; - let cbytes = group_lock.encrypt(&gid, lock, sk.as_ref())?; - let db = group_lock.wallet_db(&gid)?; + let ckey = &group_lock.account(&pid)?.encrypt; + let db_key = group_lock.db_key(&pid)?; + let cbytes = encrypt(&state.secret, lock, ckey, sk.as_ref())?; drop(group_lock); + let db = wallet_db(&state.base, &pid, &db_key)?; + let mut address = Address::import(chain, addr, cbytes); address.insert(&db)?; Ok(HandleResult::rpc(address.to_rpc())) @@ -412,14 +414,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-token", - |gid: GroupId, params: Vec, state: Arc| async move { - let network = Network::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); + |params: Vec, state: Arc| async move { + let net = Network::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let address = params[1].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let group_lock = state.group.read().await; - let db = group_lock.wallet_db(&gid)?; - let sender = group_lock.sender(); - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; let c_str = if params.len() == 4 { let cid = params[2].as_i64().ok_or(RpcError::ParseError)?; @@ -429,34 +430,32 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { None }; - let tokens = Token::list(&db, &network)?; - tokio::spawn(loop_token(sender, db, gid, network, address, c_str)); - Ok(HandleResult::rpc(token_list(network, tokens))) + let tokens = Token::list(&db, &net)?; + tokio::spawn(loop_token(state.rpc_send.clone(), db, net, address, c_str)); + Ok(HandleResult::rpc(token_list(net, tokens))) }, ); handler.add_method( "wallet-token-import", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); - let network = Network::from_i64(params[1].as_i64().ok_or(RpcError::ParseError)?); - let address = params[2].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let c_str = params[3].as_str().ok_or(RpcError::ParseError)?.to_owned(); + let net = Network::from_i64(params[1].as_i64().ok_or(RpcError::ParseError)?); + let addr = params[2].as_str().ok_or(RpcError::ParseError)?.to_owned(); + let c = params[3].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let group_lock = state.group.read().await; - let db = group_lock.wallet_db(&gid)?; - let sender = group_lock.sender(); - drop(group_lock); - - tokio::spawn(token_check(sender, db, gid, chain, network, address, c_str)); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; + tokio::spawn(token_check(state.rpc_send.clone(), db, chain, net, addr, c)); Ok(HandleResult::new()) }, ); handler.add_method( "wallet-gas-price", - |_gid: GroupId, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let network = Network::from_i64(params[1].as_i64().ok_or(RpcError::ParseError)?); let from = params[2].as_str().ok_or(RpcError::ParseError)?; @@ -471,7 +470,7 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-transfer", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let chain = ChainToken::from_i64(params[0].as_i64().ok_or(RpcError::ParseError)?); let network = Network::from_i64(params[1].as_i64().ok_or(RpcError::ParseError)?); let from = params[2].as_i64().ok_or(RpcError::ParseError)?; @@ -480,20 +479,23 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { let c_str = params[5].as_str().ok_or(RpcError::ParseError)?; let lock = params[6].as_str().ok_or(RpcError::ParseError)?; + let pid = state.pid().await; let group_lock = state.group.read().await; - if !group_lock.check_lock(&gid, &lock) { + if !group_lock.check_lock(&pid, &lock) { return Err(RpcError::Custom("Lock is invalid!".to_owned())); } - let db = group_lock.wallet_db(&gid)?; + let db_key = group_lock.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; let address = Address::get(&db, &from)?; let (mnemonic, pbytes) = if address.is_gen() { - (group_lock.mnemonic(&gid, lock)?, vec![]) + (group_lock.mnemonic(&pid, lock, &state.secret)?, vec![]) } else { - let pbytes = group_lock.decrypt(&gid, lock, address.secret.as_ref())?; + let ckey = &group_lock.account(&pid)?.encrypt; + let pbytes = decrypt(&state.secret, lock, ckey, address.secret.as_ref())?; (String::new(), pbytes) }; - let account = group_lock.account(&gid)?; + let account = group_lock.account(&pid)?; let lang = account.lang(); let pass = account.pass.to_string(); let account_index = account.index as u32; @@ -553,11 +555,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-nft", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let address = params[0].as_i64().ok_or(RpcError::ParseError)?; let token = params[1].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.wallet_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; let nfts = Balance::list(&db, &address, &token)?; let mut results = vec![]; @@ -570,12 +574,14 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-nft-add", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let address = params[0].as_i64().ok_or(RpcError::ParseError)?; let token = params[1].as_i64().ok_or(RpcError::ParseError)?; let hash = params[2].as_str().ok_or(RpcError::ParseError)?.to_owned(); - let db = state.group.read().await.wallet_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; let t = Token::get(&db, &token)?; let a = Address::get(&db, &address)?; @@ -598,13 +604,13 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "wallet-main", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let db = group_lock.wallet_db(&gid)?; - let a_db = group_lock.account_db()?; - drop(group_lock); + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = wallet_db(&state.base, &pid, &db_key)?; + let a_db = account_db(&state.base, &state.secret)?; let address = Address::get(&db, &id)?; Address::main(&db, &id)?; @@ -612,11 +618,11 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { let mut results = HandleResult::new(); let mut group_lock = state.group.write().await; - let account = group_lock.account_mut(&gid)?; + let account = group_lock.account_mut(&pid)?; account.wallet = address.chain.update_main(&address.address, &account.wallet); account.pub_height = account.pub_height + 1; account.update_info(&a_db)?; - let user = group_lock.clone_user(&gid)?; + let user = group_lock.clone_user(&pid)?; drop(group_lock); // broadcast all friends. diff --git a/src/daemon.rs b/src/daemon.rs index 1fb67da..8a566fa 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -8,8 +8,9 @@ use std::env::args; mod account; mod apps; -mod consensus; -mod event; +//mod consensus; +//mod event; +mod global; mod group; mod layer; mod migrate; @@ -22,6 +23,8 @@ mod utils; #[tokio::main] async fn main() { + console_subscriber::init(); + let db_path = args().nth(1).unwrap_or("./.tdn".to_owned()); if std::fs::metadata(&db_path).is_err() { diff --git a/src/global.rs b/src/global.rs new file mode 100644 index 0000000..d33a7e0 --- /dev/null +++ b/src/global.rs @@ -0,0 +1,121 @@ +use std::collections::HashMap; +use std::path::PathBuf; +use tdn::{ + prelude::{GroupId, P2pConfig, PeerId, PeerKey, ReceiveMessage, SendMessage}, + types::message::RpcSendMessage, +}; +use tokio::{sync::mpsc::Sender, sync::RwLock}; + +use crate::account::Account; +use crate::group::Group; +use crate::layer::Layer; + +/// global status. +pub(crate) struct Global { + /// current running account. + pub peer_id: RwLock, + /// current account public height. + pub peer_pub_height: RwLock, + /// current account own height. + pub peer_own_height: RwLock, + /// current group. + pub group: RwLock, + /// current layer. + pub layer: RwLock, + /// message delivery tracking. uuid, me_gid, db_id. + pub _delivery: RwLock>, + /// storage base path. + pub base: PathBuf, + /// random secret seed. + pub secret: [u8; 32], + /// supported layers. + pub gids: Vec, + /// inner network params. + pub p2p_config: P2pConfig, + /// inner services channel sender. + pub self_send: Sender, + /// inner p2p network sender. + pub p2p_send: RwLock>>, + /// inner rpc channel sender. + pub rpc_send: Sender, +} + +impl Global { + pub fn init( + accounts: HashMap, + base: PathBuf, + secret: [u8; 32], + p2p_config: P2pConfig, + self_send: Sender, + rpc_send: Sender, + ) -> Self { + let gids = vec![0]; // ESSE DEFAULT IS 0 + + Global { + base, + secret, + p2p_config, + self_send, + rpc_send, + gids, + peer_id: RwLock::new(PeerId::default()), + peer_pub_height: RwLock::new(0), + peer_own_height: RwLock::new(0), + group: RwLock::new(Group::init(accounts)), + layer: RwLock::new(Layer::init()), + p2p_send: RwLock::new(None), + _delivery: RwLock::new(HashMap::new()), + } + } + + pub async fn pid(&self) -> PeerId { + self.peer_id.read().await.clone() + } + + pub async fn sender(&self) -> anyhow::Result> { + self.p2p_send + .read() + .await + .clone() + .ok_or(anyhow!("network lost!")) + } + + pub async fn send(&self, msg: SendMessage) -> anyhow::Result<()> { + if let Some(sender) = &*self.p2p_send.read().await { + Ok(sender.send(msg).await?) + } else { + Err(anyhow!("network lost!")) + } + } + + pub async fn clear(&self) { + *self.peer_id.write().await = PeerId::default(); + self.layer.write().await.clear(); + } + + pub async fn reset( + &self, + pid: &PeerId, + lock: &str, + send: Sender, + ) -> anyhow::Result { + if *self.peer_id.read().await == *pid { + return Ok(true); + } + + let (pheight, oheight) = + self.group + .write() + .await + .reset(pid, lock, &self.base, &self.secret)?; + self.layer.write().await.clear(); + + *self.p2p_send.write().await = Some(send); + *self.peer_id.write().await = *pid; + *self.peer_pub_height.write().await = pheight; + *self.peer_own_height.write().await = oheight; + self._delivery.write().await.clear(); + + Ok(false) + } +} diff --git a/src/group.rs b/src/group.rs index c435b1e..2cb9c91 100644 --- a/src/group.rs +++ b/src/group.rs @@ -1,57 +1,46 @@ +use esse_primitives::id_to_str; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; use tdn::types::{ group::{EventId, GroupId}, message::{RecvType, SendMessage, SendType}, - primitive::{HandleResult, Peer, PeerId, Result}, + primitives::{HandleResult, Peer, PeerId, PeerKey, Result}, }; -use tdn_did::Proof; -use tokio::sync::{mpsc::Sender, RwLock}; - use tdn_storage::local::DStorage; +use tokio::sync::{mpsc::Sender, RwLock}; use crate::account::{Account, User}; -use crate::apps::device::rpc as device_rpc; +use crate::global::Global; +//use crate::apps::device::rpc as device_rpc; use crate::apps::device::Device; -use crate::consensus::Event; -use crate::event::{InnerEvent, StatusEvent, SyncEvent}; -use crate::layer::Layer; -use crate::migrate::{ - ACCOUNT_DB, CHAT_DB, CLOUD_DB, CONSENSUS_DB, DAO_DB, DOMAIN_DB, FILE_DB, GROUP_DB, JARVIS_DB, - SERVICE_DB, SESSION_DB, WALLET_DB, -}; -use crate::rpc; -use crate::storage::{account_init, write_avatar}; +//use crate::consensus::Event; +//use crate::event::{InnerEvent, StatusEvent, SyncEvent}; +//use crate::layer::Layer; +//use crate::rpc; +use crate::storage::{account_db, account_init, consensus_db, write_avatar}; use crate::utils::crypto::{decrypt, encrypt}; use crate::utils::device_status::{device_info, device_status as local_device_status}; -pub(crate) mod running; - -use running::RunningAccount; - /// Esse group. pub(crate) struct Group { - /// storage base path. - base: PathBuf, - /// random secret seed. - secret: [u8; 32], - /// TDN network sender. - sender: Sender, - /// current address. - addr: PeerId, /// all accounts. - accounts: HashMap, - /// distributed devices. - runnings: HashMap, + pub accounts: HashMap, + /// current account secret keypair. + pub keypair: PeerKey, + /// current account distribute connected devices. + pub distributes: Vec, + /// current account uptime + pub uptime: u32, } /// Request for make distributed. #[derive(Serialize, Deserialize)] enum GroupConnect { /// Params: User, consensus height, event_id, remote_name, remote_info, other_devices addr. - Create(Proof, User, u64, EventId, String, String, Vec), + Create(User, u64, EventId, String, String, Vec), /// connected. Connect(u64, EventId), } @@ -60,13 +49,15 @@ enum GroupConnect { #[derive(Serialize, Deserialize)] pub(crate) enum GroupEvent { /// Sync event. - Event(u64, EventId, EventId, InnerEvent), + Event(u64, EventId, EventId), + //Event(u64, EventId, EventId, InnerEvent), /// Sync infomations. - Status(StatusEvent), + Status, + //Status(StatusEvent), /// device's info update. - DeviceUpdate(PeerId, String), + DeviceUpdate(String), /// device deleted. - DeviceDelete(PeerId), + DeviceDelete, /// offline. DeviceOffline, /// Device status request. @@ -79,367 +70,373 @@ pub(crate) enum GroupEvent { /// Sync height from..to request. SyncRequest(u64, u64), /// Sync height from..last_to, to, response. - SyncResponse(u64, u64, u64, Vec), + SyncResponse(u64, u64, u64), + //SyncResponse(u64, u64, u64, Vec), } -impl Group { - pub async fn handle( - &mut self, - gid: GroupId, - msg: RecvType, - layer: &Arc>, - uid: u64, - ) -> Result { - let mut results = HandleResult::new(); - - // 1. check account is online, if not online, nothing. - if !self.runnings.contains_key(&gid) { - return Ok(results); - } +/// handle inner-group message. +pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { + let mut results = HandleResult::new(); - match msg { - RecvType::Connect(addr, data) => { - self.hanlde_connect(&mut results, &gid, addr, data, true)?; - } - RecvType::Leave(addr) => { - for (_, account) in &mut self.runnings { - if let Some(device) = account.distributes.get_mut(&addr) { - device.2 = false; - results.rpcs.push(device_rpc::device_offline(gid, device.1)); - } - } - } - RecvType::Result(addr, is_ok, data) => { - if is_ok { - self.hanlde_connect(&mut results, &gid, addr, data, false)?; - } - } - RecvType::ResultConnect(addr, data) => { - self.hanlde_connect(&mut results, &gid, addr, data, true)?; - } - RecvType::Event(addr, bytes) => { - let event: GroupEvent = bincode::deserialize(&bytes)?; - return GroupEvent::handle(self, event, gid, addr, layer, uid).await; - } - RecvType::Stream(_uid, _stream, _bytes) => { - todo!(); - // TODO stream - } - RecvType::Delivery(_t, _tid, _is_ok) => {} + match msg { + RecvType::Connect(peer, data) => { + //self.hanlde_connect(&mut results, peer, data, true)?; } - - Ok(results) - } - - fn hanlde_connect( - &mut self, - results: &mut HandleResult, - gid: &GroupId, - addr: Peer, - data: Vec, - is_connect: bool, - ) -> Result<()> { - let connect = bincode::deserialize(&data)?; - let peer_id = addr.id; - - let (remote_height, remote_event, others) = match connect { - GroupConnect::Create( - proof, - remote, - remote_height, - remote_event, - device_name, - device_info, - others, - ) => { - // check remote addr is receive addr. - if remote.addr != peer_id { - return Err(anyhow!("Address is invalid.")); - } - proof.verify(gid, &peer_id, &self.addr)?; - if is_connect { - results - .groups - .push((*gid, self.agree_message(gid, addr.clone())?)); - } - - // first init sync. - if remote.avatar.len() > 0 { - let account_db = self.account_db()?; - if let Some(u) = self.accounts.get_mut(gid) { - if u.avatar.len() == 0 { - u.name = remote.name; - u.avatar = remote.avatar; - u.update(&account_db)?; - account_db.close()?; - results.rpcs.push(rpc::account_update( - *gid, - &u.name, - base64::encode(&u.avatar), - )); - } - } - } - - let db = self.consensus_db(gid)?; - let running = self.runnings.get_mut(gid).unwrap(); // safe unwrap. checked. - let mut new_addrs = vec![]; - for a in others { - if a != peer_id && a != self.addr && !running.distributes.contains_key(&a) { - new_addrs.push(a); - } - } - - if let Some(v) = running.distributes.get_mut(&peer_id) { - v.2 = true; - results.rpcs.push(device_rpc::device_online(*gid, v.1)); - (remote_height, remote_event, new_addrs) - } else { - let mut device = Device::new(device_name, device_info, peer_id); - device.insert(&db)?; - db.close()?; - running - .distributes - .insert(peer_id, (addr.clone(), device.id, true)); - results.rpcs.push(device_rpc::device_create(*gid, &device)); - results - .rpcs - .push(device_rpc::device_online(*gid, device.id)); - (remote_height, remote_event, new_addrs) - } - } - GroupConnect::Connect(remote_height, remote_event) => { - if self - .runnings - .get(gid) - .unwrap() // safe, checked - .distributes - .contains_key(&peer_id) - { - if is_connect { - results.groups.push((*gid, self.connect_result(gid, addr)?)); - } - } else { - if is_connect { - results.groups.push((*gid, self.create_message(gid, addr)?)); - } - return Ok(()); - } - - let v = self.running_mut(gid)?; - let did = v.add_online(&peer_id)?; - results.rpcs.push(device_rpc::device_online(*gid, did)); - (remote_height, remote_event, vec![]) + RecvType::Leave(peer) => { + // check device leave. + //if let Ok(id) = account.offline(&peer) { + //results.rpcs.push(device_rpc::device_offline(peer.id, id)); + //} + } + RecvType::Result(peer, is_ok, data) => { + if is_ok { + //self.hanlde_connect(&mut results, peer, data, false)?; } - }; - - let account = self.account(gid)?; - if account.own_height != remote_height || account.event != remote_event { - results.groups.push(( - *gid, - self.sync_message(gid, peer_id, 1, account.own_height)?, - )); } - - // connect to others. - for addr in others { - results - .groups - .push((*gid, self.create_message(gid, Peer::peer(addr))?)); + RecvType::ResultConnect(peer, data) => { + //self.hanlde_connect(&mut results, peer, data, true)?; } - - Ok(()) + RecvType::Event(addr, bytes) => { + //let event: GroupEvent = bincode::deserialize(&bytes)?; + //return GroupEvent::handle(self, event, pid, addr, uid).await; + } + RecvType::Stream(_uid, _stream, _bytes) => { + todo!(); + // TODO stream + } + RecvType::Delivery(_t, _tid, _is_ok) => {} } + + Ok(results) } +// fn hanlde_connect( +// &mut self, +// results: &mut HandleResult, +// peer: Peer, +// data: Vec, +// is_connect: bool, +// ) -> Result<()> { +// let connect = bincode::deserialize(&data)?; +// let pid = peer.id; + +// let (remote_height, remote_event, others) = match connect { +// GroupConnect::Create( +// remote, +// remote_height, +// remote_event, +// device_name, +// device_info, +// others, +// ) => { +// // check remote addr is receive addr. +// if remote.addr != pid { +// return Err(anyhow!("Address is invalid.")); +// } + +// if is_connect { +// results +// .groups +// .push((pid, self.agree_message(peer.clone())?)); +// } + +// // first init sync. +// if remote.avatar.len() > 0 { +// let account_db = self.account_db()?; +// if let Some(u) = self.accounts.get_mut(pid) { +// if u.avatar.len() == 0 { +// u.name = remote.name; +// u.avatar = remote.avatar; +// u.update(&account_db)?; +// account_db.close()?; +// results.rpcs.push(rpc::account_update( +// *pid, +// &u.name, +// base64::encode(&u.avatar), +// )); +// } +// } +// } + +// let db = self.consensus_db(pid)?; +// let running = self.runnings.get_mut(pid).unwrap(); // safe unwrap. checked. +// let mut new_addrs = vec![]; +// for a in others { +// if a != peer_id && a != self.addr && !running.distributes.contains_key(&a) { +// new_addrs.push(a); +// } +// } + +// if let Some(v) = running.distributes.get_mut(&peer_id) { +// v.2 = true; +// results.rpcs.push(device_rpc::device_online(*pid, v.1)); +// (remote_height, remote_event, new_addrs) +// } else { +// let mut device = Device::new(device_name, device_info, peer_id); +// device.insert(&db)?; +// db.close()?; +// running +// .distributes +// .insert(peer_id, (addr.clone(), device.id, true)); +// results.rpcs.push(device_rpc::device_create(*pid, &device)); +// results +// .rpcs +// .push(device_rpc::device_online(*pid, device.id)); +// (remote_height, remote_event, new_addrs) +// } +// } +// GroupConnect::Connect(remote_height, remote_event) => { +// if self +// .runnings +// .get(pid) +// .unwrap() // safe, checked +// .distributes +// .contains_key(&peer_id) +// { +// if is_connect { +// results.groups.push((*pid, self.connect_result(pid, addr)?)); +// } +// } else { +// if is_connect { +// results.groups.push((*pid, self.create_message(pid, addr)?)); +// } +// return Ok(()); +// } + +// let v = self.running_mut(pid)?; +// let did = v.add_online(&peer_id)?; +// results.rpcs.push(device_rpc::device_online(*pid, did)); +// (remote_height, remote_event, vec![]) +// } +// }; + +// let account = self.account(pid)?; +// if account.own_height != remote_height || account.event != remote_event { +// results.groups.push(( +// *pid, +// self.sync_message(pid, peer_id, 1, account.own_height)?, +// )); +// } + +// // connect to others. +// for addr in others { +// results +// .groups +// .push((*pid, self.create_message(pid, Peer::peer(addr))?)); +// } + +// Ok(()) +// } +// } + impl Group { - pub async fn init( - secret: [u8; 32], - sender: Sender, - addr: PeerId, - accounts: HashMap, - base: PathBuf, - ) -> Result { - Ok(Group { - secret, - sender, - addr, + pub fn init(accounts: HashMap) -> Group { + Group { accounts, - base, - runnings: HashMap::new(), - }) + keypair: PeerKey::default(), + distributes: vec![], + uptime: 0, + } } - pub fn addr(&self) -> &PeerId { - &self.addr + pub fn keypair(&self) -> PeerKey { + let bytes = self.keypair.to_db_bytes(); + PeerKey::from_db_bytes(&bytes).unwrap() } - pub fn base(&self) -> &PathBuf { - &self.base + pub fn db_key(&self, pid: &PeerId) -> Result { + Ok(self.account(pid)?.plainkey()) } - pub fn sender(&self) -> Sender { - self.sender.clone() - } + // pub fn online(&mut self, peer: &Peer) -> Result { + // for i in self.distributes.iter_mut() { + // if &i.0 == peer { + // i.2 = true; + // return Ok(i.1); + // } + // } + // Err(anyhow!("missing distribute device")) + // } - pub fn check_lock(&self, gid: &GroupId, lock: &str) -> bool { - if let Some(account) = self.accounts.get(gid) { + // pub fn offline(&mut self, peer: &Peer) -> Result { + // for i in self.distributes.iter_mut() { + // if &i.0 == peer { + // i.2 = false; + // return Ok(i.1); + // } + // } + // Err(anyhow!("missing distribute device")) + // } + + pub fn check_lock(&self, pid: &PeerId, lock: &str) -> bool { + if let Some(account) = self.accounts.get(pid) { account.check_lock(lock).is_ok() } else { false } } - pub fn account(&self, gid: &GroupId) -> Result<&Account> { - if let Some(account) = self.accounts.get(gid) { + pub fn account(&self, pid: &PeerId) -> Result<&Account> { + if let Some(account) = self.accounts.get(pid) { Ok(account) } else { - Err(anyhow!("user missing")) + Err(anyhow!("account missing")) } } - pub fn account_mut(&mut self, gid: &GroupId) -> Result<&mut Account> { - if let Some(account) = self.accounts.get_mut(gid) { + pub fn account_mut(&mut self, pid: &PeerId) -> Result<&mut Account> { + if let Some(account) = self.accounts.get_mut(pid) { Ok(account) } else { - Err(anyhow!("user missing")) - } - } - - pub fn running(&self, gid: &GroupId) -> Result<&RunningAccount> { - if let Some(running) = self.runnings.get(gid) { - Ok(running) - } else { - Err(anyhow!("user missing")) + Err(anyhow!("account missing")) } } - pub fn running_mut(&mut self, gid: &GroupId) -> Result<&mut RunningAccount> { - if let Some(running) = self.runnings.get_mut(gid) { - Ok(running) + // pub fn running(&self, pid: &PeerId) -> Result<&RunningAccount> { + // if let Some(running) = self.runnings.get(pid) { + // Ok(running) + // } else { + // Err(anyhow!("user missing")) + // } + // } + + // pub fn running_mut(&mut self, pid: &PeerId) -> Result<&mut RunningAccount> { + // if let Some(running) = self.runnings.get_mut(pid) { + // Ok(running) + // } else { + // Err(anyhow!("user missing")) + // } + // } + + // pub fn prove_addr(&self, mpid: &PeerId, raddr: &PeerId) -> Result { + // let running = self.running(mpid)?; + // Ok(Proof::prove(&running.keypair, &self.addr, raddr)) + // } + + // pub fn uptime(&self, pid: &PeerId) -> Result { + // self.running(pid).map(|v| v.uptime) + // } + + // pub fn list_running_user(&self) -> Vec { + // self.runnings.keys().map(|d| *d).collect() + // } + + // pub fn distribute_conns(&self, pid: &PeerId) -> Vec { + // let mut vecs = vec![]; + // if let Some(running) = &self.runnings.get(pid) { + // for (addr, (peer, _, _)) in &running.distributes { + // if addr != &self.addr { + // if let Ok(s) = self.connect_message(pid, peer.clone()) { + // vecs.push(s); + // } + // } + // } + // } + // vecs + // } + + // pub fn all_distribute_conns(&self) -> HashMap> { + // let mut conns = HashMap::new(); + // for (mpid, running) in &self.runnings { + // let mut vecs = vec![]; + // for (addr, (peer, _, _)) in &running.distributes { + // if addr != &self.addr { + // if let Ok(s) = self.connect_message(mpid, peer.clone()) { + // vecs.push(s); + // } + // } + // } + // conns.insert(*mpid, vecs); + // } + // conns + // } + + // pub fn online_devices(&self, pid: &PeerId, mut devices: Vec) -> Vec { + // if let Some(running) = self.runnings.get(pid) { + // for (addr, (_peer, _id, online)) in &running.distributes { + // if *online { + // for device in devices.iter_mut() { + // if device.addr == *addr { + // device.online = true; + // } + // } + // } + // } + // } + + // devices + // } + + // pub fn remove_all_running(&mut self) -> HashMap { + // let mut addrs: HashMap = HashMap::new(); + // for (_, running) in self.runnings.drain() { + // for (addr, (_peer, _id, online)) in running.distributes { + // if addr != self.addr && online { + // addrs.insert(addr, ()); + // } + // } + // } + // addrs + // } + + // pub fn remove_running(&mut self, pid: &PeerId) -> HashMap { + // // check close the stable connection. + // let mut addrs: HashMap = HashMap::new(); + // if let Some(running) = self.runnings.remove(pid) { + // for (addr, (_peer, _id, online)) in running.distributes { + // if addr != self.addr && online { + // addrs.insert(addr, ()); + // } + // } + + // // check if other stable connection. + // for other_running in self.runnings.values() { + // for (addr, (_peer, _id, online)) in &other_running.distributes { + // if *online && addrs.contains_key(addr) { + // addrs.remove(addr); + // } + // } + // } + // } + + // addrs + // } + + /// reset group info when change account. + pub fn reset( + &mut self, + pid: &PeerId, + lock: &str, + base: &PathBuf, + secret: &[u8], + ) -> Result<(u64, u64)> { + let (keypair, pheight, oheight, key) = if let Some(u) = self.accounts.get_mut(pid) { + let keypair = u.secret(secret, lock)?; + u.cache_plainkey(secret, lock)?; + (keypair, u.pub_height, u.own_height, u.plainkey()) } else { - Err(anyhow!("user missing")) - } - } - - pub fn prove_addr(&self, mgid: &GroupId, raddr: &PeerId) -> Result { - let running = self.running(mgid)?; - Ok(Proof::prove(&running.keypair, &self.addr, raddr)) - } - - pub fn uptime(&self, gid: &GroupId) -> Result { - self.running(gid).map(|v| v.uptime) - } - - pub fn list_running_user(&self) -> Vec { - self.runnings.keys().map(|d| *d).collect() - } - - pub fn distribute_conns(&self, gid: &GroupId) -> Vec { - let mut vecs = vec![]; - if let Some(running) = &self.runnings.get(gid) { - for (addr, (peer, _, _)) in &running.distributes { - if addr != &self.addr { - if let Ok(s) = self.connect_message(gid, peer.clone()) { - vecs.push(s); - } - } - } - } - vecs - } - - pub fn all_distribute_conns(&self) -> HashMap> { - let mut conns = HashMap::new(); - for (mgid, running) in &self.runnings { - let mut vecs = vec![]; - for (addr, (peer, _, _)) in &running.distributes { - if addr != &self.addr { - if let Ok(s) = self.connect_message(mgid, peer.clone()) { - vecs.push(s); - } - } - } - conns.insert(*mgid, vecs); - } - conns - } - - pub fn online_devices(&self, gid: &GroupId, mut devices: Vec) -> Vec { - if let Some(running) = self.runnings.get(gid) { - for (addr, (_peer, _id, online)) in &running.distributes { - if *online { - for device in devices.iter_mut() { - if device.addr == *addr { - device.online = true; - } - } - } - } - } - - devices - } - - pub fn remove_all_running(&mut self) -> HashMap { - let mut addrs: HashMap = HashMap::new(); - for (_, running) in self.runnings.drain() { - for (addr, (_peer, _id, online)) in running.distributes { - if addr != self.addr && online { - addrs.insert(addr, ()); - } - } - } - addrs - } - - pub fn remove_running(&mut self, gid: &GroupId) -> HashMap { - // check close the stable connection. - let mut addrs: HashMap = HashMap::new(); - if let Some(running) = self.runnings.remove(gid) { - for (addr, (_peer, _id, online)) in running.distributes { - if addr != self.addr && online { - addrs.insert(addr, ()); - } - } + return Err(anyhow!("user missing.")); + }; - // check if other stable connection. - for other_running in self.runnings.values() { - for (addr, (_peer, _id, online)) in &other_running.distributes { - if *online && addrs.contains_key(addr) { - addrs.remove(addr); - } - } - } - } + self.keypair = keypair; - addrs - } + let db = consensus_db(base, pid, &self.db_key(pid)?)?; + self.distributes = Device::list(&db)?; + db.close()?; - pub fn add_running(&mut self, gid: &GroupId, lock: &str) -> Result<(i64, bool)> { - let (keypair, id, key) = if let Some(u) = self.accounts.get_mut(gid) { - let keypair = u.secret(&self.secret, lock)?; - u.cache_plainkey(&self.secret, lock)?; - (keypair, u.id, u.plainkey()) - } else { - return Err(anyhow!("user missing.")); - }; + let start = SystemTime::now(); + self.uptime = start + .duration_since(UNIX_EPOCH) + .map(|s| s.as_secs()) + .unwrap_or(0) as u32; // safe for all life. - if !self.runnings.contains_key(gid) { - // load devices to runnings. - let running = RunningAccount::init(keypair, &self.base, &key, gid)?; - self.runnings.insert(gid.clone(), running); - Ok((id, false)) - } else { - Ok((id, true)) - } + Ok((pheight, oheight)) } - pub fn clone_user(&self, gid: &GroupId) -> Result { - if let Some(u) = self.accounts.get(gid) { + pub fn clone_user(&self, pid: &PeerId) -> Result { + if let Some(u) = self.accounts.get(pid) { Ok(User::new( - u.gid, - self.addr, + u.pid, u.name.clone(), u.avatar.clone(), u.wallet.clone(), @@ -450,15 +447,7 @@ impl Group { } } - pub fn username(&self, gid: &GroupId) -> Result { - if let Some(u) = self.accounts.get(gid) { - Ok(u.name.clone()) - } else { - Err(anyhow!("user missing.")) - } - } - - pub fn list_users(&self) -> &HashMap { + pub fn list_accounts(&self) -> &HashMap { &self.accounts } @@ -470,11 +459,13 @@ impl Group { name: &str, lock: &str, avatar_bytes: Vec, - ) -> Result<(i64, GroupId)> { + base: &PathBuf, + secret: &[u8], + ) -> Result<(i64, PeerId)> { let account_index = self.accounts.len() as u32; let (mut account, sk) = Account::generate( account_index, - &self.secret, + secret, lang, seed, pass, @@ -482,41 +473,41 @@ impl Group { lock, avatar_bytes, )?; - let account_id = account.gid; + let account_id = account.pid; if let Some(u) = self.accounts.get(&account_id) { - let running = RunningAccount::init(sk, &self.base, &account.plainkey(), &account_id)?; - self.runnings.insert(account_id, running); return Ok((u.id, account_id)); } - account_init(&self.base, &account.plainkey(), &account.gid).await?; + account_init(base, &account.plainkey(), &account.pid).await?; - let account_db = self.account_db()?; + let account_db = account_db(base, secret)?; account.insert(&account_db)?; account_db.close()?; let account_did = account.id; let key = account.plainkey(); - let _ = write_avatar(&self.base, &account_id, &account_id, &account.avatar).await; - self.accounts.insert(account.gid, account); + let _ = write_avatar(base, &account_id, &account_id, &account.avatar).await; + self.accounts.insert(account.pid, account); let (device_name, device_info) = device_info(); - let mut device = Device::new(device_name, device_info, self.addr); - let db = self.consensus_db(&account_id)?; + let mut device = Device::new(device_name, device_info, Peer::peer(account_id)); + let db = consensus_db(base, &account_id, &self.db_key(&account_id)?)?; device.insert(&db)?; db.close()?; - self.runnings.insert( - account_id, - RunningAccount::init(sk, &self.base, &key, &account_id)?, - ); - Ok((account_did, account_id)) } - pub fn update_account(&mut self, gid: GroupId, name: &str, avatar: Vec) -> Result<()> { - let account_db = self.account_db()?; - let account = self.account_mut(&gid)?; + pub fn update_account( + &mut self, + pid: PeerId, + name: &str, + avatar: Vec, + base: &PathBuf, + secret: &[u8], + ) -> Result<()> { + let account_db = account_db(base, secret)?; + let account = self.account_mut(&pid)?; account.name = name.to_owned(); if avatar.len() > 0 { account.avatar = avatar; @@ -526,446 +517,352 @@ impl Group { account_db.close() } - pub fn mnemonic(&self, gid: &GroupId, lock: &str) -> Result { - if let Some(u) = self.accounts.get(gid) { - u.mnemonic(&self.secret, lock) - } else { - Err(anyhow!("user missing.")) - } - } - - pub fn pin(&mut self, gid: &GroupId, lock: &str, new: &str) -> Result<()> { - let account_db = self.account_db()?; - if let Some(u) = self.accounts.get_mut(gid) { - u.pin(&self.secret, lock, new)?; - u.update(&account_db)?; - account_db.close() - } else { - Err(anyhow!("user missing.")) - } - } - - pub fn encrypt(&self, gid: &GroupId, lock: &str, bytes: &[u8]) -> Result> { - let ckey = &self.account(gid)?.encrypt; - encrypt(&self.secret, lock, ckey, bytes) - } - pub fn decrypt(&self, gid: &GroupId, lock: &str, bytes: &[u8]) -> Result> { - let ckey = &self.account(gid)?.encrypt; - decrypt(&self.secret, lock, ckey, bytes) - } - - pub fn create_message(&self, gid: &GroupId, addr: Peer) -> Result { - let user = self.clone_user(gid)?; - let account = self.account(gid)?; - let height = account.own_height; - let event = account.event; - let proof = self.prove_addr(gid, &addr.id)?; - let running = self.running(gid)?; - - Ok(SendType::Connect( - 0, - addr, - bincode::serialize(&GroupConnect::Create( - proof, - user, - height, - event, - running.device_name.clone(), - running.device_info.clone(), - running.distributes.keys().cloned().collect(), - )) - .unwrap_or(vec![]), - )) + pub fn mnemonic(&self, pid: &PeerId, lock: &str, secret: &[u8]) -> Result { + let account = self.account(pid)?; + account.mnemonic(secret, lock) } - pub fn connect_message(&self, gid: &GroupId, addr: Peer) -> Result { - let account = self.account(gid)?; - let height = account.own_height; - let event = account.event; - let data = bincode::serialize(&GroupConnect::Connect(height, event)).unwrap_or(vec![]); - Ok(SendType::Connect(0, addr, data)) - } - - pub fn connect_result(&self, gid: &GroupId, addr: Peer) -> Result { - let account = self.account(gid)?; - let height = account.own_height; - let event = account.event; - let data = bincode::serialize(&GroupConnect::Connect(height, event)).unwrap_or(vec![]); - Ok(SendType::Result(0, addr, true, false, data)) - } - - pub fn agree_message(&self, gid: &GroupId, addr: Peer) -> Result { - let account = self.account(gid)?; - let height = account.own_height; - let event = account.event; - let me = self.clone_user(gid)?; - let proof = self.prove_addr(gid, &addr.id)?; - let running = self.running(gid)?; - - Ok(SendType::Result( - 0, - addr, - true, - false, - bincode::serialize(&GroupConnect::Create( - proof, - me, - height, - event, - running.device_name.clone(), - running.device_info.clone(), - running.distributes.keys().cloned().collect(), - )) - .unwrap_or(vec![]), - )) - } - - fn ancestor(from: u64, to: u64) -> (Vec, bool) { - let space = to - from; - let step = space / 8; - if step == 0 { - ((from..to + 1).map(|i| i).collect(), true) - } else { - let mut vec: Vec = (1..8).map(|i| step * i + from).collect(); - vec.push(to); - (vec, false) - } - } - - pub fn sync_message( - &self, - gid: &GroupId, - addr: PeerId, - from: u64, - to: u64, - ) -> Result { - let (ancestors, hashes, is_min) = if to >= from { - let (ancestors, is_min) = Self::ancestor(from, to); - let db = self.consensus_db(gid)?; - let hashes = crate::consensus::Event::get_assign_hash(&db, &ancestors)?; - db.close()?; - (ancestors, hashes, is_min) - } else { - (vec![], vec![], true) - }; - - let event = GroupEvent::SyncCheck(ancestors, hashes, is_min); - let data = bincode::serialize(&event).unwrap_or(vec![]); - Ok(SendType::Event(0, addr, data)) - } - - pub fn event_message(&self, addr: PeerId, event: &GroupEvent) -> Result { - let data = bincode::serialize(event).unwrap_or(vec![]); - Ok(SendType::Event(0, addr, data)) - } - - pub fn broadcast( + pub fn pin( &mut self, - gid: &GroupId, - event: InnerEvent, - path: i64, - row: i64, - results: &mut HandleResult, + pid: &PeerId, + lock: &str, + new: &str, + base: &PathBuf, + secret: &[u8], ) -> Result<()> { - let db = self.consensus_db(gid)?; - let account_db = self.account_db()?; - - let account = self.account_mut(gid)?; - let pre_event = account.event; - let eheight = account.own_height + 1; - let eid = event.generate_event_id(); - - Event::merge(&db, eid, path, row, eheight)?; - drop(db); - - account.update_consensus(&account_db, eheight, eid)?; - account_db.close()?; - drop(account); - - let e = GroupEvent::Event(eheight, eid, pre_event, event); - let data = bincode::serialize(&e).unwrap_or(vec![]); - let running = self.running(gid)?; - for (addr, (_peer, _id, online)) in &running.distributes { - if *online { - let msg = SendType::Event(0, *addr, data.clone()); - results.groups.push((*gid, msg)) - } - } - Ok(()) + let account_db = account_db(base, secret)?; + let account = self.account_mut(pid)?; + account.pin(secret, lock, new)?; + account.update(&account_db)?; + account_db.close() } - pub fn _status( - &mut self, - gid: &GroupId, - event: StatusEvent, - results: &mut HandleResult, - ) -> Result<()> { - let running = self.running(gid)?; - let data = bincode::serialize(&GroupEvent::Status(event)).unwrap_or(vec![]); - for (addr, (_peer, _id, online)) in &running.distributes { - if *online { - let msg = SendType::Event(0, *addr, data.clone()); - results.groups.push((*gid, msg)) - } + pub fn device(&self) -> Result<&Device> { + if self.distributes.len() > 0 { + Ok(&self.distributes[0]) + } else { + Err(anyhow!("no devices")) } - Ok(()) - } -} - -impl Group { - fn db_key(&self, gid: &GroupId) -> Result { - Ok(self.account(gid)?.plainkey()) - } - - pub(crate) fn account_db(&self) -> Result { - let mut db_path = self.base.clone(); - db_path.push(ACCOUNT_DB); - DStorage::open(db_path, &hex::encode(&self.secret)) - } - - pub(crate) fn consensus_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(CONSENSUS_DB); - DStorage::open(db_path, &self.db_key(gid)?) } - pub(crate) fn session_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(SESSION_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn chat_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(CHAT_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn file_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(FILE_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn _service_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(SERVICE_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn jarvis_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(JARVIS_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn group_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(GROUP_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn _dao_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(DAO_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn domain_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(DOMAIN_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn wallet_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(WALLET_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } - - pub(crate) fn _cloud_db(&self, gid: &GroupId) -> Result { - let mut db_path = self.base.clone(); - db_path.push(gid.to_hex()); - db_path.push(CLOUD_DB); - DStorage::open(db_path, &self.db_key(gid)?) - } + // pub fn create_message(&self, pid: &PeerId, addr: Peer) -> Result { + // let user = self.clone_user(pid)?; + // let account = self.account(pid)?; + // let height = account.own_height; + // let event = account.event; + // let proof = self.prove_addr(pid, &addr.id)?; + // let running = self.running(pid)?; + + // Ok(SendType::Connect( + // 0, + // addr, + // bincode::serialize(&GroupConnect::Create( + // proof, + // user, + // height, + // event, + // running.device_name.clone(), + // running.device_info.clone(), + // running.distributes.keys().cloned().collect(), + // )) + // .unwrap_or(vec![]), + // )) + // } + + // pub fn connect_message(&self, pid: &PeerId, addr: Peer) -> Result { + // let account = self.account(pid)?; + // let height = account.own_height; + // let event = account.event; + // let data = bincode::serialize(&GroupConnect::Connect(height, event)).unwrap_or(vec![]); + // Ok(SendType::Connect(0, addr, data)) + // } + + // pub fn connect_result(&self, pid: &PeerId, addr: Peer) -> Result { + // let account = self.account(pid)?; + // let height = account.own_height; + // let event = account.event; + // let data = bincode::serialize(&GroupConnect::Connect(height, event)).unwrap_or(vec![]); + // Ok(SendType::Result(0, addr, true, false, data)) + // } + + // pub fn agree_message(&self, pid: &PeerId, addr: Peer) -> Result { + // let account = self.account(pid)?; + // let height = account.own_height; + // let event = account.event; + // let me = self.clone_user(pid)?; + // let proof = self.prove_addr(pid, &addr.id)?; + // let running = self.running(pid)?; + + // Ok(SendType::Result( + // 0, + // addr, + // true, + // false, + // bincode::serialize(&GroupConnect::Create( + // proof, + // me, + // height, + // event, + // running.device_name.clone(), + // running.device_info.clone(), + // running.distributes.keys().cloned().collect(), + // )) + // .unwrap_or(vec![]), + // )) + // } + + // fn ancestor(from: u64, to: u64) -> (Vec, bool) { + // let space = to - from; + // let step = space / 8; + // if step == 0 { + // ((from..to + 1).map(|i| i).collect(), true) + // } else { + // let mut vec: Vec = (1..8).map(|i| step * i + from).collect(); + // vec.push(to); + // (vec, false) + // } + // } + + // pub fn sync_message(&self, pid: &PeerId, addr: PeerId, from: u64, to: u64) -> Result { + // let (ancestors, hashes, is_min) = if to >= from { + // let (ancestors, is_min) = Self::ancestor(from, to); + // let db = self.consensus_db(pid)?; + // let hashes = crate::consensus::Event::get_assign_hash(&db, &ancestors)?; + // db.close()?; + // (ancestors, hashes, is_min) + // } else { + // (vec![], vec![], true) + // }; + + // let event = GroupEvent::SyncCheck(ancestors, hashes, is_min); + // let data = bincode::serialize(&event).unwrap_or(vec![]); + // Ok(SendType::Event(0, addr, data)) + // } + + // pub fn event_message(&self, addr: PeerId, event: &GroupEvent) -> Result { + // let data = bincode::serialize(event).unwrap_or(vec![]); + // Ok(SendType::Event(0, addr, data)) + // } + + // pub fn broadcast( + // &mut self, + // pid: &PeerId, + // event: InnerEvent, + // path: i64, + // row: i64, + // results: &mut HandleResult, + // ) -> Result<()> { + // let db = self.consensus_db(pid)?; + // let account_db = self.account_db()?; + + // let account = self.account_mut(pid)?; + // let pre_event = account.event; + // let eheight = account.own_height + 1; + // let eid = event.generate_event_id(); + + // Event::merge(&db, eid, path, row, eheight)?; + // drop(db); + + // account.update_consensus(&account_db, eheight, eid)?; + // account_db.close()?; + // drop(account); + + // let e = GroupEvent::Event(eheight, eid, pre_event, event); + // let data = bincode::serialize(&e).unwrap_or(vec![]); + // let running = self.running(pid)?; + // for (addr, (_peer, _id, online)) in &running.distributes { + // if *online { + // let msg = SendType::Event(0, *addr, data.clone()); + // results.groups.push((*pid, msg)) + // } + // } + // Ok(()) + // } + + // pub fn _status( + // &mut self, + // pid: &PeerId, + // event: StatusEvent, + // results: &mut HandleResult, + // ) -> Result<()> { + // let running = self.running(pid)?; + // let data = bincode::serialize(&GroupEvent::Status(event)).unwrap_or(vec![]); + // for (addr, (_peer, _id, online)) in &running.distributes { + // if *online { + // let msg = SendType::Event(0, *addr, data.clone()); + // results.groups.push((*pid, msg)) + // } + // } + // Ok(()) + // } } -impl GroupEvent { - pub async fn handle( - group: &mut Group, - event: GroupEvent, - gid: GroupId, - addr: PeerId, - layer: &Arc>, - uid: u64, - ) -> Result { - let mut results = HandleResult::new(); - match event { - GroupEvent::DeviceUpdate(_at, _name) => { - // TODO - } - GroupEvent::DeviceDelete(_at) => { - // TODO - } - GroupEvent::DeviceOffline => { - let v = group.running_mut(&gid)?; - let did = v.offline(&addr)?; - results.rpcs.push(device_rpc::device_offline(gid, did)); - } - GroupEvent::StatusRequest => { - let (cpu_n, mem_s, swap_s, disk_s, cpu_p, mem_p, swap_p, disk_p) = - local_device_status(); - results.groups.push(( - gid, - SendType::Event( - 0, - addr, - bincode::serialize(&GroupEvent::StatusResponse( - cpu_n, - mem_s, - swap_s, - disk_s, - cpu_p, - mem_p, - swap_p, - disk_p, - group.uptime(&gid)?, - )) - .unwrap_or(vec![]), - ), - )) - } - GroupEvent::StatusResponse( - cpu_n, - mem_s, - swap_s, - disk_s, - cpu_p, - mem_p, - swap_p, - disk_p, - uptime, - ) => results.rpcs.push(device_rpc::device_status( - gid, cpu_n, mem_s, swap_s, disk_s, cpu_p, mem_p, swap_p, disk_p, uptime, - )), - GroupEvent::Event(eheight, eid, pre, inner_event) => { - inner_event.handle(group, gid, addr, eheight, eid, pre, &mut results, layer)?; - } - GroupEvent::Status(status_event) => { - status_event.handle(group, gid, addr, &mut results, layer, uid)?; - } - GroupEvent::SyncCheck(ancestors, hashes, is_min) => { - println!("sync check: {:?}", ancestors); - let account = group.account(&gid)?; - if ancestors.len() == 0 || hashes.len() == 0 { - return Ok(results); - } - - // remote is new need it handle. - if hashes[0] == EventId::default() { - return Ok(results); - } - - let remote_height = ancestors.last().map(|v| *v).unwrap_or(0); - let remote_event = hashes.last().map(|v| *v).unwrap_or(EventId::default()); - if account.own_height != remote_height || account.event != remote_event { - // check ancestor and merge. - let db = group.consensus_db(&gid)?; - let ours = crate::consensus::Event::get_assign_hash(&db, &ancestors)?; - drop(db); - - if ours.len() == 0 { - let event = GroupEvent::SyncRequest(1, remote_height); - let data = bincode::serialize(&event).unwrap_or(vec![]); - results.groups.push((gid, SendType::Event(0, addr, data))); - return Ok(results); - } - - let mut ancestor = 0u64; - for i in 0..ancestors.len() { - if hashes[i] != ours[i] { - if i == 0 { - ancestor = ancestors[0]; - break; - } - - if ancestors[i - 1] == ancestors[i] + 1 { - ancestor = ancestors[i - 1]; - } else { - if is_min { - ancestor = ancestors[i - 1]; - } else { - results.groups.push(( - gid, - group.sync_message( - &gid, - addr, - ancestors[i - 1], - ancestors[i], - )?, - )); - return Ok(results); - } - } - - break; - } - } - - if ancestor != 0 { - let event = GroupEvent::SyncRequest(ancestor, remote_height); - let data = bincode::serialize(&event).unwrap_or(vec![]); - results.groups.push((gid, SendType::Event(0, addr, data))); - } else { - results.groups.push(( - gid, - group.sync_message(&gid, addr, remote_height, account.own_height)?, - )); - } - } - } - GroupEvent::SyncRequest(from, to) => { - println!("====== DEBUG Sync Request: from: {} to {}", from, to); - // every time sync MAX is 100. - let last_to = if to - from > 100 { to - 100 } else { to }; - let sync_events = SyncEvent::sync( - &group, - &group.base, - &gid, - group.account(&gid)?, - from, - last_to, - ) - .await?; - let event = GroupEvent::SyncResponse(from, last_to, to, sync_events); - let data = bincode::serialize(&event).unwrap_or(vec![]); - results.groups.push((gid, SendType::Event(0, addr, data))); - } - GroupEvent::SyncResponse(from, last_to, to, events) => { - println!( - "====== DEBUG Sync Response: from: {} last {}, to {}", - from, last_to, to - ); - if last_to < to { - let event = GroupEvent::SyncRequest(last_to + 1, to); - let data = bincode::serialize(&event).unwrap_or(vec![]); - results.groups.push((gid, SendType::Event(0, addr, data))); - } - SyncEvent::handle(gid, from, last_to, events, group, layer, &mut results, addr)?; - } - } - - Ok(results) - } -} +// impl GroupEvent { +// pub async fn handle( +// group: &mut Group, +// event: GroupEvent, +// pid: PeerId, +// addr: PeerId, +// //layer: &Arc>, +// uid: u64, +// ) -> Result { +// let mut results = HandleResult::new(); +// match event { +// GroupEvent::DeviceUpdate(_at, _name) => { +// // TODO +// } +// GroupEvent::DeviceDelete(_at) => { +// // TODO +// } +// GroupEvent::DeviceOffline => { +// let v = group.running_mut(&pid)?; +// let did = v.offline(&addr)?; +// results.rpcs.push(device_rpc::device_offline(pid, did)); +// } +// GroupEvent::StatusRequest => { +// let (cpu_n, mem_s, swap_s, disk_s, cpu_p, mem_p, swap_p, disk_p) = +// local_device_status(); +// results.groups.push(( +// pid, +// SendType::Event( +// 0, +// addr, +// bincode::serialize(&GroupEvent::StatusResponse( +// cpu_n, +// mem_s, +// swap_s, +// disk_s, +// cpu_p, +// mem_p, +// swap_p, +// disk_p, +// group.uptime(&pid)?, +// )) +// .unwrap_or(vec![]), +// ), +// )) +// } +// GroupEvent::StatusResponse( +// cpu_n, +// mem_s, +// swap_s, +// disk_s, +// cpu_p, +// mem_p, +// swap_p, +// disk_p, +// uptime, +// ) => results.rpcs.push(device_rpc::device_status( +// pid, cpu_n, mem_s, swap_s, disk_s, cpu_p, mem_p, swap_p, disk_p, uptime, +// )), +// GroupEvent::Event(eheight, eid, pre) => { +// //inner_event.handle(group, pid, addr, eheight, eid, pre, &mut results, layer)?; +// } +// GroupEvent::Status => { +// //status_event.handle(group, pid, addr, &mut results, layer, uid)?; +// } +// GroupEvent::SyncCheck(ancestors, hashes, is_min) => { +// println!("sync check: {:?}", ancestors); +// let account = group.account(&pid)?; +// if ancestors.len() == 0 || hashes.len() == 0 { +// return Ok(results); +// } + +// // remote is new need it handle. +// if hashes[0] == EventId::default() { +// return Ok(results); +// } + +// let remote_height = ancestors.last().map(|v| *v).unwrap_or(0); +// let remote_event = hashes.last().map(|v| *v).unwrap_or(EventId::default()); +// if account.own_height != remote_height || account.event != remote_event { +// // check ancestor and merge. +// let db = group.consensus_db(&pid)?; +// let ours = vec![]; +// //let ours = crate::consensus::Event::get_assign_hash(&db, &ancestors)?; +// drop(db); + +// if ours.len() == 0 { +// let event = GroupEvent::SyncRequest(1, remote_height); +// let data = bincode::serialize(&event).unwrap_or(vec![]); +// results.groups.push((pid, SendType::Event(0, addr, data))); +// return Ok(results); +// } + +// let mut ancestor = 0u64; +// for i in 0..ancestors.len() { +// if hashes[i] != ours[i] { +// if i == 0 { +// ancestor = ancestors[0]; +// break; +// } + +// if ancestors[i - 1] == ancestors[i] + 1 { +// ancestor = ancestors[i - 1]; +// } else { +// if is_min { +// ancestor = ancestors[i - 1]; +// } else { +// results.groups.push(( +// pid, +// group.sync_message( +// &pid, +// addr, +// ancestors[i - 1], +// ancestors[i], +// )?, +// )); +// return Ok(results); +// } +// } + +// break; +// } +// } + +// if ancestor != 0 { +// let event = GroupEvent::SyncRequest(ancestor, remote_height); +// let data = bincode::serialize(&event).unwrap_or(vec![]); +// results.groups.push((pid, SendType::Event(0, addr, data))); +// } else { +// results.groups.push(( +// pid, +// group.sync_message(&pid, addr, remote_height, account.own_height)?, +// )); +// } +// } +// } +// GroupEvent::SyncRequest(from, to) => { +// println!("====== DEBUG Sync Request: from: {} to {}", from, to); +// // every time sync MAX is 100. +// let last_to = if to - from > 100 { to - 100 } else { to }; +// // let sync_events = SyncEvent::sync( +// // &group, +// // &group.base, +// // &pid, +// // group.account(&pid)?, +// // from, +// // last_to, +// // ) +// // .await?; +// let event = GroupEvent::SyncResponse(from, last_to, to); +// let data = bincode::serialize(&event).unwrap_or(vec![]); +// results.groups.push((pid, SendType::Event(0, addr, data))); +// } +// GroupEvent::SyncResponse(from, last_to, to) => { +// println!( +// "====== DEBUG Sync Response: from: {} last {}, to {}", +// from, last_to, to +// ); +// if last_to < to { +// let event = GroupEvent::SyncRequest(last_to + 1, to); +// let data = bincode::serialize(&event).unwrap_or(vec![]); +// results.groups.push((pid, SendType::Event(0, addr, data))); +// } +// //SyncEvent::handle(pid, from, last_to, events, group, layer, &mut results, addr)?; +// } +// } + +// Ok(results) +// } +// } diff --git a/src/group/running.rs b/src/group/running.rs index 0e20a36..a9a4f3b 100644 --- a/src/group/running.rs +++ b/src/group/running.rs @@ -1,11 +1,7 @@ -use std::collections::HashMap; +use esse_primitives::id_to_str; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; -use tdn::types::{ - group::GroupId, - primitive::{Peer, PeerId, Result}, -}; -use tdn_did::Keypair; +use tdn::types::primitives::{Peer, PeerId, PeerKey, Result}; use tdn_storage::local::DStorage; use crate::apps::device::Device; @@ -13,21 +9,21 @@ use crate::migrate::CONSENSUS_DB; pub(crate) struct RunningAccount { /// secret keypair. - pub keypair: Keypair, + pub keypair: PeerKey, /// device's name. pub device_name: String, /// device's info. pub device_info: String, /// distribute connected devices. - pub distributes: HashMap, + pub distributes: Vec<(Peer, i64, bool)>, /// uptime pub uptime: u32, } impl RunningAccount { - pub fn init(keypair: Keypair, base: &PathBuf, key: &str, gid: &GroupId) -> Result { + pub fn init(keypair: PeerKey, base: &PathBuf, key: &str, pid: &PeerId) -> Result { let mut db_path = base.clone(); - db_path.push(gid.to_hex()); + db_path.push(id_to_str(&pid)); db_path.push(CONSENSUS_DB); let db = DStorage::open(db_path, key)?; let distributes = Device::distributes(&db)?; @@ -49,21 +45,23 @@ impl RunningAccount { }) } - pub fn add_online(&mut self, addr: &PeerId) -> Result { - if let Some(v) = self.distributes.get_mut(addr) { - v.2 = true; - Ok(v.1) - } else { - Err(anyhow!("device missing")) + pub fn online(&mut self, peer: &Peer) -> Result { + for i in self.distributes.iter_mut() { + if &i.0 == peer { + i.2 = true; + return Ok(i.1); + } } + Err(anyhow!("missing distribute device")) } - pub fn offline(&mut self, addr: &PeerId) -> Result { - if let Some(v) = self.distributes.get_mut(addr) { - v.2 = false; - Ok(v.1) - } else { - Err(anyhow!("device missing")) + pub fn offline(&mut self, peer: &Peer) -> Result { + for i in self.distributes.iter_mut() { + if &i.0 == peer { + i.2 = false; + return Ok(i.1); + } } + Err(anyhow!("missing distribute device")) } } diff --git a/src/layer.rs b/src/layer.rs index b44e79b..6640243 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -1,450 +1,496 @@ +use chat_types::CHAT_ID; +use esse_primitives::id_to_str; +use group_types::GroupChatId; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; use tdn::types::{ - group::GroupId, message::SendType, - primitive::{HandleResult, Peer, PeerId, Result}, + primitives::{HandleResult, Peer, PeerId, Result}, }; use tokio::sync::RwLock; use crate::account::User; -use crate::apps::chat::{chat_conn, LayerEvent as ChatLayerEvent}; -use crate::apps::group::{group_conn, GROUP_ID}; +use crate::apps::chat::LayerEvent as ChatLayerEvent; +//use crate::apps::group::{group_conn, GROUP_ID}; use crate::group::Group; use crate::session::{Session, SessionType}; -/// ESSE app's `BaseLayerEvent`. -/// EVERY LAYER APP MUST EQUAL THE FIRST THREE FIELDS. -#[derive(Serialize, Deserialize)] -pub(crate) enum LayerEvent { - /// Offline. params: remote_id. - Offline(GroupId), - /// Suspend. params: remote_id. - Suspend(GroupId), - /// Actived. params: remote_id. - Actived(GroupId), -} - /// ESSE layers. pub(crate) struct Layer { - /// layer_gid (include account id, group chat id) => running_layer. - pub runnings: HashMap, - /// message delivery tracking. uuid, me_gid, db_id. - pub delivery: HashMap, - /// storage base path. - pub base: PathBuf, - /// self peer addr. - pub addr: PeerId, - /// group info. - pub group: Arc>, + /// friend pid => Session + pub chats: HashMap, + /// group chat id => Session + pub groups: HashMap, + /// delivery feedback. + pub delivery: HashMap, + /// delivery counter. + delivery_count: usize, } impl Layer { - pub async fn init(base: PathBuf, addr: PeerId, group: Arc>) -> Result { - Ok(Layer { - base, - group, - addr, - runnings: HashMap::new(), + pub fn init() -> Layer { + Layer { + chats: HashMap::new(), + groups: HashMap::new(), delivery: HashMap::new(), - }) - } - - pub fn base(&self) -> &PathBuf { - &self.base + delivery_count: 0, + } } - pub fn running(&self, gid: &GroupId) -> Result<&RunningLayer> { - self.runnings.get(gid).ok_or(anyhow!("not online")) + pub fn delivery(&mut self, db_id: i64) -> u64 { + let next = self.delivery_count as u64; + self.delivery.insert(next, db_id); + self.delivery_count += 1; + next } - pub fn running_mut(&mut self, gid: &GroupId) -> Result<&mut RunningLayer> { - self.runnings.get_mut(gid).ok_or(anyhow!("not online")) + pub fn clear(&mut self) { + self.chats.clear(); + self.groups.clear(); + self.delivery.clear(); } - pub fn add_running( - &mut self, - gid: &GroupId, - owner: GroupId, - id: i64, - consensus: i64, - ) -> Result<()> { - if !self.runnings.contains_key(gid) { - self.runnings - .insert(*gid, RunningLayer::init(owner, id, consensus)); - } - - Ok(()) - } - - pub fn remove_running(&mut self, gid: &GroupId) -> HashMap { - // check close the stable connection. - let mut addrs: HashMap = HashMap::new(); - if let Some(running) = self.runnings.remove(gid) { - for (addr, fgid) in running.remove_onlines() { - addrs.insert(addr, fgid); - } - } - - let mut need_keep = vec![]; - for (_, running) in &self.runnings { - for addr in addrs.keys() { - if running.check_addr_online(addr) { - need_keep.push(*addr); + pub fn is_addr_online(&self, addr: &PeerId) -> bool { + if self.chats.contains_key(addr) { + return true; + } else { + for (_, session) in &self.groups { + if session.addrs.contains(addr) { + return true; } } } - for i in need_keep { - addrs.remove(&i); - } - - addrs + false } - pub fn remove_all_running(&mut self) -> HashMap { - let mut addrs: HashMap = HashMap::new(); - for (_, running) in self.runnings.drain() { - for (addr, fgid) in running.remove_onlines() { - addrs.insert(addr, fgid); - } + pub fn chat_active(&mut self, pid: &PeerId, is_me: bool) -> Option { + if let Some(session) = self.chats.get_mut(pid) { + Some(session.active(is_me)) + } else { + None } - addrs - } - - pub fn get_running_remote_id(&self, mgid: &GroupId, fgid: &GroupId) -> Result<(i64, i64)> { - debug!("onlines: {:?}, find: {:?}", self.runnings.keys(), mgid); - self.running(mgid)?.get_online_id(fgid) } - pub fn remove_online(&mut self, gid: &GroupId, fgid: &GroupId) -> Option { - self.running_mut(gid).ok()?.remove_online(fgid) - } - - pub async fn all_layer_conns(&self) -> Result>> { - let mut conns = HashMap::new(); - let group_lock = self.group.read().await; - for mgid in self.runnings.keys() { - let mut vecs = vec![]; - - let db = group_lock.session_db(&mgid)?; - let sessions = Session::list(&db)?; - drop(db); - - 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, Peer::peer(s.addr)))); - } - SessionType::Group => { - let proof = group_lock.prove_addr(mgid, &s.addr)?; - vecs.push((GROUP_ID, group_conn(proof, Peer::peer(s.addr), s.gid))); - } - _ => {} - } - } - - conns.insert(*mgid, vecs); + pub fn group_active(&mut self, gid: &GroupChatId, is_me: bool) -> Option { + if let Some(session) = self.groups.get_mut(gid) { + Some(session.active(is_me)) + } else { + None } - - Ok(conns) } - pub fn is_addr_online(&self, faddr: &PeerId) -> bool { - for (_, running) in &self.runnings { - if running.check_addr_online(faddr) { - return true; - } + pub fn chat_suspend(&mut self, pid: &PeerId, me: bool, m: bool) -> Result> { + if let Some(session) = self.chats.get_mut(pid) { + Ok(session.suspend(me, m)) + } else { + Err(anyhow!("session missing!")) } - return false; } - pub fn is_online(&self, gid: &GroupId, fgid: &GroupId) -> bool { - if let Some(running) = self.runnings.get(gid) { - running.is_online(fgid) + pub fn group_suspend(&mut self, g: &GroupChatId, me: bool, m: bool) -> Result> { + if let Some(session) = self.groups.get_mut(g) { + Ok(session.suspend(me, m)) } else { - false + Err(anyhow!("session missing!")) } } - pub fn broadcast(&self, user: User, results: &mut HandleResult) { - let gid = user.id; - let info = ChatLayerEvent::InfoRes(user); - let data = bincode::serialize(&info).unwrap_or(vec![]); - if let Some(running) = self.runnings.get(&gid) { - for (fgid, online) in &running.sessions { - let msg = SendType::Event(0, *online.online.addr(), data.clone()); - results.layers.push((gid, *fgid, msg)); - } - } + pub fn chat_is_online(&self, pid: &PeerId) -> bool { + self.chats.contains_key(pid) } -} -/// online info. -#[derive(Eq, PartialEq)] -pub(crate) enum Online { - /// connected to this device. - Direct(PeerId), - /// connected to other device. - _Relay(PeerId), -} + pub fn chat_rm_online(&mut self, pid: &PeerId) -> Option { + self.chats.remove(pid).map(|session| session.addrs[0]) + } -impl Online { - fn addr(&self) -> &PeerId { - match self { - Online::Direct(ref addr) | Online::_Relay(ref addr) => addr, + pub fn chat_add(&mut self, pid: PeerId, sid: i64, fid: i64, h: i64) { + if !self.chats.contains_key(&pid) { + self.chats.insert(pid, LayerSession::new(pid, sid, fid, h)); } } -} - -pub(crate) struct OnlineSession { - pub online: Online, - /// session database id. - pub db_id: i64, - /// session ref's service(friend/group) database id. - pub db_fid: i64, - pub suspend_me: bool, - pub suspend_remote: bool, - pub remain: u16, // keep-alive remain minutes -} -impl OnlineSession { - fn new(online: Online, db_id: i64, db_fid: i64) -> Self { - Self { - online, - db_id, - db_fid, - suspend_me: false, - suspend_remote: false, - remain: 0, + pub fn chat_session(&self, pid: &PeerId) -> Result<(i64, i64)> { + if let Some(session) = self.chats.get(pid) { + Ok((session.s_id, session.db_id)) + } else { + Err(anyhow!("session missing!")) } } - fn close_suspend(&mut self) -> bool { - if self.suspend_me && self.suspend_remote { - if self.remain == 0 { - true - } else { - self.remain -= 1; - false - } + pub fn group(&self, gid: &GroupChatId) -> Result<&LayerSession> { + if let Some(session) = self.groups.get(gid) { + Ok(session) } else { - false + Err(anyhow!("session missing!")) } } -} -pub(crate) struct RunningLayer { - owner: GroupId, // if is service it has owner account. - /// layer current database id. - id: i64, - /// layer current consensus height. - consensus: i64, - /// online group (friends/services) => (group's address, group's db id) - sessions: HashMap, -} - -impl RunningLayer { - pub fn init(owner: GroupId, id: i64, consensus: i64) -> Self { - RunningLayer { - owner, - id, - consensus, - sessions: HashMap::new(), + pub fn group_mut(&mut self, gid: &GroupChatId) -> Result<&mut LayerSession> { + if let Some(session) = self.groups.get_mut(gid) { + Ok(session) + } else { + Err(anyhow!("session missing!")) } } - pub fn owner_height_id(&self) -> (GroupId, i64, i64) { - (self.owner, self.consensus, self.id) + pub fn group_add(&mut self, gid: GroupChatId, pid: PeerId, sid: i64, fid: i64, h: i64) { + if !self.groups.contains_key(&gid) { + self.groups.insert(gid, LayerSession::new(pid, sid, fid, h)); + } } - pub fn increased(&mut self) -> i64 { - self.consensus += 1; - self.consensus + pub fn group_del(&mut self, gid: &GroupChatId) -> Option> { + self.groups.remove(gid).map(|session| session.addrs) } - pub fn active(&mut self, gid: &GroupId, is_me: bool) -> Option { - if let Some(online) = self.sessions.get_mut(gid) { - if is_me { - online.suspend_me = false; - } else { - online.suspend_remote = false; - } - - online.remain = 0; - Some(*online.online.addr()) - } else { - None + pub fn group_add_member(&mut self, gid: &GroupChatId, addr: PeerId) { + if let Some(session) = self.groups.get_mut(gid) { + session.addrs.push(addr); } } - pub fn suspend(&mut self, gid: &GroupId, is_me: bool, must: bool) -> Result { - if let Some(online) = self.sessions.get_mut(gid) { - if must { - online.suspend_me = true; - online.suspend_remote = true; - } - - if is_me { - online.suspend_me = true; - } else { - online.suspend_remote = true; - } - - if online.suspend_remote && online.suspend_me { - online.remain = 6; // keep-alive 10~11 minutes 120s/time - Ok(true) - } else { - Ok(false) - } - } else { - Err(anyhow!("remote not online")) + pub fn group_del_member(&mut self, gid: &GroupChatId, index: usize) { + if let Some(session) = self.groups.get_mut(gid) { + session.addrs.remove(index); } } - pub fn get_online_id(&self, gid: &GroupId) -> Result<(i64, i64)> { - debug!("onlines: {:?}, find: {:?}", self.sessions.keys(), gid); - self.sessions - .get(gid) - .map(|online| (online.db_id, online.db_fid)) - .ok_or(anyhow!("remote not online")) - } - - /// get online peer's addr. - pub fn online(&self, gid: &GroupId) -> Result { - self.sessions - .get(gid) - .map(|online| *online.online.addr()) - .ok_or(anyhow!("remote not online")) - } - - pub fn online_direct(&self, gid: &GroupId) -> Result { - if let Some(online) = self.sessions.get(gid) { - match online.online { - Online::Direct(addr) => return Ok(addr), - _ => {} + pub fn group_del_online(&mut self, gid: &GroupChatId, addr: &PeerId) -> bool { + if let Some(session) = self.groups.get_mut(gid) { + if let Some(pos) = session.addrs.iter().position(|x| x == addr) { + session.addrs.remove(pos); + return true; } } - Err(anyhow!("no direct online")) + false } - /// get all online peer. - pub fn onlines(&self) -> Vec<(&GroupId, &PeerId)> { - self.sessions - .iter() - .map(|(fgid, online)| (fgid, online.online.addr())) - .collect() - } + // pub fn remove_running(&mut self, gid: &GroupId) -> HashMap { + // // check close the stable connection. + // let mut addrs: HashMap = HashMap::new(); + // if let Some(running) = self.runnings.remove(gid) { + // for (addr, fgid) in running.remove_onlines() { + // addrs.insert(addr, fgid); + // } + // } + + // let mut need_keep = vec![]; + // for (_, running) in &self.runnings { + // for addr in addrs.keys() { + // if running.check_addr_online(addr) { + // need_keep.push(*addr); + // } + // } + // } + // for i in need_keep { + // addrs.remove(&i); + // } + + // addrs + // } + + // pub fn remove_all_running(&mut self) -> HashMap { + // let mut addrs: HashMap = HashMap::new(); + // for (_, running) in self.runnings.drain() { + // for (addr, fgid) in running.remove_onlines() { + // addrs.insert(addr, fgid); + // } + // } + // addrs + // } + + // pub fn get_running_remote_id(&self, mgid: &GroupId, fgid: &GroupId) -> Result<(i64, i64)> { + // debug!("onlines: {:?}, find: {:?}", self.runnings.keys(), mgid); + // self.running(mgid)?.get_online_id(fgid) + // } + + // pub fn remove_online(&mut self, gid: &GroupId, fgid: &GroupId) -> Option { + // self.running_mut(gid).ok()?.remove_online(fgid) + // } + + // pub async fn all_layer_conns(&self) -> Result>> { + // let mut conns = HashMap::new(); + // let group_lock = self.group.read().await; + // for mgid in self.runnings.keys() { + // let mut vecs = vec![]; + + // let db = group_lock.session_db(&mgid)?; + // let sessions = Session::list(&db)?; + // drop(db); + + // 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, Peer::peer(s.addr)))); + // } + // SessionType::Group => { + // let proof = group_lock.prove_addr(mgid, &s.addr)?; + // vecs.push((GROUP_ID, group_conn(proof, Peer::peer(s.addr), s.gid))); + // } + // _ => {} + // } + // } + + // conns.insert(*mgid, vecs); + // } + + // Ok(conns) + // } + + // pub fn is_addr_online(&self, faddr: &PeerId) -> bool { + // for (_, running) in &self.runnings { + // if running.check_addr_online(faddr) { + // return true; + // } + // } + // return false; + // } + + // pub fn is_online(&self, gid: &GroupId, fgid: &GroupId) -> bool { + // if let Some(running) = self.runnings.get(gid) { + // running.is_online(fgid) + // } else { + // false + // } + // } - pub fn is_online(&self, gid: &GroupId) -> bool { - self.sessions.contains_key(gid) - } + pub fn broadcast(&self, user: User, results: &mut HandleResult) { + let info = ChatLayerEvent::InfoRes(user); + let data = bincode::serialize(&info).unwrap_or(vec![]); - /// check add online. - pub fn check_add_online( - &mut self, - gid: GroupId, - online: Online, - id: i64, - fid: i64, - ) -> Result<()> { - if let Some(o) = self.sessions.get(&gid) { - match (&o.online, &online) { - (Online::_Relay(..), Online::Direct(..)) => { - self.sessions - .insert(gid, OnlineSession::new(online, id, fid)); - Ok(()) - } - _ => Err(anyhow!("remote had online")), - } - } else { - self.sessions - .insert(gid, OnlineSession::new(online, id, fid)); - Ok(()) + for fpid in self.chats.keys() { + let msg = SendType::Event(0, *fpid, data.clone()); + results.layers.push((CHAT_ID, msg)); } + + // TODO GROUPS } +} - /// check offline, and return is direct. - pub fn check_offline(&mut self, gid: &GroupId, addr: &PeerId) -> bool { - if let Some(online) = self.sessions.remove(gid) { - if online.online.addr() != addr { - return false; - } +// pub(crate) struct OnlineSession { +// pub pid: PeerId, +// /// session database id. +// pub id: i64, +// /// session ref's service(friend/group) database id. +// pub fid: i64, +// pub suspend_me: bool, +// pub suspend_remote: bool, +// pub remain: u16, // keep-alive remain minutes +// } + +// impl OnlineSession { +// fn new(online: Online, db_id: i64, db_fid: i64) -> Self { +// Self { +// online, +// db_id, +// db_fid, +// suspend_me: false, +// suspend_remote: false, +// remain: 0, +// } +// } + +// fn close_suspend(&mut self) -> bool { +// if self.suspend_me && self.suspend_remote { +// if self.remain == 0 { +// true +// } else { +// self.remain -= 1; +// false +// } +// } else { +// false +// } +// } +// } + +/// online connected layer session. +pub(crate) struct LayerSession { + pub height: i64, + /// session network addr. + pub addrs: Vec, + /// session database id. + pub s_id: i64, + /// layer service database id. + pub db_id: i64, + /// if session is suspend by me. + pub suspend_me: bool, + /// if session is suspend by remote. + pub suspend_remote: bool, + /// keep alive remain minutes. + pub remain: u16, +} - match online.online { - Online::Direct(..) => { - return true; - } - _ => {} - } +impl LayerSession { + fn new(addr: PeerId, s_id: i64, db_id: i64, height: i64) -> Self { + Self { + s_id, + db_id, + height, + addrs: vec![addr], + suspend_me: false, + suspend_remote: false, + remain: 0, } - false } - pub fn remove_online(&mut self, gid: &GroupId) -> Option { - self.sessions - .remove(gid) - .map(|online| *online.online.addr()) + pub fn info(&self) -> (i64, i64, i64, PeerId) { + (self.height, self.s_id, self.db_id, self.addrs[0]) } - /// remove all onlines peer. - pub fn remove_onlines(self) -> Vec<(PeerId, GroupId)> { - let mut peers = vec![]; - for (fgid, online) in self.sessions { - match online.online { - Online::Direct(addr) => peers.push((addr, fgid)), - _ => {} - } - } - peers + pub fn increased(&mut self) -> i64 { + self.height += 1; + self.height } - /// check if addr is online. - pub fn check_addr_online(&self, addr: &PeerId) -> bool { - for (_, online) in &self.sessions { - if online.online.addr() == addr { - return true; - } + pub fn active(&mut self, is_me: bool) -> PeerId { + if is_me { + self.suspend_me = false; + } else { + self.suspend_remote = false; } - false + self.remain = 0; + self.addrs[0] } - /// peer leave, remove online peer. - pub fn peer_leave(&mut self, addr: &PeerId) -> Vec { - let mut peers = vec![]; - let mut deletes = vec![]; - for (fgid, online) in &self.sessions { - if online.online.addr() == addr { - peers.push(online.db_id); - deletes.push(*fgid); - } - } - for i in &deletes { - self.sessions.remove(&i); + pub fn suspend(&mut self, is_me: bool, must: bool) -> Option { + if must { + self.suspend_me = true; + self.suspend_remote = true; } - peers - } - - /// list all onlines groups. - pub fn close_suspend(&mut self, self_addr: &PeerId) -> Vec<(GroupId, PeerId, i64)> { - let mut needed = vec![]; - for (fgid, online) in &mut self.sessions { - // when online is self. skip. - if online.online == Online::Direct(*self_addr) { - continue; - } - - if online.close_suspend() { - needed.push((*fgid, *online.online.addr(), online.db_id)); - } + if is_me { + self.suspend_me = true; + } else { + self.suspend_remote = true; } - for (gid, _, _) in needed.iter() { - self.sessions.remove(gid); + if self.suspend_remote && self.suspend_me { + self.remain = 6; // keep-alive 10~11 minutes 120s/time + Some(self.addrs[0]) + } else { + None } - needed } + + // pub fn get_online_id(&self, gid: &GroupId) -> Result<(i64, i64)> { + // debug!("onlines: {:?}, find: {:?}", self.sessions.keys(), gid); + // self.sessions + // .get(gid) + // .map(|online| (online.db_id, online.db_fid)) + // .ok_or(anyhow!("remote not online")) + // } + + // /// get online peer's addr. + // pub fn online(&self, gid: &GroupId) -> Result { + // self.sessions + // .get(gid) + // .map(|online| *online.online.addr()) + // .ok_or(anyhow!("remote not online")) + // } + + // pub fn online_direct(&self, gid: &GroupId) -> Result { + // if let Some(online) = self.sessions.get(gid) { + // match online.online { + // Online::Direct(addr) => return Ok(addr), + // _ => {} + // } + // } + // Err(anyhow!("no direct online")) + // } + + // /// get all online peer. + // pub fn onlines(&self) -> Vec<(&GroupId, &PeerId)> { + // self.sessions + // .iter() + // .map(|(fgid, online)| (fgid, online.online.addr())) + // .collect() + // } + + // /// check add online. + + // /// check offline, and return is direct. + // pub fn check_offline(&mut self, gid: &GroupId, addr: &PeerId) -> bool { + // if let Some(online) = self.sessions.remove(gid) { + // if online.online.addr() != addr { + // return false; + // } + + // match online.online { + // Online::Direct(..) => { + // return true; + // } + // _ => {} + // } + // } + // false + // } + + // pub fn remove_online(&mut self, gid: &GroupId) -> Option { + // self.sessions + // .remove(gid) + // .map(|online| *online.online.addr()) + // } + + // /// remove all onlines peer. + // pub fn remove_onlines(self) -> Vec<(PeerId, GroupId)> { + // let mut peers = vec![]; + // for (fgid, online) in self.sessions { + // match online.online { + // Online::Direct(addr) => peers.push((addr, fgid)), + // _ => {} + // } + // } + // peers + // } + + // /// check if addr is online. + // pub fn check_addr_online(&self, addr: &PeerId) -> bool { + // for (_, online) in &self.sessions { + // if online.online.addr() == addr { + // return true; + // } + // } + // false + // } + + // /// peer leave, remove online peer. + // pub fn peer_leave(&mut self, addr: &PeerId) -> Vec { + // let mut peers = vec![]; + // let mut deletes = vec![]; + // for (fgid, online) in &self.sessions { + // if online.online.addr() == addr { + // peers.push(online.db_id); + // deletes.push(*fgid); + // } + // } + // for i in &deletes { + // self.sessions.remove(&i); + // } + + // peers + // } + + // /// list all onlines groups. + // pub fn close_suspend(&mut self, self_addr: &PeerId) -> Vec<(GroupId, PeerId, i64)> { + // let mut needed = vec![]; + // for (fgid, online) in &mut self.sessions { + // // when online is self. skip. + // if online.online == Online::Direct(*self_addr) { + // continue; + // } + + // if online.close_suspend() { + // needed.push((*fgid, *online.online.addr(), online.db_id)); + // } + // } + + // for (gid, _, _) in needed.iter() { + // self.sessions.remove(gid); + // } + // needed + // } } diff --git a/src/lib.rs b/src/lib.rs index 7127f4f..28ef2ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,9 @@ use std::os::raw::c_char; mod account; mod apps; -mod consensus; -mod event; +//mod consensus; +//mod event; +mod global; mod group; mod layer; mod migrate; diff --git a/src/migrate.rs b/src/migrate.rs index 1c10bb5..31659d2 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -1,5 +1,5 @@ use std::path::PathBuf; -use tdn::types::primitive::Result; +use tdn::types::primitives::Result; use tdn_storage::local::DStorage; pub mod consensus; diff --git a/src/migrate/account.rs b/src/migrate/account.rs index edd5892..dbae9f9 100644 --- a/src/migrate/account.rs +++ b/src/migrate/account.rs @@ -2,7 +2,7 @@ pub(super) const ACCOUNT_VERSIONS: [&str; 13] = [ "CREATE TABLE IF NOT EXISTS accounts( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - gid TEXT NOT NULL, + pid TEXT NOT NULL, indx INTEGER NOT NULL, lang INTEGER NOT NULL, pass TEXT NOT NULL, diff --git a/src/migrate/chat.rs b/src/migrate/chat.rs index 8b4dee2..16fb747 100644 --- a/src/migrate/chat.rs +++ b/src/migrate/chat.rs @@ -2,8 +2,7 @@ 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, + pid TEXT NOT NULL, name TEXT NOT NULL, wallet TEXT, height INTEGER NOT NULL, @@ -12,8 +11,7 @@ pub(super) const CHAT_VERSIONS: [&str; 3] = [ datetime INTEGER NOT NULL);", "CREATE TABLE IF NOT EXISTS requests( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - gid TEXT NOT NULL, - addr TEXT NOT NULL, + pid TEXT NOT NULL, name TEXT, remark TEXT, is_me INTEGER NOT NULL, diff --git a/src/migrate/consensus.rs b/src/migrate/consensus.rs index b1a9391..57dac53 100644 --- a/src/migrate/consensus.rs +++ b/src/migrate/consensus.rs @@ -10,7 +10,7 @@ pub(super) const CONSENSUS_VERSIONS: [&str; 9] = [ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, info TEXT NOT NULL, - addr TEXT NOT NULL, + peer TEXT NOT NULL, lasttime INTEGER NOT NULL);", "CREATE TABLE IF NOT EXISTS db_tables( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, diff --git a/src/migrate/group.rs b/src/migrate/group.rs index cff1d3e..8457f93 100644 --- a/src/migrate/group.rs +++ b/src/migrate/group.rs @@ -3,7 +3,7 @@ pub(super) const GROUP_VERSIONS: [&str; 3] = [ "CREATE TABLE IF NOT EXISTS groups( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, height INTEGER NOT NULL, - gcd TEXT NOT NULL, + gid INTEGER NOT NULL, addr TEXT NOT NULL, name TEXT NOT NULL, is_close INTEGER NOT NULL, @@ -12,8 +12,7 @@ pub(super) const GROUP_VERSIONS: [&str; 3] = [ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, height INTEGER NOT NULL, fid INTEGER NOT NULL, - mid TEXT NOT NULL, - addr TEXT NOT NULL, + pid TEXT NOT NULL, name TEXT NOT NULL, leave INTEGER NOT NULL);", "CREATE TABLE IF NOT EXISTS messages( diff --git a/src/migrate/session.rs b/src/migrate/session.rs index 138df89..d0eb4f3 100644 --- a/src/migrate/session.rs +++ b/src/migrate/session.rs @@ -3,7 +3,7 @@ pub(super) const SESSION_VERSIONS: [&str; 2] = [ "CREATE TABLE IF NOT EXISTS sessions( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, fid INTEGER NOT NULL, - gid TEXT NOT NULL, + pid TEXT NOT NULL, addr TEXT NOT NULL, s_type INTEGER NOT NULL, name TEXT NOT NULL, @@ -12,5 +12,5 @@ pub(super) const SESSION_VERSIONS: [&str; 2] = [ last_datetime INTEGER, last_content TEXT, last_readed INTEGER);", - "INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES (0, '', '', 3, '', 0, 0, 0, '', 1);", // Jarvis. + "INSERT INTO sessions (fid, pid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES (0, '', '', 3, '', 0, 0, 0, '', 1);", // Jarvis. ]; diff --git a/src/rpc.rs b/src/rpc.rs index 85d5e8f..299c433 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -1,42 +1,35 @@ -use std::collections::HashMap; +use chat_types::CHAT_ID; +use esse_primitives::{id_from_str, id_to_str}; +use group_types::{GroupChatId, LayerEvent as GroupLayerEvent, GROUP_CHAT_ID}; use std::net::SocketAddr; use std::sync::Arc; -use tdn::types::{ - group::GroupId, - message::{NetworkType, SendMessage, SendType, StateRequest, StateResponse}, - primitive::{HandleResult, Peer, PeerId, Result}, - rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, +use tdn::{ + prelude::{new_send_channel, start_main}, + types::{ + message::{ + NetworkType, RpcSendMessage, SendMessage, SendType, StateRequest, StateResponse, + }, + primitives::{HandleResult, Peer, PeerId, Result}, + rpc::{json, rpc_response, RpcError, RpcHandler, RpcParam}, + }, }; use tdn_did::{generate_mnemonic, Count}; -use tokio::sync::{ - mpsc::{self, error::SendError, Sender}, - RwLock, -}; use crate::account::lang_from_i64; use crate::apps::app_rpc_inject; -use crate::apps::chat::chat_conn; -use crate::apps::group::{add_layer, group_conn, GroupChat}; -use crate::event::InnerEvent; -use crate::group::Group; -use crate::layer::{Layer, LayerEvent, Online}; +use crate::apps::chat::{chat_conn, LayerEvent as ChatLayerEvent}; +use crate::apps::group::{group_conn, GroupChat}; +use crate::global::Global; +//use crate::event::InnerEvent; use crate::session::{connect_session, Session, SessionType}; +use crate::storage::{group_db, session_db}; -pub(crate) fn init_rpc( - addr: PeerId, - group: Arc>, - layer: Arc>, -) -> RpcHandler { - let mut handler = new_rpc_handler(addr, group, layer); +pub(crate) fn init_rpc(global: Arc) -> RpcHandler { + let mut handler = new_rpc_handler(global); app_rpc_inject(&mut handler); handler } -pub(crate) struct RpcState { - pub group: Arc>, - pub layer: Arc>, -} - #[inline] pub(crate) fn network_stable(peers: Vec<(PeerId, bool)>) -> RpcParam { let s_peers: Vec> = peers @@ -50,90 +43,72 @@ pub(crate) fn network_stable(peers: Vec<(PeerId, bool)>) -> RpcParam { vec![p.to_hex(), d] }) .collect(); - rpc_response(0, "network-stable", json!(s_peers), GroupId::default()) + rpc_response(0, "network-stable", json!(s_peers)) } #[inline] pub(crate) fn network_dht(peers: Vec) -> RpcParam { let s_peers: Vec = peers.iter().map(|p| p.to_hex()).collect(); - rpc_response(0, "network-dht", json!(s_peers), GroupId::default()) + rpc_response(0, "network-dht", json!(s_peers)) } #[inline] -pub(crate) fn account_update(mgid: GroupId, name: &str, avatar: String) -> RpcParam { - rpc_response( - 0, - "account-update", - json!([mgid.to_hex(), name, avatar]), - mgid, - ) +pub(crate) fn account_update(pid: &PeerId, name: &str, avatar: String) -> RpcParam { + rpc_response(0, "account-update", json!([id_to_str(pid), name, avatar])) } #[inline] -pub(crate) fn session_create(mgid: GroupId, session: &Session) -> RpcParam { - rpc_response(0, "session-create", session.to_rpc(), mgid) +pub(crate) fn session_create(session: &Session) -> RpcParam { + rpc_response(0, "session-create", session.to_rpc()) } #[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) +pub(crate) fn session_last(id: &i64, time: &i64, content: &str, readed: bool) -> RpcParam { + rpc_response(0, "session-last", json!([id, time, content, readed])) } #[inline] -pub(crate) fn notice_menu(mgid: GroupId, t: &SessionType) -> RpcParam { - rpc_response(0, "notice-menu", json!([t.to_int()]), mgid) +pub(crate) fn notice_menu(t: &SessionType) -> RpcParam { + rpc_response(0, "notice-menu", json!([t.to_int()])) } #[inline] -pub(crate) fn session_update_name(mgid: GroupId, id: &i64, name: &str) -> RpcParam { - rpc_response(0, "session-update", json!([id, "", name, false]), mgid) +pub(crate) fn session_update_name(id: &i64, name: &str) -> RpcParam { + rpc_response(0, "session-update", json!([id, "", name, false])) } #[inline] -pub(crate) fn session_update( - mgid: GroupId, - id: &i64, - addr: &PeerId, - name: &str, - is_top: bool, -) -> RpcParam { +pub(crate) fn session_update(id: &i64, addr: &PeerId, name: &str, is_top: bool) -> RpcParam { rpc_response( 0, "session-update", json!([id, addr.to_hex(), name, is_top]), - mgid, ) } #[inline] -pub(crate) fn session_connect(mgid: GroupId, id: &i64, addr: &PeerId) -> RpcParam { - rpc_response(0, "session-connect", json!([id, addr.to_hex()]), mgid) +pub(crate) fn session_connect(id: &i64, addr: &PeerId) -> RpcParam { + rpc_response(0, "session-connect", json!([id, addr.to_hex()])) } #[inline] -pub(crate) fn session_suspend(mgid: GroupId, id: &i64) -> RpcParam { - rpc_response(0, "session-suspend", json!([id]), mgid) +pub(crate) fn session_suspend(id: &i64) -> RpcParam { + rpc_response(0, "session-suspend", json!([id])) } #[inline] -pub(crate) fn session_lost(mgid: GroupId, id: &i64) -> RpcParam { - rpc_response(0, "session-lost", json!([id]), mgid) +pub(crate) fn session_lost(id: &i64) -> RpcParam { + rpc_response(0, "session-lost", json!([id])) } #[inline] -pub(crate) fn session_delete(mgid: GroupId, id: &i64) -> RpcParam { - rpc_response(0, "session-delete", json!([id]), mgid) +pub(crate) fn session_delete(id: &i64) -> RpcParam { + rpc_response(0, "session-delete", json!([id])) } #[inline] -pub(crate) fn session_close(mgid: GroupId, id: &i64) -> RpcParam { - rpc_response(0, "session-close", json!([id]), mgid) +pub(crate) fn session_close(id: &i64) -> RpcParam { + rpc_response(0, "session-close", json!([id])) } #[inline] @@ -146,36 +121,7 @@ fn session_list(sessions: Vec) -> RpcParam { } #[inline] -pub(crate) async fn sleep_waiting_close_stable( - sender: Sender, - groups: HashMap, - layers: HashMap, -) -> std::result::Result<(), SendError> { - tokio::time::sleep(std::time::Duration::from_secs(10)).await; - for (addr, _) in groups { - sender - .send(SendMessage::Group( - Default::default(), - SendType::Disconnect(addr), - )) - .await?; - } - - for (faddr, fgid) in layers { - sender - .send(SendMessage::Layer( - Default::default(), - fgid, - SendType::Disconnect(faddr), - )) - .await?; - } - - Ok(()) -} - -#[inline] -pub(crate) async fn inner_rpc(uid: u64, method: &str, sender: &Sender) -> Result<()> { +pub(crate) async fn inner_rpc(uid: u64, method: &str, global: &Arc) -> Result<()> { // Inner network default rpc method. only use in http-rpc. if method == "network-stable" || method == "network-dht" { let req = match method { @@ -184,11 +130,10 @@ pub(crate) async fn inner_rpc(uid: u64, method: &str, sender: &Sender return Ok(()), }; - let (s, mut r) = mpsc::channel::(128); - let _ = sender + let (s, mut r) = tokio::sync::mpsc::channel::(128); + let _ = global .send(SendMessage::Network(NetworkType::NetworkState(req, s))) - .await - .expect("TDN channel closed"); + .await?; let param = match r.recv().await { Some(StateResponse::Stable(peers)) => network_stable(peers), @@ -198,69 +143,54 @@ pub(crate) async fn inner_rpc(uid: u64, method: &str, sender: &Sender>, - layer: Arc>, -) -> RpcHandler { - let mut handler = RpcHandler::new(RpcState { group, layer }); +fn new_rpc_handler(global: Arc) -> RpcHandler { + let mut handler = RpcHandler::new_with_state(global); - handler.add_method("echo", |_, params, _| async move { + handler.add_method("echo", |params, _| async move { Ok(HandleResult::rpc(json!(params))) }); - handler.add_method("account-system-info", move |_, _, _| async move { - Ok(HandleResult::rpc(json!(vec![addr.to_hex()]))) + handler.add_method("add-bootstrap", |params: Vec, _| async move { + let socket = params[0].as_str().ok_or(RpcError::ParseError)?; + let transport = params[1].as_str().ok_or(RpcError::ParseError)?; + + if let Ok(addr) = socket.parse::() { + Ok(HandleResult::network(NetworkType::Connect( + Peer::socket_transport(addr, transport), + ))) + } else { + Err(RpcError::InvalidRequest) + } }); - handler.add_method( - "add-bootstrap", - |_gid, params: Vec, _| async move { - let socket = params[0].as_str().ok_or(RpcError::ParseError)?; - let transport = params[1].as_str().ok_or(RpcError::ParseError)?; - - if let Ok(addr) = socket.parse::() { - Ok(HandleResult::network(NetworkType::Connect( - Peer::socket_transport(addr, transport), - ))) - } else { - Err(RpcError::InvalidRequest) - } - }, - ); - - handler.add_method( - "account-list", - |_gid, _params: Vec, state: Arc| async move { - let mut users: Vec> = vec![]; - let group_lock = state.group.read().await; - for (gid, user) in group_lock.list_users().iter() { - users.push(vec![ - gid.to_hex(), - user.name.clone(), - base64::encode(&user.avatar), - ]); - } - drop(group_lock); - - Ok(HandleResult::rpc(json!(users))) - }, - ); + handler.add_method("account-list", |_, state: Arc| async move { + let mut accounts: Vec> = vec![]; + let group_lock = state.group.read().await; + for (pid, account) in group_lock.list_accounts().iter() { + accounts.push(vec![ + id_to_str(pid), + account.name.clone(), + base64::encode(&account.avatar), + ]); + } + drop(group_lock); + + Ok(HandleResult::rpc(json!(accounts))) + }); handler.add_method( "account-generate", - |_gid, params: Vec, _state: Arc| async move { + |params: Vec, _state: Arc| async move { let lang = params[0].as_i64().ok_or(RpcError::ParseError)?; let language = lang_from_i64(lang); let words = generate_mnemonic(language, Count::Words12); @@ -270,7 +200,7 @@ fn new_rpc_handler( handler.add_method( "account-create", - |_gid, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let lang = params[0].as_i64().ok_or(RpcError::ParseError)?; let seed = params[1].as_str().ok_or(RpcError::ParseError)?; let pass = params[2].as_str().ok_or(RpcError::ParseError)?; @@ -280,26 +210,29 @@ fn new_rpc_handler( let avatar = params[5].as_str().ok_or(RpcError::ParseError)?; let avatar_bytes = base64::decode(avatar).unwrap_or(vec![]); - let (id, gid) = state + let (_id, pid) = state .group .write() .await - .add_account(lang, seed, pass, name, lock, avatar_bytes) + .add_account( + lang, + seed, + pass, + name, + lock, + avatar_bytes, + &state.base, + &state.secret, + ) .await?; - state.layer.write().await.add_running(&gid, gid, id, 0)?; - - let mut results = HandleResult::rpc(json!(vec![gid.to_hex()])); - results.networks.push(NetworkType::AddGroup(gid)); // add AddGroup to TDN. - debug!("Account Logined: {}.", gid.to_hex()); - - Ok(results) + Ok(HandleResult::rpc(json!(vec![id_to_str(&pid)]))) }, ); handler.add_method( "account-restore", - |_gid, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let lang = params[0].as_i64().ok_or(RpcError::ParseError)?; let seed = params[1].as_str().ok_or(RpcError::ParseError)?; let pass = params[2].as_str().ok_or(RpcError::ParseError)?; @@ -307,60 +240,55 @@ fn new_rpc_handler( let name = params[3].as_str().ok_or(RpcError::ParseError)?; let lock = params[4].as_str().ok_or(RpcError::ParseError)?; - let some_addr = PeerId::from_hex(params[5].as_str().ok_or(RpcError::ParseError)?).ok(); - - let (id, gid) = state + let (_id, pid) = state .group .write() .await - .add_account(lang, seed, pass, name, lock, vec![]) + .add_account( + lang, + seed, + pass, + name, + lock, + vec![], + &state.base, + &state.secret, + ) .await?; - state.layer.write().await.add_running(&gid, gid, id, 0)?; - - let mut results = HandleResult::rpc(json!(vec![gid.to_hex()])); - results.networks.push(NetworkType::AddGroup(gid)); // add AddGroup to TDN. - - debug!("Account Logined: {}.", gid.to_hex()); - - if let Some(addr) = some_addr { - let group_lock = state.group.read().await; - let sender = group_lock.sender(); - let msg = group_lock.create_message(&gid, Peer::peer(addr))?; - drop(group_lock); - tokio::spawn(async move { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let _ = sender.send(SendMessage::Group(gid, msg)).await; - }); - } - Ok(results) + // TODO auto search online account info. + + Ok(HandleResult::rpc(json!(vec![id_to_str(&pid)]))) }, ); handler.add_method( "account-update", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let name = params[0].as_str().ok_or(RpcError::ParseError)?; let avatar = params[1].as_str().ok_or(RpcError::ParseError)?; let avatar_bytes = base64::decode(avatar).unwrap_or(vec![]); + let pid = state.pid().await; let mut group_lock = state.group.write().await; - group_lock.update_account(gid, name, avatar_bytes.clone())?; - let user = group_lock.clone_user(&gid)?; - - let mut results = HandleResult::new(); - group_lock.broadcast( - &gid, - InnerEvent::UserInfo(name.to_owned(), avatar_bytes.clone()), - 0, - 0, - &mut results, + group_lock.update_account( + pid, + name, + avatar_bytes.clone(), + &state.base, + &state.secret, )?; drop(group_lock); - // broadcast all friends. - state.layer.read().await.broadcast(user, &mut results); + let results = HandleResult::new(); + + // TODO broadcast to all devices. + //let user = group_lock.clone_user(&pid)?; + //group_lock.broadcast(&pid, &mut results)?; + + // TODO broadcast to all layers. + //state.layer.read().await.broadcast(user, &mut results); Ok(results) }, @@ -368,81 +296,85 @@ fn new_rpc_handler( handler.add_method( "account-pin-check", - |_gid: GroupId, params: Vec, state: Arc| async move { - let gid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; + |params: Vec, state: Arc| async move { + let pid = id_from_str(params[0].as_str().ok_or(RpcError::ParseError)?)?; let lock = params[1].as_str().ok_or(RpcError::ParseError)?; - let res = state.group.read().await.check_lock(&gid, lock); + let res = state.group.read().await.check_lock(&pid, lock); Ok(HandleResult::rpc(json!([res]))) }, ); handler.add_method( - "account-pin", - |gid: GroupId, params: Vec, state: Arc| async move { + "account-pin-change", + |params: Vec, state: Arc| async move { let old = params[0].as_str().ok_or(RpcError::ParseError)?; let new = params[1].as_str().ok_or(RpcError::ParseError)?; + let pid = state.pid().await; let result = HandleResult::rpc(json!([new])); - state.group.write().await.pin(&gid, old, new)?; + state + .group + .write() + .await + .pin(&pid, old, new, &state.base, &state.secret)?; Ok(result) }, ); handler.add_method( "account-mnemonic", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let lock = params[0].as_str().ok_or(RpcError::ParseError)?; - - let mnemonic = state.group.read().await.mnemonic(&gid, lock)?; + let pid = state.pid().await; + let mnemonic = state + .group + .read() + .await + .mnemonic(&pid, lock, &state.secret)?; Ok(HandleResult::rpc(json!([mnemonic]))) }, ); handler.add_method( "account-login", - |_gid: GroupId, params: Vec, state: Arc| async move { - let ogid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; + |params: Vec, state: Arc| async move { + let pid = id_from_str(params[0].as_str().ok_or(RpcError::ParseError)?)?; let me_lock = params[1].as_str().ok_or(RpcError::ParseError)?; - let mut results = HandleResult::rpc(json!([ogid.to_hex()])); + let results = HandleResult::rpc(json!([id_to_str(&pid)])); - let (id, running) = state.group.write().await.add_running(&ogid, me_lock)?; + let (tdn_send, tdn_recv) = new_send_channel(); + let running = state.reset(&pid, me_lock, tdn_send).await?; if running { return Ok(results); } - // add AddGroup to TDN. - results.networks.push(NetworkType::AddGroup(ogid)); - - let mut layer_lock = state.layer.write().await; - layer_lock.add_running(&ogid, ogid, id, 0)?; // TODO account current state height. - - // load all services layer created by this account. + // load all local services created by this account. + let db_key = state.group.read().await.db_key(&pid)?; + let group_db = group_db(&state.base, &pid, &db_key)?; + let s_db = session_db(&state.base, &pid, &db_key)?; // 1. group chat. - let self_addr = layer_lock.addr.clone(); - let group_lock = state.group.read().await; - let group_db = group_lock.group_db(&ogid)?; - let s_db = group_lock.session_db(&ogid)?; - drop(group_lock); let group_chats = GroupChat::local(&group_db)?; + let mut layer = state.layer.write().await; for g in group_chats { - layer_lock.add_running(&g.g_id, ogid, g.id, g.height)?; - results.networks.push(NetworkType::AddGroup(g.g_id)); - // 2. online group to self group onlines. - if let Some(session) = - connect_session(&s_db, &SessionType::Group, &g.id, &self_addr)? - { - layer_lock.running_mut(&ogid)?.check_add_online( - g.g_id, - Online::Direct(self_addr), - session.id, - g.id, - )?; + if let Some(s) = connect_session(&s_db, &SessionType::Group, &g.id, &pid)? { + layer.group_add(g.gid, g.addr, s.id, g.id, g.height); } } - drop(layer_lock); + drop(layer); + + let key = state.group.read().await.keypair(); + let peer_id = start_main( + state.gids.clone(), + state.p2p_config.clone(), + state.self_send.clone(), + tdn_recv, + None, + Some(key), + ) + .await?; - debug!("Account Logined: {}.", ogid.to_hex()); + debug!("Account Logined: {}.", id_to_str(&peer_id)); Ok(results) }, @@ -450,182 +382,105 @@ fn new_rpc_handler( handler.add_method( "account-logout", - |_gid: GroupId, _params: Vec, state: Arc| async move { - let mut results = HandleResult::new(); - - let group_lock = state.group.read().await; - let layer_lock = state.layer.read().await; - let keys = group_lock.list_running_user(); - - for gid in keys { - for (fgid, addr) in layer_lock.running(&gid)?.onlines() { - // send a event that is offline. - let data = bincode::serialize(&LayerEvent::Offline(*fgid))?; - let msg = SendType::Event(0, *addr, data); - results.layers.push((gid, *fgid, msg)); - } - - debug!("Account Offline: {}.", gid.to_hex()); - // add Remove Group to TDN. - results.networks.push(NetworkType::DelGroup(gid)); - } - drop(group_lock); - drop(layer_lock); - - let mut layer_lock = state.layer.write().await; - let layers = layer_lock.remove_all_running(); - drop(layer_lock); - - let mut group_lock = state.group.write().await; - let groups = group_lock.remove_all_running(); - let sender = group_lock.sender(); - drop(group_lock); - tokio::spawn(sleep_waiting_close_stable(sender, groups, layers)); - - Ok(results) - }, - ); - - handler.add_method( - "account-online", - |_gid: GroupId, params: Vec, state: Arc| async move { - let gid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; - + |_params: Vec, state: Arc| async move { let mut results = HandleResult::new(); - - let group_lock = state.group.read().await; - 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) - }, - ); - - handler.add_method( - "account-offline", - |_gid: GroupId, params: Vec, state: Arc| async move { - let gid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?; - - let mut results = HandleResult::new(); - let layer_lock = state.layer.read().await; - for (fgid, addr) in layer_lock.running(&gid)?.onlines() { - // send a event that is offline. - let data = bincode::serialize(&LayerEvent::Offline(*fgid))?; - let msg = SendType::Event(0, *addr, data); - results.layers.push((gid, *fgid, msg)); - } - drop(layer_lock); - - let layers = state.layer.write().await.remove_running(&gid); - let mut group_lock = state.group.write().await; - let groups = group_lock.remove_running(&gid); - let sender = group_lock.sender(); - drop(group_lock); - tokio::spawn(sleep_waiting_close_stable(sender, groups, layers)); - - debug!("Account Offline: {}.", gid.to_hex()); - // add Remove Group to TDN. - results.networks.push(NetworkType::DelGroup(gid)); - + results.networks.push(NetworkType::NetworkStop); + debug!("Account Offline: {}.", id_to_str(&state.pid().await)); + state.clear().await; Ok(results) }, ); handler.add_method( "session-list", - |gid: GroupId, _params: Vec, state: Arc| async move { - let db = state.group.read().await.session_db(&gid)?; + |_: Vec, state: Arc| async move { + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = session_db(&state.base, &pid, &db_key)?; Ok(HandleResult::rpc(session_list(Session::list(&db)?))) }, ); handler.add_method( "session-connect", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let remote = GroupId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; + let remote = params[1].as_str().ok_or(RpcError::ParseError)?; - let group_lock = state.group.read().await; - let db = group_lock.session_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = session_db(&state.base, &pid, &db_key)?; Session::readed(&db, &id)?; - - let mut layer_lock = state.layer.write().await; - let online = layer_lock.running_mut(&gid)?.active(&remote, true); - drop(layer_lock); - if let Some(addr) = online { - return Ok(HandleResult::rpc(json!([id, addr.to_hex()]))); - } - let s = Session::get(&db, &id)?; drop(db); + let mut layer_lock = state.layer.write().await; + let mut results = HandleResult::new(); match s.s_type { SessionType::Chat => { - let proof = group_lock.prove_addr(&gid, &s.addr)?; - results - .layers - .push((gid, s.gid, chat_conn(proof, Peer::peer(s.addr)))); + let remote_pid = id_from_str(remote)?; + let online = layer_lock.chat_active(&remote_pid, true); + if let Some(addr) = online { + return Ok(HandleResult::rpc(json!([id, id_to_str(&addr)]))); + } + chat_conn(remote_pid, &mut results); } SessionType::Group => { - let proof = group_lock.prove_addr(&gid, &s.addr)?; - add_layer( - &mut results, - gid, - group_conn(proof, Peer::peer(s.addr), s.gid), - ); + let remote_gid: GroupChatId = + remote.parse().map_err(|_| RpcError::ParseError)?; + let online = layer_lock.group_active(&remote_gid, true); + if let Some(addr) = online { + return Ok(HandleResult::rpc(json!([id, id_to_str(&addr)]))); + } + group_conn(s.addr, remote_gid, &mut results); } _ => {} } + Ok(results) }, ); handler.add_method( "session-suspend", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let remote = GroupId::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; + let remote = params[1].as_str().ok_or(RpcError::ParseError)?; let must = params[2].as_bool().ok_or(RpcError::ParseError)?; // if need must suspend. - let db = state.group.read().await.session_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = session_db(&state.base, &pid, &db_key)?; let s = Session::get(&db, &id)?; drop(db); - let msg = match s.s_type { - SessionType::Chat | SessionType::Group => { - let event = LayerEvent::Suspend(s.gid); - let data = bincode::serialize(&event)?; - SendType::Event(0, s.addr, data) - } - _ => { - return Ok(HandleResult::new()); // others has no online. - } - }; - - let mut layer_lock = state.layer.write().await; - let suspend = layer_lock.running_mut(&gid)?.suspend(&remote, true, must)?; - drop(layer_lock); - let mut results = HandleResult::new(); - if suspend { - results.rpcs.push(json!([id])) - } - + let mut layer_lock = state.layer.write().await; match s.s_type { SessionType::Chat => { - results.layers.push((gid, s.gid, msg)); + let remote_id = id_from_str(remote)?; + if layer_lock.chat_suspend(&remote_id, true, must)?.is_some() { + results.rpcs.push(json!([id])); + } + let data = bincode::serialize(&ChatLayerEvent::Suspend)?; + let msg = SendType::Event(0, remote_id, data); + results.layers.push((CHAT_ID, msg)); } SessionType::Group => { - add_layer(&mut results, gid, msg); + let remote_gid: GroupChatId = + remote.parse().map_err(|_| RpcError::ParseError)?; + if layer_lock.group_suspend(&remote_gid, true, must)?.is_some() { + results.rpcs.push(json!([id])); + } + let data = bincode::serialize(&GroupLayerEvent::Suspend(remote_gid))?; + let msg = SendType::Event(0, s.addr, data); + results.layers.push((GROUP_CHAT_ID, msg)); } - _ => {} - } + _ => { + return Ok(HandleResult::new()); // others has no online. + } + }; Ok(results) }, @@ -633,9 +488,12 @@ fn new_rpc_handler( handler.add_method( "session-readed", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.session_db(&gid)?; + + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = session_db(&state.base, &pid, &db_key)?; Session::readed(&db, &id)?; Ok(HandleResult::new()) }, @@ -643,12 +501,14 @@ fn new_rpc_handler( handler.add_method( "session-update", - |gid: GroupId, params: Vec, state: Arc| async move { + |params: Vec, state: Arc| async move { let id = params[0].as_i64().ok_or(RpcError::ParseError)?; let is_top = params[1].as_bool().ok_or(RpcError::ParseError)?; let is_close = params[2].as_bool().ok_or(RpcError::ParseError)?; - let db = state.group.read().await.session_db(&gid)?; + let pid = state.pid().await; + let db_key = state.group.read().await.db_key(&pid)?; + let db = session_db(&state.base, &pid, &db_key)?; Session::update(&db, &id, is_top, is_close)?; Ok(HandleResult::new()) }, diff --git a/src/server.rs b/src/server.rs index 25ff2ea..ca8761f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,7 +5,10 @@ use std::path::PathBuf; use std::sync::Arc; use tdn::{ prelude::*, - types::primitive::{HandleResult, Result}, + types::{ + message::RpcSendMessage, + primitives::{HandleResult, Result}, + }, }; use tokio::{ sync::mpsc::{error::SendError, Sender}, @@ -16,13 +19,14 @@ use tdn_storage::local::DStorage; use crate::account::Account; use crate::apps::app_layer_handle; -use crate::group::Group; +use crate::global::Global; +use crate::group::{handle as group_handle, Group}; use crate::layer::Layer; use crate::migrate::{main_migrate, ACCOUNT_DB}; use crate::primitives::network_seeds; use crate::rpc::{init_rpc, inner_rpc}; -pub const DEFAULT_WS_ADDR: &'static str = "127.0.0.1:8080"; +pub const DEFAULT_WS_ADDR: &'static str = "127.0.0.1:7366"; pub const DEFAULT_LOG_FILE: &'static str = "esse.log.txt"; pub static RPC_WS_UID: OnceCell = OnceCell::new(); @@ -61,49 +65,46 @@ pub async fn start(db_path: String) -> Result<()> { let account_db = DStorage::open(account_db_path, &hex::encode(&rand_secret))?; let accounts = Account::all(&account_db)?; account_db.close()?; - let mut me: HashMap = HashMap::new(); + let mut me: HashMap = HashMap::new(); for account in accounts { - me.insert(account.gid, account); + me.insert(account.pid, account); } - config.group_ids = me.keys().cloned().collect(); - let (peer_id, sender, mut recver) = start_with_config(config).await?; - info!("Network Peer id : {}", peer_id.to_hex()); - - let group = Arc::new(RwLock::new( - Group::init(rand_secret, sender.clone(), peer_id, me, db_path.clone()).await?, - )); - let layer = Arc::new(RwLock::new( - Layer::init(db_path, peer_id, group.clone()).await?, + let (_, _, p2p_config, rpc_config) = config.split(); + let (self_send, mut self_recv) = new_receive_channel(); + let rpc_send = start_rpc(rpc_config, self_send.clone()).await?; + + let global = Arc::new(Global::init( + me, + db_path, + rand_secret, + p2p_config, + self_send, + rpc_send, )); - let rpc = init_rpc(peer_id, group.clone(), layer.clone()); - //let mut group_rpcs: HashMap = HashMap::new(); + let rpc = init_rpc(global.clone()); + // //let mut group_rpcs: HashMap = HashMap::new(); let mut now_rpc_uid = 0; - // running session remain task. - tokio::spawn(session_remain(peer_id, layer.clone(), sender.clone())); + // // running session remain task. + // tokio::spawn(session_remain(peer_id, layer.clone(), sender.clone())); - while let Some(message) = recver.recv().await { + while let Some(message) = self_recv.recv().await { match message { - ReceiveMessage::Group(fgid, g_msg) => { - if let Ok(handle_result) = group - .write() - .await - .handle(fgid, g_msg, &layer, now_rpc_uid) - .await - { - handle(handle_result, now_rpc_uid, true, &sender).await; + ReceiveMessage::Group(g_msg) => { + if let Ok(handle_result) = group_handle(g_msg, &global).await { + handle(handle_result, now_rpc_uid, true, &global).await; } } ReceiveMessage::Layer(fgid, tgid, l_msg) => { - if let Ok(handle_result) = app_layer_handle(&layer, fgid, tgid, l_msg).await { - handle(handle_result, now_rpc_uid, true, &sender).await; + if let Ok(handle_result) = app_layer_handle(fgid, tgid, l_msg, &global).await { + handle(handle_result, now_rpc_uid, true, &global).await; } } ReceiveMessage::Rpc(uid, params, is_ws) => { if !is_ws { - if inner_rpc(uid, params["method"].as_str().unwrap(), &sender) + if inner_rpc(uid, params["method"].as_str().unwrap(), &global) .await .is_ok() { @@ -117,23 +118,22 @@ pub async fn start(db_path: String) -> Result<()> { } if let Ok(handle_result) = rpc.handle(params).await { - handle(handle_result, uid, is_ws, &sender).await; + handle(handle_result, uid, is_ws, &global).await; } } ReceiveMessage::NetworkLost => { - sender + global .send(SendMessage::Network(NetworkType::NetworkReboot)) - .await - .expect("TDN channel closed"); - let t_sender = sender.clone(); - let g_conns = group.read().await.all_distribute_conns(); - let l_conns = layer - .read() - .await - .all_layer_conns() - .await - .unwrap_or(HashMap::new()); - tokio::spawn(sleep_waiting_reboot(t_sender, g_conns, l_conns)); + .await?; + // let t_sender = tdn_send.clone(); + // let g_conns = group.read().await.all_distribute_conns(); + // let l_conns = layer + // .read() + // .await + // .all_layer_conns() + // .await + // .unwrap_or(HashMap::new()); + // tokio::spawn(sleep_waiting_reboot(t_sender, g_conns, l_conns)); } } } @@ -141,81 +141,81 @@ pub async fn start(db_path: String) -> Result<()> { Ok(()) } -#[inline] -async fn sleep_waiting_reboot( - sender: Sender, - groups: HashMap>, - layers: HashMap>, -) -> std::result::Result<(), SendError> { - tokio::time::sleep(std::time::Duration::from_secs(10)).await; - - for (gid, conns) in groups { - for conn in conns { - sender.send(SendMessage::Group(gid, conn)).await?; - } - } - - for (fgid, conns) in layers { - for (tgid, conn) in conns { - sender.send(SendMessage::Layer(fgid, tgid, conn)).await?; - } - } - - Ok(()) -} - -async fn session_remain( - self_addr: PeerId, - layer: Arc>, - sender: Sender, -) -> Result<()> { - loop { - tokio::time::sleep(std::time::Duration::from_secs(120)).await; - if let Some(uid) = RPC_WS_UID.get() { - let mut layer_lock = layer.write().await; - let mut rpcs = vec![]; - let mut addrs = HashMap::new(); - - for (_, running) in layer_lock.runnings.iter_mut() { - let closed = running.close_suspend(&self_addr); - for (gid, addr, sid) in closed { - addrs.insert(addr, false); - rpcs.push(crate::rpc::session_lost(gid, &sid)); - } - } - drop(layer_lock); - - let layer_lock = layer.read().await; - for (_, running) in layer_lock.runnings.iter() { - for (addr, keep) in addrs.iter_mut() { - if running.check_addr_online(addr) { - *keep = true; - } - } - } - drop(layer_lock); - - for rpc in rpcs { - let _ = sender.send(SendMessage::Rpc(*uid, rpc, true)).await; - } - - for (addr, keep) in addrs { - if !keep { - let _ = sender - .send(SendMessage::Layer( - GroupId::default(), - GroupId::default(), - SendType::Disconnect(addr), - )) - .await; - } - } - } - } -} +// #[inline] +// async fn sleep_waiting_reboot( +// sender: Sender, +// groups: HashMap>, +// layers: HashMap>, +// ) -> std::result::Result<(), SendError> { +// tokio::time::sleep(std::time::Duration::from_secs(10)).await; + +// for (gid, conns) in groups { +// for conn in conns { +// sender.send(SendMessage::Group(gid, conn)).await?; +// } +// } + +// for (fgid, conns) in layers { +// for (tgid, conn) in conns { +// sender.send(SendMessage::Layer(fgid, tgid, conn)).await?; +// } +// } + +// Ok(()) +// } + +// async fn session_remain( +// self_addr: PeerId, +// layer: Arc>, +// sender: Sender, +// ) -> Result<()> { +// loop { +// tokio::time::sleep(std::time::Duration::from_secs(120)).await; +// if let Some(uid) = RPC_WS_UID.get() { +// let mut layer_lock = layer.write().await; +// let mut rpcs = vec![]; +// let mut addrs = HashMap::new(); + +// for (_, running) in layer_lock.runnings.iter_mut() { +// let closed = running.close_suspend(&self_addr); +// for (gid, addr, sid) in closed { +// addrs.insert(addr, false); +// rpcs.push(crate::rpc::session_lost(gid, &sid)); +// } +// } +// drop(layer_lock); + +// let layer_lock = layer.read().await; +// for (_, running) in layer_lock.runnings.iter() { +// for (addr, keep) in addrs.iter_mut() { +// if running.check_addr_online(addr) { +// *keep = true; +// } +// } +// } +// drop(layer_lock); + +// for rpc in rpcs { +// let _ = sender.send(SendMessage::Rpc(*uid, rpc, true)).await; +// } + +// for (addr, keep) in addrs { +// if !keep { +// let _ = sender +// .send(SendMessage::Layer( +// GroupId::default(), +// GroupId::default(), +// SendType::Disconnect(addr), +// )) +// .await; +// } +// } +// } +// } +// } #[inline] -async fn handle(handle_result: HandleResult, uid: u64, is_ws: bool, sender: &Sender) { +async fn handle(handle_result: HandleResult, uid: u64, is_ws: bool, global: &Arc) { let HandleResult { mut rpcs, mut groups, @@ -226,8 +226,9 @@ async fn handle(handle_result: HandleResult, uid: u64, is_ws: bool, sender: &Sen loop { if rpcs.len() != 0 { let msg = rpcs.remove(0); - sender - .send(SendMessage::Rpc(uid, msg, is_ws)) + global + .rpc_send + .send(RpcSendMessage(uid, msg, is_ws)) .await .expect("TDN channel closed"); } else { @@ -235,39 +236,42 @@ async fn handle(handle_result: HandleResult, uid: u64, is_ws: bool, sender: &Sen } } - loop { - if networks.len() != 0 { - let msg = networks.remove(0); - sender - .send(SendMessage::Network(msg)) - .await - .expect("TDN channel closed"); - } else { - break; + if let Ok(sender) = global.sender().await { + loop { + if groups.len() != 0 { + let msg = groups.remove(0); + sender + .send(SendMessage::Group(msg)) + .await + .expect("TDN channel closed"); + } else { + break; + } } - } - loop { - if groups.len() != 0 { - let (gid, msg) = groups.remove(0); - sender - .send(SendMessage::Group(gid, msg)) - .await - .expect("TDN channel closed"); - } else { - break; + loop { + if layers.len() != 0 { + let (tgid, msg) = layers.remove(0); + sender + .send(SendMessage::Layer(tgid, msg)) + .await + .expect("TDN channel closed"); + } else { + break; + } } - } - loop { - if layers.len() != 0 { - let (fgid, tgid, msg) = layers.remove(0); - sender - .send(SendMessage::Layer(fgid, tgid, msg)) - .await - .expect("TDN channel closed"); - } else { - break; + // must last send, because it will has stop type. + loop { + if networks.len() != 0 { + let msg = networks.remove(0); + sender + .send(SendMessage::Network(msg)) + .await + .expect("TDN channel closed"); + } else { + break; + } } } } diff --git a/src/session.rs b/src/session.rs index c7abdef..3fb050c 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,6 +1,5 @@ use tdn::types::{ - group::GroupId, - primitive::{PeerId, Result}, + primitives::{PeerId, Result}, rpc::{json, RpcParam}, }; use tdn_storage::local::{DStorage, DsValue}; @@ -36,7 +35,7 @@ impl SessionType { pub(crate) struct Session { pub id: i64, fid: i64, - pub gid: GroupId, + pub pid: String, pub addr: PeerId, pub s_type: SessionType, name: String, @@ -50,7 +49,7 @@ pub(crate) struct Session { impl Session { pub fn new( fid: i64, - gid: GroupId, + pid: String, addr: PeerId, s_type: SessionType, name: String, @@ -58,7 +57,7 @@ impl Session { ) -> Self { Self { fid, - gid, + pid, addr, s_type, name, @@ -75,7 +74,7 @@ impl Session { json!([ self.id, self.fid, - self.gid.to_hex(), + self.pid, self.addr.to_hex(), self.s_type.to_int(), self.name, @@ -97,7 +96,7 @@ impl Session { name: v.pop().unwrap().as_string(), s_type: SessionType::from_int(v.pop().unwrap().as_i64()), addr: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), - gid: GroupId::from_hex(v.pop().unwrap().as_str()).unwrap_or(GroupId::default()), + pid: v.pop().unwrap().as_string(), fid: v.pop().unwrap().as_i64(), id: v.pop().unwrap().as_i64(), } @@ -113,8 +112,8 @@ impl Session { let id = unique_check.pop().unwrap().pop().unwrap().as_i64(); self.id = id; - let sql = format!("UPDATE sessions SET gid = '{}', addr='{}', name = '{}', is_top = '{}', is_close = false WHERE id = {}", - self.gid.to_hex(), + let sql = format!("UPDATE sessions SET pid='{}', addr='{}', name = '{}', is_top = '{}', is_close = false WHERE id = {}", + self.pid, self.addr.to_hex(), self.name, self.is_top, @@ -122,9 +121,9 @@ impl Session { ); db.update(&sql)?; } else { - let sql = format!("INSERT INTO sessions (fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES ({}, '{}', '{}', {}, '{}', {}, {}, {}, '{}', {})", + let sql = format!("INSERT INTO sessions (fid, pid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed) VALUES ({}, '{}', '{}', {}, '{}', {}, {}, {}, '{}', {})", self.fid, - self.gid.to_hex(), + self.pid, self.addr.to_hex(), self.s_type.to_int(), self.name, @@ -142,7 +141,7 @@ impl Session { } pub fn get(db: &DStorage, id: &i64) -> Result { - let sql = format!("SELECT id, fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions WHERE id = {}", id); + let sql = format!("SELECT id, fid, pid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions WHERE id = {}", id); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Session::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -152,7 +151,7 @@ impl Session { } pub fn list(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions ORDER BY last_datetime DESC")?; + let matrix = db.query("SELECT id, fid, pid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions ORDER BY last_datetime DESC")?; let mut sessions = vec![]; for values in matrix { sessions.push(Session::from_values(values)); @@ -268,7 +267,7 @@ pub(crate) fn connect_session( fid: &i64, addr: &PeerId, ) -> Result> { - let sql = format!("SELECT id, fid, gid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions WHERE s_type = {} AND fid = {}", s_type.to_int(), fid); + let sql = format!("SELECT id, fid, pid, addr, s_type, name, is_top, is_close, last_datetime, last_content, last_readed FROM sessions WHERE s_type = {} AND fid = {}", s_type.to_int(), fid); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { diff --git a/src/storage.rs b/src/storage.rs index e2fc140..db7885f 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,12 +1,17 @@ +use esse_primitives::id_to_str; use image::{load_from_memory, DynamicImage, GenericImageView}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; +use tdn::types::primitives::{PeerId, Result}; +use tdn_storage::local::DStorage; use tokio::fs; -use tdn::types::{group::GroupId, primitive::Result}; - use crate::migrate::account_init_migrate; +use crate::migrate::{ + ACCOUNT_DB, CHAT_DB, CLOUD_DB, CONSENSUS_DB, DAO_DB, DOMAIN_DB, FILE_DB, GROUP_DB, JARVIS_DB, + SERVICE_DB, SESSION_DB, WALLET_DB, +}; const FILES_DIR: &'static str = "files"; const IMAGE_DIR: &'static str = "images"; @@ -56,11 +61,11 @@ pub(crate) async fn read_file(base: &PathBuf) -> Result> { pub(crate) async fn copy_file( target: &PathBuf, base: &PathBuf, - gid: &GroupId, + pid: &PeerId, name: &str, ) -> Result<()> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(FILES_DIR); path.push(name); fs::copy(target, path).await?; @@ -69,12 +74,12 @@ pub(crate) async fn copy_file( pub(crate) async fn write_file( base: &PathBuf, - gid: &GroupId, + pid: &PeerId, name: &str, bytes: &[u8], ) -> Result { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(FILES_DIR); path.push(name); fs::write(path, bytes).await?; @@ -83,12 +88,12 @@ pub(crate) async fn write_file( pub(crate) fn write_file_sync( base: &PathBuf, - gid: &GroupId, + pid: &PeerId, name: &str, bytes: Vec, ) -> Result { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(FILES_DIR); path.push(name); tokio::spawn(async move { fs::write(path, bytes).await }); @@ -96,9 +101,9 @@ pub(crate) fn write_file_sync( Ok(name.to_owned()) } -pub(crate) async fn read_db_file(base: &PathBuf, gid: &GroupId, name: &str) -> Result> { +pub(crate) async fn read_db_file(base: &PathBuf, pid: &PeerId, name: &str) -> Result> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(FILES_DIR); path.push(name); if path.exists() { @@ -108,9 +113,9 @@ pub(crate) async fn read_db_file(base: &PathBuf, gid: &GroupId, name: &str) -> R } } -pub(crate) async fn read_image(base: &PathBuf, gid: &GroupId, name: &str) -> Result> { +pub(crate) async fn read_image(base: &PathBuf, pid: &PeerId, name: &str) -> Result> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(IMAGE_DIR); path.push(name); if path.exists() { @@ -143,9 +148,9 @@ fn image_thumb(bytes: &[u8]) -> Result { } } -pub(crate) fn write_image_sync(base: &PathBuf, gid: &GroupId, bytes: Vec) -> Result { +pub(crate) fn write_image_sync(base: &PathBuf, pid: &PeerId, bytes: Vec) -> Result { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); let thumb = image_thumb(&bytes)?; let name = image_name(); @@ -164,9 +169,9 @@ pub(crate) fn write_image_sync(base: &PathBuf, gid: &GroupId, bytes: Vec) -> Ok(name) } -pub(crate) async fn write_image(base: &PathBuf, gid: &GroupId, bytes: &[u8]) -> Result { +pub(crate) async fn write_image(base: &PathBuf, pid: &PeerId, bytes: &[u8]) -> Result { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); let thumb = image_thumb(bytes)?; let name = image_name(); @@ -186,19 +191,15 @@ pub(crate) async fn write_image(base: &PathBuf, gid: &GroupId, bytes: &[u8]) -> } #[inline] -fn avatar_png(gid: &GroupId) -> String { - let mut gs = gid.to_hex(); +fn avatar_png(pid: &PeerId) -> String { + let mut gs = id_to_str(pid); gs.push_str(".png"); gs } -pub(crate) async fn read_avatar( - base: &PathBuf, - gid: &GroupId, - remote: &GroupId, -) -> Result> { +pub(crate) async fn read_avatar(base: &PathBuf, pid: &PeerId, remote: &PeerId) -> Result> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); if path.exists() { @@ -208,9 +209,9 @@ pub(crate) async fn read_avatar( } } -pub(crate) fn read_avatar_sync(base: &PathBuf, gid: &GroupId, remote: &GroupId) -> Result> { +pub(crate) fn read_avatar_sync(base: &PathBuf, pid: &PeerId, remote: &PeerId) -> Result> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); if path.exists() { @@ -222,15 +223,15 @@ pub(crate) fn read_avatar_sync(base: &PathBuf, gid: &GroupId, remote: &GroupId) pub(crate) async fn write_avatar( base: &PathBuf, - gid: &GroupId, - remote: &GroupId, + pid: &PeerId, + remote: &PeerId, bytes: &[u8], ) -> Result<()> { if bytes.len() < 1 { return Ok(()); } let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); Ok(fs::write(path, bytes).await?) @@ -238,24 +239,24 @@ pub(crate) async fn write_avatar( pub(crate) fn write_avatar_sync( base: &PathBuf, - gid: &GroupId, - remote: &GroupId, + pid: &PeerId, + remote: &PeerId, bytes: Vec, ) -> Result<()> { if bytes.len() < 1 { return Ok(()); } let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); tokio::spawn(async move { fs::write(path, bytes).await }); Ok(()) } -pub(crate) async fn delete_avatar(base: &PathBuf, gid: &GroupId, remote: &GroupId) -> Result<()> { +pub(crate) async fn delete_avatar(base: &PathBuf, pid: &PeerId, remote: &PeerId) -> Result<()> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); if path.exists() { @@ -265,9 +266,9 @@ pub(crate) async fn delete_avatar(base: &PathBuf, gid: &GroupId, remote: &GroupI } } -pub(crate) fn delete_avatar_sync(base: &PathBuf, gid: &GroupId, remote: &GroupId) -> Result<()> { +pub(crate) fn delete_avatar_sync(base: &PathBuf, pid: &PeerId, remote: &PeerId) -> Result<()> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(AVATAR_DIR); path.push(avatar_png(remote)); if path.exists() { @@ -276,9 +277,9 @@ pub(crate) fn delete_avatar_sync(base: &PathBuf, gid: &GroupId, remote: &GroupId Ok(()) } -pub(crate) async fn read_record(base: &PathBuf, gid: &GroupId, name: &str) -> Result> { +pub(crate) async fn read_record(base: &PathBuf, pid: &PeerId, name: &str) -> Result> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(RECORD_DIR); path.push(name); if path.exists() { @@ -290,7 +291,7 @@ pub(crate) async fn read_record(base: &PathBuf, gid: &GroupId, name: &str) -> Re pub(crate) fn write_record_sync( base: &PathBuf, - gid: &GroupId, + pid: &PeerId, t: u32, bytes: Vec, ) -> Result { @@ -301,7 +302,7 @@ pub(crate) fn write_record_sync( .unwrap_or(0u128); let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(RECORD_DIR); path.push(format!("{}.m4a", datetime)); tokio::spawn(async move { fs::write(path, bytes).await }); @@ -309,27 +310,110 @@ pub(crate) fn write_record_sync( Ok(format!("{}_{}.m4a", t, datetime)) } -pub(crate) async fn _delete_record(base: &PathBuf, gid: &GroupId, name: &str) -> Result<()> { +pub(crate) async fn _delete_record(base: &PathBuf, pid: &PeerId, name: &str) -> Result<()> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(RECORD_DIR); path.push(name); Ok(fs::remove_file(path).await?) } -pub(crate) fn _write_emoji(base: &PathBuf, gid: &GroupId) -> Result<()> { +pub(crate) fn _write_emoji(base: &PathBuf, pid: &PeerId) -> Result<()> { let mut path = base.clone(); - path.push(gid.to_hex()); + path.push(id_to_str(pid)); path.push(EMOJI_DIR); Ok(()) } /// account independent db and storage directory. -pub(crate) async fn account_init(base: &PathBuf, key: &str, gid: &GroupId) -> Result<()> { +pub(crate) async fn account_init(base: &PathBuf, key: &str, pid: &PeerId) -> Result<()> { let mut db_path = base.clone(); - db_path.push(gid.to_hex()); + db_path.push(id_to_str(pid)); init_local_files(&db_path).await?; // Inner Database. account_init_migrate(&db_path, key) } + +pub(crate) fn account_db(base: &PathBuf, secret: &[u8]) -> Result { + let mut db_path = base.clone(); + db_path.push(ACCOUNT_DB); + DStorage::open(db_path, &hex::encode(secret)) +} + +pub(crate) fn consensus_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(CONSENSUS_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn session_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(SESSION_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn chat_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(CHAT_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn file_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(FILE_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn _service_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(SERVICE_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn jarvis_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(JARVIS_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn group_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(GROUP_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn _dao_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(DAO_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn domain_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(DOMAIN_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn wallet_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(WALLET_DB); + DStorage::open(db_path, db_key) +} + +pub(crate) fn _cloud_db(base: &PathBuf, pid: &PeerId, db_key: &str) -> Result { + let mut db_path = base.clone(); + db_path.push(id_to_str(pid)); + db_path.push(CLOUD_DB); + DStorage::open(db_path, db_key) +} diff --git a/types/cloud/Cargo.toml b/types/cloud/Cargo.toml index 403599c..0831f88 100644 --- a/types/cloud/Cargo.toml +++ b/types/cloud/Cargo.toml @@ -12,4 +12,3 @@ license = "MIT/Apache-2.0" [dependencies] serde = { version = "1", features = ["derive"] } tdn_types = { version = "0.7", default-features = false } -tdn_did = { version = "0.7", default-features = false } diff --git a/types/cloud/src/lib.rs b/types/cloud/src/lib.rs index 5f4e037..703b364 100644 --- a/types/cloud/src/lib.rs +++ b/types/cloud/src/lib.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use tdn_did::Proof; use tdn_types::group::GroupId; /// Personal data cloud service default TDN GROUP ID. @@ -7,11 +6,11 @@ pub const CLOUD_ID: GroupId = 5; /// ESSE service to peer layer Event. #[derive(Serialize, Deserialize)] -pub struct LayerServerEvent(pub ServerEvent, pub Proof); +pub struct LayerServerEvent(pub ServerEvent); /// ESSE peer to layer Event. #[derive(Serialize, Deserialize)] -pub struct LayerPeerEvent(pub PeerEvent, pub Proof); +pub struct LayerPeerEvent(pub PeerEvent); /// ESSE service to peer Event. #[derive(Serialize, Deserialize)] diff --git a/types/dao/src/lib.rs b/types/dao/src/lib.rs index 970fd3b..698564a 100644 --- a/types/dao/src/lib.rs +++ b/types/dao/src/lib.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use tdn_did::Proof; use tdn_types::{group::GroupId, primitives::PeerId}; use chat_types::NetworkMessage; @@ -91,10 +90,10 @@ pub struct LayerResult(pub DaoId, pub i64); pub enum ConnectProof { /// when is joined in group chat, can only use had to join (connect). /// params: proof. - Common(Proof), + Common, /// zero-knowledge-proof. not has account id. /// verify(proof, key_hash, current_peer_addr). - Zkp(Proof), // TODO MOCK-PROOF + Zkp, // TODO MOCK-PROOF } /// Dao chat join proof. @@ -104,11 +103,11 @@ pub enum JoinProof { /// params: member name, member avatar. Open(String, Vec), /// when is invate, it will take group_manager's proof for invate. - /// params: invite_by_account, invite_proof, member name, member avatar. - Invite(PeerId, Proof, String, Vec), + /// params: invite_by_account, member name, member avatar. + Invite(PeerId, String, Vec), /// zero-knowledge-proof. not has account id. /// verify(proof, key_hash, current_peer_addr). - Zkp(Proof), // TODO MOCK-PROOF + Zkp, // TODO MOCK-PROOF } /// check result type. @@ -150,8 +149,8 @@ pub enum LayerEvent { /// params: check type, provider name, remain, supported_group_types. CheckResult(CheckType, String, i64, Vec), /// create a Group Chat. - /// params: group_info, proof. - Create(DaoInfo, Proof), + /// params: group_info. + Create(DaoInfo), /// result create group success. /// params: Group ID, is_ok. CreateResult(DaoId, bool), diff --git a/types/domain/Cargo.toml b/types/domain/Cargo.toml index d5548a4..d972d1f 100644 --- a/types/domain/Cargo.toml +++ b/types/domain/Cargo.toml @@ -12,4 +12,3 @@ license = "MIT/Apache-2.0" [dependencies] serde = { version = "1", features = ["derive"] } tdn_types = { version = "0.7", default-features = false } -tdn_did = { version = "0.7", default-features = false } diff --git a/types/domain/src/lib.rs b/types/domain/src/lib.rs index 473770b..409a6cd 100644 --- a/types/domain/src/lib.rs +++ b/types/domain/src/lib.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use tdn_did::Proof; use tdn_types::{group::GroupId, primitives::PeerId}; // Same ID can has many name !. @@ -7,17 +6,9 @@ use tdn_types::{group::GroupId, primitives::PeerId}; /// Group chat app(service) default TDN GROUP ID. pub const DOMAIN_ID: GroupId = 4; -/// ESSE domain service layer Event. -#[derive(Serialize, Deserialize)] -pub struct LayerServerEvent(pub ServerEvent, pub Proof); - -/// ESSE domain service layer Event. -#[derive(Serialize, Deserialize)] -pub struct LayerPeerEvent(pub PeerEvent, pub Proof); - /// ESSE domain service to peer layer Event. #[derive(Serialize, Deserialize)] -pub enum ServerEvent { +pub enum LayerServerEvent { /// check result status. /// params: provider name, is support request proxy. Status(String, bool), @@ -42,7 +33,7 @@ pub enum ServerEvent { /// ESSE domain peer to service layer Event. #[derive(Serialize, Deserialize)] -pub enum PeerEvent { +pub enum LayerPeerEvent { /// check service status is ok. Check, /// register new unique identity to service. diff --git a/types/group/Cargo.toml b/types/group/Cargo.toml index a93cbe0..ad0a699 100644 --- a/types/group/Cargo.toml +++ b/types/group/Cargo.toml @@ -13,4 +13,3 @@ license = "MIT/Apache-2.0" chat_types = { path = "../chat", version = "0.1" } serde = { version = "1", features = ["derive"] } tdn_types = { version = "0.7", default-features = false } -tdn_did = { version = "0.7", default-features = false } diff --git a/types/group/src/lib.rs b/types/group/src/lib.rs index bd6250e..050370b 100644 --- a/types/group/src/lib.rs +++ b/types/group/src/lib.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use tdn_did::Proof; use tdn_types::{group::GroupId, primitives::PeerId}; use chat_types::NetworkMessage; @@ -11,9 +10,9 @@ pub const GROUP_CHAT_ID: GroupId = 2; pub type GroupChatId = u64; /// Group chat connect data structure. -/// params: Group Chat ID, join_proof. +/// params: Group Chat ID. #[derive(Serialize, Deserialize)] -pub struct LayerConnect(pub GroupChatId, pub Proof); +pub struct LayerConnect(pub GroupChatId); /// Group chat connect success result data structure. /// params: Group ID, group name, group current height. @@ -63,20 +62,20 @@ pub enum LayerEvent { impl LayerEvent { /// get event's group id. - pub fn gcd(&self) -> &GroupChatId { + pub fn gid(&self) -> &GroupChatId { match self { - Self::Offline(gcd) => gcd, - Self::Suspend(gcd) => gcd, - Self::Actived(gcd) => gcd, - Self::MemberOnline(gcd, ..) => gcd, - Self::MemberOffline(gcd, ..) => gcd, - Self::MemberOnlineSync(gcd) => gcd, - Self::MemberOnlineSyncResult(gcd, ..) => gcd, - Self::GroupName(gcd, ..) => gcd, - Self::GroupClose(gcd) => gcd, - Self::Sync(gcd, ..) => gcd, - Self::SyncReq(gcd, ..) => gcd, - Self::SyncRes(gcd, ..) => gcd, + Self::Offline(gid) => gid, + Self::Suspend(gid) => gid, + Self::Actived(gid) => gid, + Self::MemberOnline(gid, ..) => gid, + Self::MemberOffline(gid, ..) => gid, + Self::MemberOnlineSync(gid) => gid, + Self::MemberOnlineSyncResult(gid, ..) => gid, + Self::GroupName(gid, ..) => gid, + Self::GroupClose(gid) => gid, + Self::Sync(gid, ..) => gid, + Self::SyncReq(gid, ..) => gid, + Self::SyncRes(gid, ..) => gid, } } } diff --git a/types/primitives/src/lib.rs b/types/primitives/src/lib.rs index 0209250..39aab94 100644 --- a/types/primitives/src/lib.rs +++ b/types/primitives/src/lib.rs @@ -77,11 +77,11 @@ pub mod bs32 { use tdn_types::primitives::{new_io_error, PeerId, PEER_ID_LENGTH}; -pub fn id_to_string(peer: &PeerId) -> String { +pub fn id_to_str(peer: &PeerId) -> String { bs32::encode(&peer.0) } -pub fn id_from_string(s: &str) -> std::io::Result { +pub fn id_from_str(s: &str) -> std::io::Result { let data = bs32::decode(s).ok_or(new_io_error("id from string is failure."))?; if data.len() != PEER_ID_LENGTH { return Err(new_io_error("id from string is failure.")); diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index a7402be..d52ab30 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,14 +7,17 @@ #include "generated_plugin_registrant.h" #include -#include +#include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { EsseCorePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("EsseCorePlugin")); - FileSelectorPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FileSelectorPlugin")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 1dccebe..66b79ea 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST esse_core file_selector_windows + permission_handler_windows url_launcher_windows )