From 44be5c86027bf187888c84bf70fcea543b294d70 Mon Sep 17 00:00:00 2001 From: Sun Date: Thu, 20 May 2021 10:54:06 +0800 Subject: [PATCH] group chat agree/reject/sync --- lib/apps/group_chat/add.dart | 14 ++++--- lib/apps/group_chat/models.dart | 5 +++ lib/apps/group_chat/provider.dart | 33 +++++++++++---- src/apps/group_chat/layer.rs | 69 ++++++++++++++++++++++++++----- src/apps/group_chat/models.rs | 10 +++++ src/apps/group_chat/rpc.rs | 39 ++++++++++++++--- 6 files changed, 142 insertions(+), 28 deletions(-) diff --git a/lib/apps/group_chat/add.dart b/lib/apps/group_chat/add.dart index 3b66eed..b60240c 100644 --- a/lib/apps/group_chat/add.dart +++ b/lib/apps/group_chat/add.dart @@ -53,6 +53,7 @@ class _GroupAddPageState extends State { bool _groupHasNeedAgree = true; bool _addrOnline = false; bool _addrChecked = false; + String _myName = ''; // 0 => encrypted, 1 => common, 2 => open. Widget _groupTypeWidget(String text, int value, ColorScheme color) { @@ -132,7 +133,6 @@ class _GroupAddPageState extends State { } _create() { - final myName = context.read().activedAccount.name; var addr = _createAddrController.text.trim(); // if has 0x, need remove if (addr.substring(0, 2) == '0x') { @@ -140,7 +140,7 @@ class _GroupAddPageState extends State { } final name = _createNameController.text.trim(); final bio = _createBioController.text.trim(); - context.read().create(myName, addr, name, bio, _groupNeedAgree); + context.read().create(_groupType, _myName, addr, name, bio, _groupNeedAgree); setState(() { _createNameController.text = ''; _createBioController.text = ''; @@ -151,6 +151,8 @@ class _GroupAddPageState extends State { @override void initState() { super.initState(); + _addrChecked = false; + _joinIdController.text = widget.id; _joinAddrController.text = widget.addr; _joinNameController.text = widget.name; @@ -178,6 +180,7 @@ class _GroupAddPageState extends State { }); new Future.delayed(Duration.zero, () { //context.read().requestList(); + _myName = context.read().activedAccount.name; }); } @@ -460,7 +463,7 @@ class _GroupAddPageState extends State { physics: ClampingScrollPhysics(), scrollDirection: Axis.vertical, itemBuilder: (BuildContext context, int index) => - _CreateItem(group: groups[createKeys[index]]), + _CreateItem(group: groups[createKeys[index]], name: _myName), ), ) ], @@ -695,7 +698,8 @@ class _RequestItem extends StatelessWidget { class _CreateItem extends StatelessWidget { final GroupChat group; - const _CreateItem({Key key, this.group}) : super(key: key); + final String name; + const _CreateItem({Key key, this.group, this.name}) : super(key: key); @override Widget build(BuildContext context) { @@ -738,7 +742,7 @@ class _CreateItem extends StatelessWidget { style: TextStyle(color: Color(0xFFADB0BB), fontSize: 14.0), )) : InkWell( - onTap: () => context.read().reSend(group.id), + onTap: () => context.read().reSend(group.id, name), hoverColor: Colors.transparent, child: Container( height: 35.0, diff --git a/lib/apps/group_chat/models.dart b/lib/apps/group_chat/models.dart index 3898d49..68d854d 100644 --- a/lib/apps/group_chat/models.dart +++ b/lib/apps/group_chat/models.dart @@ -148,6 +148,11 @@ class Request { bool get isMe => this.fid == 0; + overIt(bool ok) { + this.ok = ok; + this.over = true; + } + Avatar showAvatar([double width = 45.0]) { final avatar = Global.avatarPath + this.gid + '.png'; return Avatar( diff --git a/lib/apps/group_chat/provider.dart b/lib/apps/group_chat/provider.dart index 73834e7..5761c8c 100644 --- a/lib/apps/group_chat/provider.dart +++ b/lib/apps/group_chat/provider.dart @@ -43,8 +43,8 @@ class GroupChatProvider extends ChangeNotifier { rpc.addListener('group-chat-detail', _detail, true); // rpc.addListener('group-chat-update', _update, false); rpc.addListener('group-chat-join', _join, true); - // rpc.addListener('group-chat-agree', _agree, true); - // rpc.addListener('group-chat-reject', _reject, false); + rpc.addListener('group-chat-agree', _agree, true); + rpc.addListener('group-chat-reject', _reject, false); rpc.addListener('group-chat-member-join', _memberJoin, false); rpc.addListener('group-chat-member-info', _memberInfo, false); // rpc.addListener('group-chat-member-leave', _memberLeave, false); @@ -85,13 +85,12 @@ class GroupChatProvider extends ChangeNotifier { rpc.send('group-chat-check', [addr]); } - create(String myName, String addr, String name, String bio, bool needAgree) { - print(addr); - rpc.send('group-chat-create', [myName, addr, name, bio, needAgree]); + create(int gtype, String myName, String addr, String name, String bio, bool needAgree) { + rpc.send('group-chat-create', [gtype, myName, addr, name, bio, needAgree]); } - reSend(int id) { - // + reSend(int id, String myName) { + rpc.send('group-chat-resend', [id, myName]); } join(String gid, String gaddr, String name, String remark, [String key = '']) { @@ -183,6 +182,26 @@ class GroupChatProvider extends ChangeNotifier { notifyListeners(); } + _agree(List params) { + final id = params[0]; + if (this.requests.containsKey(id)) { + this.requests[id].overIt(false); + } + + final gc = GroupChat.fromList(params[1]); + this.orderKeys.add(gc.id); + this.groups[gc.id] = gc; + notifyListeners(); + } + + _reject(List params) { + final id = params[0]; + if (this.requests.containsKey(id)) { + this.requests[id].overIt(false); + notifyListeners(); + } + } + _memberJoin(List params) { final member = Member.fromList(params); if (this.actived == member.fid) { diff --git a/src/apps/group_chat/layer.rs b/src/apps/group_chat/layer.rs index bb62af6..c14579a 100644 --- a/src/apps/group_chat/layer.rs +++ b/src/apps/group_chat/layer.rs @@ -9,7 +9,7 @@ use tdn::{ }, }; -use group_chat_types::{Event, GroupConnect, GroupResult, JoinProof, LayerEvent}; +use group_chat_types::{Event, GroupConnect, GroupResult, JoinProof, LayerEvent, PackedEvent}; use tdn_did::Proof; use crate::layer::{Layer, Online}; @@ -73,11 +73,12 @@ pub(crate) async fn handle( // 3. online to UI. results.rpcs.push(rpc::group_online(mgid, group.id)); - // 4. TODO online ping. + // 4. online ping. + add_layer(&mut results, mgid, ping(gcd, addr)); - // 5. TODO sync group height. + // 5. sync group height. if group.height < height { - // + add_layer(&mut results, mgid, sync(gcd, addr, group.height)); } } else { let msg = SendType::Result(0, addr, false, false, vec![]); @@ -90,6 +91,7 @@ pub(crate) async fn handle( // TODO waiting } GroupResult::Agree(gcd, info, height) => { + println!("Agree.........."); let base = layer.read().await.base.clone(); let db = group_chat_db(&base, &mgid)?; let (rid, key) = Request::over(&db, &gcd, true)?; @@ -102,10 +104,13 @@ pub(crate) async fn handle( results.rpcs.push(rpc::group_agree(mgid, rid, group)); // 3. online ping. + add_layer(&mut results, mgid, ping(gcd, addr)); // 4. sync group height. + add_layer(&mut results, mgid, sync(gcd, addr, 0)); } GroupResult::Reject(gcd) => { + println!("Reject.........."); let db = group_chat_db(layer.read().await.base(), &mgid)?; let (rid, _key) = Request::over(&db, &gcd, true)?; results.rpcs.push(rpc::group_reject(mgid, rid)); @@ -145,7 +150,11 @@ async fn handle_event( | LayerEvent::OnlinePong(gcd) | LayerEvent::MemberOnline(gcd, ..) | LayerEvent::MemberOffline(gcd, ..) - | LayerEvent::Sync(gcd, ..) => layer.read().await.get_running_remote_id(&mgid, &gcd)?, + | LayerEvent::Sync(gcd, ..) + | LayerEvent::SyncReq(gcd, ..) + | LayerEvent::PackedSync(gcd, ..) => { + layer.read().await.get_running_remote_id(&mgid, &gcd)? + } }; match event { @@ -162,6 +171,12 @@ async fn handle_event( LayerEvent::OnlinePong(_) => { results.rpcs.push(rpc::group_online(mgid, gid)); } + LayerEvent::MemberOnline(_, mid, maddr) => { + results.rpcs.push(rpc::member_online(mgid, gid, mid, maddr)); + } + LayerEvent::MemberOffline(_, mid, ma) => { + results.rpcs.push(rpc::member_offline(mgid, gid, mid, ma)); + } LayerEvent::Sync(_, height, event) => { let base = layer.read().await.base().clone(); let db = group_chat_db(&base, &mgid)?; @@ -200,12 +215,10 @@ async fn handle_event( // save event. GroupChat::add_height(&db, gid, height)?; } - LayerEvent::MemberOnline(_, mid, maddr) => { - results.rpcs.push(rpc::member_online(mgid, gid, mid, maddr)); - } - LayerEvent::MemberOffline(_, mid, ma) => { - results.rpcs.push(rpc::member_offline(mgid, gid, mid, ma)); + LayerEvent::PackedSync(gcd, height, from, to, events) => { + handle_sync(mgid, gcd, addr, height, from, to, events, results); } + LayerEvent::SyncReq(..) => {} // Never here. } Ok(()) @@ -222,3 +235,39 @@ pub(crate) fn group_chat_conn(proof: Proof, addr: PeerAddr, gid: GroupId) -> Sen postcard::to_allocvec(&GroupConnect::Join(gid, JoinProof::Had(proof))).unwrap_or(vec![]); SendType::Connect(0, addr, None, None, data) } + +fn ping(gcd: GroupId, addr: PeerAddr) -> SendType { + let data = postcard::to_allocvec(&LayerEvent::OnlinePing(gcd)).unwrap_or(vec![]); + SendType::Event(0, addr, data) +} + +fn sync(gcd: GroupId, addr: PeerAddr, height: i64) -> SendType { + let data = postcard::to_allocvec(&LayerEvent::SyncReq(gcd, height + 1)).unwrap_or(vec![]); + SendType::Event(0, addr, data) +} + +fn handle_sync( + mgid: GroupId, + gcd: GroupId, + addr: PeerAddr, + height: i64, + mut from: i64, + to: i64, + events: Vec, + results: &mut HandleResult, +) { + for event in events { + handle_sync_event(from, event); + from += 1; + } + + if to < height { + add_layer(results, mgid, sync(gcd, addr, to + 1)); + } + + // update group chat height. +} + +fn handle_sync_event(height: i64, event: PackedEvent) { + // +} diff --git a/src/apps/group_chat/models.rs b/src/apps/group_chat/models.rs index 9ddefe8..5935caf 100644 --- a/src/apps/group_chat/models.rs +++ b/src/apps/group_chat/models.rs @@ -315,6 +315,16 @@ impl GroupChat { Ok(None) } + pub fn get_id(db: &DStorage, id: &i64) -> Result> { + let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE id = {} AND is_deleted = false", id); + let mut matrix = db.query(&sql)?; + if matrix.len() > 0 { + let values = matrix.pop().unwrap(); // safe unwrap() + return Ok(Some(GroupChat::from_values(values, false))); + } + Ok(None) + } + pub fn insert(&mut self, db: &DStorage) -> Result<()> { let sql = format!("INSERT INTO groups (height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime, is_deleted) VALUES ({}, '{}', '{}', {}, '{}', '{}', '{}', {}, {}, {}, {}, '{}', {}, '{}', {}, {}, false)", self.height, diff --git a/src/apps/group_chat/rpc.rs b/src/apps/group_chat/rpc.rs index 29f6e56..92b26ff 100644 --- a/src/apps/group_chat/rpc.rs +++ b/src/apps/group_chat/rpc.rs @@ -162,15 +162,16 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "group-chat-create", |gid: GroupId, params: Vec, state: Arc| async move { - let my_name = params[0].as_str()?.to_owned(); - let addr = PeerAddr::from_hex(params[1].as_str()?)?; - let name = params[2].as_str()?.to_owned(); - let bio = params[3].as_str()?.to_owned(); - let need_agree = params[4].as_bool()?; + let gtype = GroupType::from_u32(params[0].as_i64()? as u32); + let my_name = params[1].as_str()?.to_owned(); + let addr = PeerAddr::from_hex(params[2].as_str()?)?; + let name = params[3].as_str()?.to_owned(); + let bio = params[4].as_str()?.to_owned(); + let need_agree = params[5].as_bool()?; let avatar = vec![]; let db = group_chat_db(state.layer.read().await.base(), &gid)?; - let mut gc = GroupChat::new(gid, GroupType::Common, addr, name, bio, need_agree); + let mut gc = GroupChat::new(gid, gtype, addr, name, bio, need_agree); let _gcd = gc.g_id; // save db @@ -195,6 +196,32 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { }, ); + handler.add_method( + "group-chat-resend", + |gid: GroupId, params: Vec, state: Arc| async move { + let id = params[0].as_i64()?; + let mname = params[1].as_str()?.to_owned(); + + let db = group_chat_db(state.layer.read().await.base(), &gid)?; + let gc = GroupChat::get_id(&db, &id)??; + drop(db); + + // TODO load avatar + let avatar = vec![]; + let addr = gc.g_addr; + let info = gc.to_group_info(mname, avatar); + + // TODO create proof. + let proof: Proof = Default::default(); + + let data = postcard::to_allocvec(&GroupConnect::Create(info, proof)).unwrap_or(vec![]); + let s = SendType::Connect(0, addr, None, None, data); + let mut results = HandleResult::new(); + add_layer(&mut results, gid, s); + Ok(results) + }, + ); + handler.add_method( "group-chat-join", |gid: GroupId, params: Vec, state: Arc| async move {