From 0608138c4b3281fc8be001ff3700bad7b61474a8 Mon Sep 17 00:00:00 2001 From: Sun Date: Mon, 17 May 2021 18:43:39 +0800 Subject: [PATCH] handle member join --- lib/apps/group_chat/models.dart | 5 +++ lib/apps/group_chat/provider.dart | 6 ++- lib/l10n/localizations.dart | 1 + lib/l10n/localizations_en.dart | 2 + lib/l10n/localizations_zh.dart | 2 + src/apps/group_chat/layer.rs | 44 ++++++++++------------ src/apps/group_chat/models.rs | 62 +++++++++++++++++++++---------- src/apps/group_chat/rpc.rs | 10 ++++- src/migrate/group_chat.rs | 1 + 9 files changed, 87 insertions(+), 46 deletions(-) diff --git a/lib/apps/group_chat/models.dart b/lib/apps/group_chat/models.dart index 7710560..0c13c08 100644 --- a/lib/apps/group_chat/models.dart +++ b/lib/apps/group_chat/models.dart @@ -16,6 +16,7 @@ enum GroupType { enum CheckType { Allow, None, + Suspend, Deny, Wait, } @@ -55,6 +56,8 @@ extension CheckTypeExtension on CheckType { return [lang.groupCheckTypeAllow, true]; case CheckType.None: return [lang.groupCheckTypeNone, false]; + case CheckType.Suspend: + return [lang.groupCheckTypeSuspend, false]; case CheckType.Deny: return [lang.groupCheckTypeDeny, false]; default: @@ -69,6 +72,8 @@ extension CheckTypeExtension on CheckType { case 1: return CheckType.None; case 2: + return CheckType.Suspend; + case 3: return CheckType.Deny; default: return CheckType.Deny; diff --git a/lib/apps/group_chat/provider.dart b/lib/apps/group_chat/provider.dart index 6e0e8c6..901d70e 100644 --- a/lib/apps/group_chat/provider.dart +++ b/lib/apps/group_chat/provider.dart @@ -45,7 +45,7 @@ class GroupChatProvider extends ChangeNotifier { // rpc.addListener('group-chat-join', _join, true); // rpc.addListener('group-chat-agree', _agree, true); // rpc.addListener('group-chat-reject', _reject, false); - // rpc.addListener('group-chat-member-join', _memberJoin, 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); rpc.addListener('group-chat-member-online', _memberOnline, false); @@ -173,6 +173,10 @@ class GroupChatProvider extends ChangeNotifier { } } + _memberJoin(List params) { + // + } + _memberOnline(List params) { // } diff --git a/lib/l10n/localizations.dart b/lib/l10n/localizations.dart index 50ca8d6..5f7f9c6 100644 --- a/lib/l10n/localizations.dart +++ b/lib/l10n/localizations.dart @@ -165,6 +165,7 @@ abstract class AppLocalizations { String get groupChatBio; String get groupCheckTypeAllow; String get groupCheckTypeNone; + String get groupCheckTypeSuspend; String get groupCheckTypeDeny; String get members; } diff --git a/lib/l10n/localizations_en.dart b/lib/l10n/localizations_en.dart index 8cb4411..1745ad8 100644 --- a/lib/l10n/localizations_en.dart +++ b/lib/l10n/localizations_en.dart @@ -241,6 +241,8 @@ class AppLocalizationsEn extends AppLocalizations { @override String get groupCheckTypeNone => 'Restricted, the allowed number is full'; @override + String get groupCheckTypeSuspend => 'Account is suspended'; + @override String get groupCheckTypeDeny => 'No permission to create here'; @override String get members => 'Members'; diff --git a/lib/l10n/localizations_zh.dart b/lib/l10n/localizations_zh.dart index aac573d..b7fb008 100644 --- a/lib/l10n/localizations_zh.dart +++ b/lib/l10n/localizations_zh.dart @@ -241,6 +241,8 @@ class AppLocalizationsZh extends AppLocalizations { @override String get groupCheckTypeNone => '创建被限制,允许数目已满'; @override + String get groupCheckTypeSuspend => '账户被暂停使用'; + @override String get groupCheckTypeDeny => '没有权限在此创建群聊'; @override String get members => '成员'; diff --git a/src/apps/group_chat/layer.rs b/src/apps/group_chat/layer.rs index feb90e4..9aa80e2 100644 --- a/src/apps/group_chat/layer.rs +++ b/src/apps/group_chat/layer.rs @@ -9,13 +9,13 @@ use tdn::{ }, }; -use group_chat_types::{Event, GroupConnect, GroupResult, JoinProof, LayerEvent, NetworkMessage}; +use group_chat_types::{Event, GroupConnect, GroupResult, JoinProof, LayerEvent}; use tdn_did::Proof; use crate::layer::{Layer, Online}; use crate::storage::group_chat_db; -use super::models::{from_network_message, GroupChat}; +use super::models::{from_network_message, GroupChat, Member}; use super::{add_layer, rpc}; pub(crate) async fn handle( @@ -27,9 +27,7 @@ pub(crate) async fn handle( match msg { RecvType::Connect(..) => {} // Never to here. - RecvType::Leave(_addr) => { - // - } + RecvType::Leave(..) => {} // Never to here. handled in chat. RecvType::Result(addr, _is_ok, data) => { let res: GroupResult = postcard::from_bytes(&data) .map_err(|_e| new_io_error("Deseralize result failure"))?; @@ -76,11 +74,7 @@ pub(crate) async fn handle( results.rpcs.push(rpc::group_online(mgid, group.id)); // 5. sync group height. - let db = group_chat_db(&base, &mgid)?; - let my_height = GroupChat::get_height(&db, &group.id)?; - drop(db); - - if my_height < height { + if group.height < height { // TOOD } } else { @@ -153,23 +147,25 @@ async fn handle_event( } LayerEvent::Sync(_, height, event) => { match event { - Event::Message(mid, nmsg) => { + Event::GroupInfo => {} + Event::GroupTransfer => {} + Event::GroupManagerAdd => {} + Event::GroupManagerDel => {} + Event::GroupClose => {} + Event::MemberInfo(mid, maddr, mname, mavatar) => {} + Event::MemberJoin(mid, maddr, mname, mavatar, mtime) => { + let db = group_chat_db(layer.read().await.base(), &mgid)?; + let mut member = Member::new(gid, mid, maddr, mname, false, mtime); + member.insert(&db)?; + results.rpcs.push(rpc::member_join(mgid, member)); + } + Event::MemberLeave(mid) => {} + Event::MessageCreate(mid, nmsg, mtime) => { let base = layer.read().await.base.clone(); - let msg = from_network_message(height as i64, gid, mid, mgid, nmsg, base)?; + let msg = + from_network_message(height as i64, gid, mid, mgid, nmsg, mtime, base)?; results.rpcs.push(rpc::message_create(mgid, msg)); } - Event::GroupUpdate => { - // - } - Event::GroupTransfer => { - // - } - Event::UserInfo => { - // - } - Event::Close => { - // - } } // save event. diff --git a/src/apps/group_chat/models.rs b/src/apps/group_chat/models.rs index 9dc6232..3039402 100644 --- a/src/apps/group_chat/models.rs +++ b/src/apps/group_chat/models.rs @@ -57,6 +57,8 @@ impl GroupChatKey { pub(crate) struct GroupChat { /// db auto-increment id. pub id: i64, + /// consensus height. + pub height: i64, /// group chat owner. pub owner: GroupId, /// group chat id. @@ -123,6 +125,7 @@ impl GroupChat { key, datetime, id: 0, + height: 0, is_top: true, is_ok: false, is_closed: false, @@ -206,13 +209,14 @@ impl GroupChat { g_type: GroupType::from_u32(v.pop().unwrap().as_i64() as u32), g_id: GroupId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), owner: GroupId::from_hex(v.pop().unwrap().as_string()).unwrap_or(Default::default()), + height: v.pop().unwrap().as_i64(), id: v.pop().unwrap().as_i64(), } } /// use in rpc when load account friends. pub fn all(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_deleted = false ORDER BY last_datetime DESC")?; + let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_deleted = false ORDER BY last_datetime DESC")?; let mut groups = vec![]; for values in matrix { groups.push(GroupChat::from_values(values, false)); @@ -222,7 +226,7 @@ impl GroupChat { /// use in rpc when load account groups. pub fn all_ok(db: &DStorage) -> Result> { - let matrix = db.query("SELECT id, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_closed = false ORDER BY last_datetime DESC")?; + let matrix = db.query("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE is_closed = false ORDER BY last_datetime DESC")?; let mut groups = vec![]; for values in matrix { groups.push(GroupChat::from_values(values, false)); @@ -231,7 +235,7 @@ impl GroupChat { } pub fn get(db: &DStorage, gid: &GroupId) -> Result> { - let sql = format!("SELECT id, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE gcd = '{}' AND is_deleted = false", gid.to_hex()); + let sql = format!("SELECT id, height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime FROM groups WHERE gcd = '{}' AND is_deleted = false", gid.to_hex()); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { let values = matrix.pop().unwrap(); // safe unwrap() @@ -240,13 +244,9 @@ impl GroupChat { Ok(None) } - pub fn get_height(db: &DStorage, id: &i64) -> Result { - // TODO - Ok(0) - } - pub fn insert(&mut self, db: &DStorage) -> Result<()> { - let sql = format!("INSERT INTO groups (owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime, is_deleted) VALUES ('{}', '{}', {}, '{}', '{}', '{}', {}, {}, {}, {}, '{}', {}, '{}', {}, {}, false)", + let sql = format!("INSERT INTO groups (height, owner, gcd, gtype, addr, name, bio, is_top, is_ok, is_need_agree, is_closed, key, last_datetime, last_content, last_readed, datetime, is_deleted) VALUES ({}, '{}', '{}', {}, '{}', '{}', '{}', {}, {}, {}, {}, '{}', {}, '{}', {}, {}, false)", + self.height, self.owner.to_hex(), self.g_id.to_hex(), self.g_type.to_u32(), @@ -263,7 +263,6 @@ impl GroupChat { if self.last_readed { 1 } else { 0 }, self.datetime, ); - println!("{}", sql); let id = db.insert(&sql)?; self.id = id; Ok(()) @@ -293,7 +292,7 @@ impl GroupChat { } /// Group Member Model. -pub(super) struct Member { +pub(crate) struct Member { /// db auto-increment id. id: i64, /// group's db id. @@ -426,20 +425,15 @@ pub(crate) struct Message { } impl Message { - pub(crate) fn new( + pub(crate) fn new_with_time( height: i64, fid: i64, mid: i64, is_me: bool, m_type: MessageType, content: String, + datetime: i64, ) -> Message { - let start = SystemTime::now(); - let datetime = start - .duration_since(UNIX_EPOCH) - .map(|s| s.as_secs()) - .unwrap_or(0) as i64; // safe for all life. - Self { fid, mid, @@ -453,6 +447,22 @@ impl Message { id: 0, } } + pub(crate) fn new( + height: i64, + fid: i64, + mid: i64, + is_me: bool, + m_type: MessageType, + content: String, + ) -> Message { + let start = SystemTime::now(); + let datetime = start + .duration_since(UNIX_EPOCH) + .map(|s| s.as_secs()) + .unwrap_or(0) as i64; // safe for all life. + + Self::new_with_time(height, fid, mid, is_me, m_type, content, datetime) + } /// here is zero-copy and unwrap is safe. checked. fn from_values(mut v: Vec, contains_deleted: bool) -> Message { let is_deleted = if contains_deleted { @@ -515,12 +525,26 @@ impl Message { } } +pub(super) fn to_network_message( + mtype: MessageType, + content: &str, +) -> Result<(NetworkMessage, i64)> { + let start = SystemTime::now(); + let datetime = start + .duration_since(UNIX_EPOCH) + .map(|s| s.as_secs()) + .unwrap_or(0) as i64; // safe for all life. + + Ok((NetworkMessage::String(content.to_owned()), datetime)) +} + pub(super) fn from_network_message( height: i64, gdid: i64, mid: GroupId, mgid: GroupId, msg: NetworkMessage, + datetime: i64, base: PathBuf, ) -> Result { let db = group_chat_db(&base, &mgid)?; @@ -572,7 +596,7 @@ pub(super) fn from_network_message( } }; - let mut msg = Message::new(height, gdid, mdid, is_me, m_type, raw); + let mut msg = Message::new_with_time(height, gdid, mdid, is_me, m_type, raw, datetime); msg.insert(&db)?; GroupChat::update_last_message(&db, gdid, &msg, false)?; Ok(msg) diff --git a/src/apps/group_chat/rpc.rs b/src/apps/group_chat/rpc.rs index 3bd50b2..1943079 100644 --- a/src/apps/group_chat/rpc.rs +++ b/src/apps/group_chat/rpc.rs @@ -14,7 +14,7 @@ use crate::rpc::RpcState; use crate::storage::group_chat_db; use super::add_layer; -use super::models::{GroupChat, Member, Message}; +use super::models::{to_network_message, GroupChat, Member, Message}; #[inline] pub(crate) fn create_check(mgid: GroupId, ct: CheckType, supported: Vec) -> RpcParam { @@ -37,6 +37,11 @@ pub(crate) fn group_offline(mgid: GroupId, fid: i64, gid: &GroupId) -> RpcParam rpc_response(0, "group-chat-offline", json!([fid, gid.to_hex()]), mgid) } +#[inline] +pub(crate) fn member_join(mgid: GroupId, member: Member) -> RpcParam { + rpc_response(0, "group-chat-member-join", json!(member.to_rpc()), mgid) +} + #[inline] pub(crate) fn member_online(mgid: GroupId, gid: i64, mid: GroupId, maddr: PeerAddr) -> RpcParam { rpc_response( @@ -183,7 +188,8 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { let addr = state.layer.read().await.running(&gid)?.online(&gcd)?; let mut results = HandleResult::new(); - let event = Event::Message(gid, NetworkMessage::String(m_content.to_owned())); + let (nmsg, datetime) = to_network_message(m_type, m_content)?; + let event = Event::MessageCreate(gid, nmsg, datetime); let data = postcard::to_allocvec(&LayerEvent::Sync(gcd, 0, event)).unwrap_or(vec![]); let msg = SendType::Event(0, addr, data); add_layer(&mut results, gid, msg); diff --git a/src/migrate/group_chat.rs b/src/migrate/group_chat.rs index 910857c..d105e81 100644 --- a/src/migrate/group_chat.rs +++ b/src/migrate/group_chat.rs @@ -2,6 +2,7 @@ pub(super) const GROUP_CHAT_VERSIONS: [&str; 4] = [ "CREATE TABLE IF NOT EXISTS groups( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + height INTEGER NOT NULL, owner TEXT NOT NULL, gcd TEXT NOT NULL, gtype INTEGER NOT NULL,