Browse Source

handle member join

pull/18/head
Sun 4 years ago
parent
commit
0608138c4b
  1. 5
      lib/apps/group_chat/models.dart
  2. 6
      lib/apps/group_chat/provider.dart
  3. 1
      lib/l10n/localizations.dart
  4. 2
      lib/l10n/localizations_en.dart
  5. 2
      lib/l10n/localizations_zh.dart
  6. 44
      src/apps/group_chat/layer.rs
  7. 62
      src/apps/group_chat/models.rs
  8. 10
      src/apps/group_chat/rpc.rs
  9. 1
      src/migrate/group_chat.rs

5
lib/apps/group_chat/models.dart

@ -16,6 +16,7 @@ enum GroupType {
enum CheckType { enum CheckType {
Allow, Allow,
None, None,
Suspend,
Deny, Deny,
Wait, Wait,
} }
@ -55,6 +56,8 @@ extension CheckTypeExtension on CheckType {
return [lang.groupCheckTypeAllow, true]; return [lang.groupCheckTypeAllow, true];
case CheckType.None: case CheckType.None:
return [lang.groupCheckTypeNone, false]; return [lang.groupCheckTypeNone, false];
case CheckType.Suspend:
return [lang.groupCheckTypeSuspend, false];
case CheckType.Deny: case CheckType.Deny:
return [lang.groupCheckTypeDeny, false]; return [lang.groupCheckTypeDeny, false];
default: default:
@ -69,6 +72,8 @@ extension CheckTypeExtension on CheckType {
case 1: case 1:
return CheckType.None; return CheckType.None;
case 2: case 2:
return CheckType.Suspend;
case 3:
return CheckType.Deny; return CheckType.Deny;
default: default:
return CheckType.Deny; return CheckType.Deny;

6
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-join', _join, true);
// rpc.addListener('group-chat-agree', _agree, true); // rpc.addListener('group-chat-agree', _agree, true);
// rpc.addListener('group-chat-reject', _reject, false); // 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-info', _memberInfo, false);
// rpc.addListener('group-chat-member-leave', _memberLeave, false); // rpc.addListener('group-chat-member-leave', _memberLeave, false);
rpc.addListener('group-chat-member-online', _memberOnline, false); rpc.addListener('group-chat-member-online', _memberOnline, false);
@ -173,6 +173,10 @@ class GroupChatProvider extends ChangeNotifier {
} }
} }
_memberJoin(List params) {
//
}
_memberOnline(List params) { _memberOnline(List params) {
// //
} }

1
lib/l10n/localizations.dart

@ -165,6 +165,7 @@ abstract class AppLocalizations {
String get groupChatBio; String get groupChatBio;
String get groupCheckTypeAllow; String get groupCheckTypeAllow;
String get groupCheckTypeNone; String get groupCheckTypeNone;
String get groupCheckTypeSuspend;
String get groupCheckTypeDeny; String get groupCheckTypeDeny;
String get members; String get members;
} }

2
lib/l10n/localizations_en.dart

@ -241,6 +241,8 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get groupCheckTypeNone => 'Restricted, the allowed number is full'; String get groupCheckTypeNone => 'Restricted, the allowed number is full';
@override @override
String get groupCheckTypeSuspend => 'Account is suspended';
@override
String get groupCheckTypeDeny => 'No permission to create here'; String get groupCheckTypeDeny => 'No permission to create here';
@override @override
String get members => 'Members'; String get members => 'Members';

2
lib/l10n/localizations_zh.dart

@ -241,6 +241,8 @@ class AppLocalizationsZh extends AppLocalizations {
@override @override
String get groupCheckTypeNone => '创建被限制,允许数目已满'; String get groupCheckTypeNone => '创建被限制,允许数目已满';
@override @override
String get groupCheckTypeSuspend => '账户被暂停使用';
@override
String get groupCheckTypeDeny => '没有权限在此创建群聊'; String get groupCheckTypeDeny => '没有权限在此创建群聊';
@override @override
String get members => '成员'; String get members => '成员';

44
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 tdn_did::Proof;
use crate::layer::{Layer, Online}; use crate::layer::{Layer, Online};
use crate::storage::group_chat_db; 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}; use super::{add_layer, rpc};
pub(crate) async fn handle( pub(crate) async fn handle(
@ -27,9 +27,7 @@ pub(crate) async fn handle(
match msg { match msg {
RecvType::Connect(..) => {} // Never to here. RecvType::Connect(..) => {} // Never to here.
RecvType::Leave(_addr) => { RecvType::Leave(..) => {} // Never to here. handled in chat.
//
}
RecvType::Result(addr, _is_ok, data) => { RecvType::Result(addr, _is_ok, data) => {
let res: GroupResult = postcard::from_bytes(&data) let res: GroupResult = postcard::from_bytes(&data)
.map_err(|_e| new_io_error("Deseralize result failure"))?; .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)); results.rpcs.push(rpc::group_online(mgid, group.id));
// 5. sync group height. // 5. sync group height.
let db = group_chat_db(&base, &mgid)?; if group.height < height {
let my_height = GroupChat::get_height(&db, &group.id)?;
drop(db);
if my_height < height {
// TOOD // TOOD
} }
} else { } else {
@ -153,23 +147,25 @@ async fn handle_event(
} }
LayerEvent::Sync(_, height, event) => { LayerEvent::Sync(_, height, event) => {
match 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 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)); results.rpcs.push(rpc::message_create(mgid, msg));
} }
Event::GroupUpdate => {
//
}
Event::GroupTransfer => {
//
}
Event::UserInfo => {
//
}
Event::Close => {
//
}
} }
// save event. // save event.

62
src/apps/group_chat/models.rs

@ -57,6 +57,8 @@ impl GroupChatKey {
pub(crate) struct GroupChat { pub(crate) struct GroupChat {
/// db auto-increment id. /// db auto-increment id.
pub id: i64, pub id: i64,
/// consensus height.
pub height: i64,
/// group chat owner. /// group chat owner.
pub owner: GroupId, pub owner: GroupId,
/// group chat id. /// group chat id.
@ -123,6 +125,7 @@ impl GroupChat {
key, key,
datetime, datetime,
id: 0, id: 0,
height: 0,
is_top: true, is_top: true,
is_ok: false, is_ok: false,
is_closed: false, is_closed: false,
@ -206,13 +209,14 @@ impl GroupChat {
g_type: GroupType::from_u32(v.pop().unwrap().as_i64() as u32), 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()), 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()), 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(), id: v.pop().unwrap().as_i64(),
} }
} }
/// use in rpc when load account friends. /// use in rpc when load account friends.
pub fn all(db: &DStorage) -> Result<Vec<GroupChat>> { pub fn all(db: &DStorage) -> Result<Vec<GroupChat>> {
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![]; let mut groups = vec![];
for values in matrix { for values in matrix {
groups.push(GroupChat::from_values(values, false)); groups.push(GroupChat::from_values(values, false));
@ -222,7 +226,7 @@ impl GroupChat {
/// use in rpc when load account groups. /// use in rpc when load account groups.
pub fn all_ok(db: &DStorage) -> Result<Vec<GroupChat>> { pub fn all_ok(db: &DStorage) -> Result<Vec<GroupChat>> {
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![]; let mut groups = vec![];
for values in matrix { for values in matrix {
groups.push(GroupChat::from_values(values, false)); groups.push(GroupChat::from_values(values, false));
@ -231,7 +235,7 @@ impl GroupChat {
} }
pub fn get(db: &DStorage, gid: &GroupId) -> Result<Option<GroupChat>> { pub fn get(db: &DStorage, gid: &GroupId) -> Result<Option<GroupChat>> {
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)?; let mut matrix = db.query(&sql)?;
if matrix.len() > 0 { if matrix.len() > 0 {
let values = matrix.pop().unwrap(); // safe unwrap() let values = matrix.pop().unwrap(); // safe unwrap()
@ -240,13 +244,9 @@ impl GroupChat {
Ok(None) Ok(None)
} }
pub fn get_height(db: &DStorage, id: &i64) -> Result<u64> {
// TODO
Ok(0)
}
pub fn insert(&mut self, db: &DStorage) -> Result<()> { 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.owner.to_hex(),
self.g_id.to_hex(), self.g_id.to_hex(),
self.g_type.to_u32(), self.g_type.to_u32(),
@ -263,7 +263,6 @@ impl GroupChat {
if self.last_readed { 1 } else { 0 }, if self.last_readed { 1 } else { 0 },
self.datetime, self.datetime,
); );
println!("{}", sql);
let id = db.insert(&sql)?; let id = db.insert(&sql)?;
self.id = id; self.id = id;
Ok(()) Ok(())
@ -293,7 +292,7 @@ impl GroupChat {
} }
/// Group Member Model. /// Group Member Model.
pub(super) struct Member { pub(crate) struct Member {
/// db auto-increment id. /// db auto-increment id.
id: i64, id: i64,
/// group's db id. /// group's db id.
@ -426,20 +425,15 @@ pub(crate) struct Message {
} }
impl Message { impl Message {
pub(crate) fn new( pub(crate) fn new_with_time(
height: i64, height: i64,
fid: i64, fid: i64,
mid: i64, mid: i64,
is_me: bool, is_me: bool,
m_type: MessageType, m_type: MessageType,
content: String, content: String,
datetime: i64,
) -> Message { ) -> 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 { Self {
fid, fid,
mid, mid,
@ -453,6 +447,22 @@ impl Message {
id: 0, 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. /// here is zero-copy and unwrap is safe. checked.
fn from_values(mut v: Vec<DsValue>, contains_deleted: bool) -> Message { fn from_values(mut v: Vec<DsValue>, contains_deleted: bool) -> Message {
let is_deleted = if contains_deleted { 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( pub(super) fn from_network_message(
height: i64, height: i64,
gdid: i64, gdid: i64,
mid: GroupId, mid: GroupId,
mgid: GroupId, mgid: GroupId,
msg: NetworkMessage, msg: NetworkMessage,
datetime: i64,
base: PathBuf, base: PathBuf,
) -> Result<Message> { ) -> Result<Message> {
let db = group_chat_db(&base, &mgid)?; 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)?; msg.insert(&db)?;
GroupChat::update_last_message(&db, gdid, &msg, false)?; GroupChat::update_last_message(&db, gdid, &msg, false)?;
Ok(msg) Ok(msg)

10
src/apps/group_chat/rpc.rs

@ -14,7 +14,7 @@ use crate::rpc::RpcState;
use crate::storage::group_chat_db; use crate::storage::group_chat_db;
use super::add_layer; use super::add_layer;
use super::models::{GroupChat, Member, Message}; use super::models::{to_network_message, GroupChat, Member, Message};
#[inline] #[inline]
pub(crate) fn create_check(mgid: GroupId, ct: CheckType, supported: Vec<GroupType>) -> RpcParam { pub(crate) fn create_check(mgid: GroupId, ct: CheckType, supported: Vec<GroupType>) -> 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) 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] #[inline]
pub(crate) fn member_online(mgid: GroupId, gid: i64, mid: GroupId, maddr: PeerAddr) -> RpcParam { pub(crate) fn member_online(mgid: GroupId, gid: i64, mid: GroupId, maddr: PeerAddr) -> RpcParam {
rpc_response( rpc_response(
@ -183,7 +188,8 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) {
let addr = state.layer.read().await.running(&gid)?.online(&gcd)?; let addr = state.layer.read().await.running(&gid)?.online(&gcd)?;
let mut results = HandleResult::new(); 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 data = postcard::to_allocvec(&LayerEvent::Sync(gcd, 0, event)).unwrap_or(vec![]);
let msg = SendType::Event(0, addr, data); let msg = SendType::Event(0, addr, data);
add_layer(&mut results, gid, msg); add_layer(&mut results, gid, msg);

1
src/migrate/group_chat.rs

@ -2,6 +2,7 @@
pub(super) const GROUP_CHAT_VERSIONS: [&str; 4] = [ pub(super) const GROUP_CHAT_VERSIONS: [&str; 4] = [
"CREATE TABLE IF NOT EXISTS groups( "CREATE TABLE IF NOT EXISTS groups(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
height INTEGER NOT NULL,
owner TEXT NOT NULL, owner TEXT NOT NULL,
gcd TEXT NOT NULL, gcd TEXT NOT NULL,
gtype INTEGER NOT NULL, gtype INTEGER NOT NULL,

Loading…
Cancel
Save