mirror of https://github.com/CympleTech/ESSE.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
484 lines
16 KiB
484 lines
16 KiB
use std::collections::HashMap; |
|
use std::sync::Arc; |
|
use tdn::types::{ |
|
group::GroupId, |
|
message::SendType, |
|
primitive::{HandleResult, PeerAddr}, |
|
rpc::{json, rpc_response, RpcHandler, RpcParam}, |
|
}; |
|
use tdn_did::user::User; |
|
|
|
use crate::event::InnerEvent; |
|
use crate::migrate::consensus::{FRIEND_TABLE_PATH, MESSAGE_TABLE_PATH, REQUEST_TABLE_PATH}; |
|
use crate::rpc::{sleep_waiting_close_stable, RpcState}; |
|
use crate::storage::{chat_db, delete_avatar}; |
|
|
|
use super::layer::LayerEvent; |
|
use super::{Friend, Message, MessageType, Request}; |
|
|
|
#[inline] |
|
pub(crate) fn friend_online(mgid: GroupId, fid: i64, addr: PeerAddr) -> RpcParam { |
|
rpc_response(0, "chat-friend-online", json!([fid, addr.to_hex()]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn friend_offline(mgid: GroupId, fid: i64, gid: &GroupId) -> RpcParam { |
|
rpc_response(0, "chat-friend-offline", json!([fid, gid.to_hex()]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn friend_info(mgid: GroupId, friend: &Friend) -> RpcParam { |
|
rpc_response(0, "chat-friend-info", json!(friend.to_rpc()), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn friend_update(mgid: GroupId, fid: i64, remark: &str) -> RpcParam { |
|
rpc_response(0, "chat-friend-update", json!([fid, remark]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn friend_close(mgid: GroupId, fid: i64) -> RpcParam { |
|
rpc_response(0, "chat-friend-close", json!([fid]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn friend_delete(mgid: GroupId, fid: i64) -> RpcParam { |
|
rpc_response(0, "chat-friend-delete", json!([fid]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn request_create(mgid: GroupId, req: &Request) -> RpcParam { |
|
rpc_response(0, "chat-request-create", json!(req.to_rpc()), mgid) |
|
} |
|
|
|
#[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) |
|
} |
|
|
|
#[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) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn request_reject(mgid: GroupId, id: i64) -> RpcParam { |
|
rpc_response(0, "chat-request-reject", json!([id]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn request_delete(mgid: GroupId, id: i64) -> RpcParam { |
|
rpc_response(0, "chat-request-delete", json!([id]), mgid) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn message_create(mgid: GroupId, msg: &Message) -> RpcParam { |
|
rpc_response(0, "chat-message-create", json!(msg.to_rpc()), mgid) |
|
} |
|
|
|
#[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) |
|
} |
|
|
|
#[inline] |
|
pub(crate) fn message_delete(mgid: GroupId, id: i64) -> RpcParam { |
|
rpc_response(0, "chat-message-delete", json!([id]), mgid) |
|
} |
|
|
|
#[inline] |
|
fn friend_list(friends: Vec<Friend>) -> RpcParam { |
|
let mut results = vec![]; |
|
for friend in friends { |
|
results.push(friend.to_rpc()); |
|
} |
|
|
|
json!(results) |
|
} |
|
|
|
#[inline] |
|
fn request_list(requests: Vec<Request>) -> RpcParam { |
|
let mut results = vec![]; |
|
for request in requests { |
|
results.push(request.to_rpc()); |
|
} |
|
json!(results) |
|
} |
|
|
|
#[inline] |
|
fn message_list(messages: Vec<Message>) -> RpcParam { |
|
let mut results = vec![]; |
|
for msg in messages { |
|
results.push(msg.to_rpc()); |
|
} |
|
json!(results) |
|
} |
|
|
|
pub(crate) fn new_rpc_handler(handler: &mut RpcHandler<RpcState>) { |
|
handler.add_method("chat-echo", |_, params, _| async move { |
|
Ok(HandleResult::rpc(json!(params))) |
|
}); |
|
|
|
handler.add_method( |
|
"chat-friend-list", |
|
|gid: GroupId, _params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let layer_lock = state.layer.read().await; |
|
let db = chat_db(&layer_lock.base, &gid)?; |
|
let mut friends = Friend::all(&db)?; |
|
drop(db); |
|
|
|
Ok(HandleResult::rpc(friend_list(friends))) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-friend-update", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
let remark = params[1].as_str()?; |
|
|
|
let mut results = HandleResult::new(); |
|
let db = chat_db(state.layer.read().await.base(), &gid)?; |
|
let f = if let Some(mut f) = Friend::get_id(&db, id)? { |
|
f.remark = remark.to_owned(); |
|
f.me_update(&db)?; |
|
f |
|
} else { |
|
return Ok(results); |
|
}; |
|
drop(db); |
|
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<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let mut results = HandleResult::new(); |
|
let mut layer_lock = state.layer.write().await; |
|
|
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
let friend = Friend::get_id(&db, id)??; |
|
friend.close(&db)?; |
|
drop(db); |
|
|
|
let online = layer_lock.remove_online(&gid, &friend.gid); |
|
drop(layer_lock); |
|
|
|
if let Some(faddr) = online { |
|
let mut addrs: HashMap<PeerAddr, GroupId> = HashMap::new(); |
|
addrs.insert(faddr, friend.gid); |
|
let sender = state.group.read().await.sender(); |
|
tdn::smol::spawn(sleep_waiting_close_stable(sender, HashMap::new(), addrs)) |
|
.detach(); |
|
} |
|
|
|
let data = postcard::to_allocvec(&LayerEvent::Close).unwrap_or(vec![]); |
|
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, |
|
)?; |
|
|
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-friend-delete", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let mut results = HandleResult::new(); |
|
let mut layer_lock = state.layer.write().await; |
|
|
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
let friend = Friend::get_id(&db, id)??; |
|
friend.delete(&db)?; |
|
drop(db); |
|
|
|
let online = layer_lock.remove_online(&gid, &friend.gid); |
|
delete_avatar(layer_lock.base(), &gid, &friend.gid).await?; |
|
drop(layer_lock); |
|
|
|
if let Some(faddr) = online { |
|
let mut addrs: HashMap<PeerAddr, GroupId> = HashMap::new(); |
|
addrs.insert(faddr, friend.gid); |
|
let sender = state.group.read().await.sender(); |
|
tdn::smol::spawn(sleep_waiting_close_stable(sender, HashMap::new(), addrs)) |
|
.detach(); |
|
} |
|
|
|
let data = postcard::to_allocvec(&LayerEvent::Close).unwrap_or(vec![]); |
|
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, |
|
)?; |
|
|
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-request-list", |
|
|gid: GroupId, _params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let layer_lock = state.layer.read().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
drop(layer_lock); |
|
let requests = Request::all(&db)?; |
|
drop(db); |
|
Ok(HandleResult::rpc(request_list(requests))) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-request-create", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let remote_gid = GroupId::from_hex(params[0].as_str()?)?; |
|
let remote_addr = PeerAddr::from_hex(params[1].as_str()?)?; |
|
let remote_name = params[2].as_str()?.to_string(); |
|
let remark = params[3].as_str()?.to_string(); |
|
|
|
let mut request = Request::new( |
|
remote_gid, |
|
remote_addr, |
|
remote_name.clone(), |
|
remark.clone(), |
|
true, |
|
false, |
|
); |
|
|
|
let me = state.group.read().await.clone_user(&gid)?; |
|
|
|
let mut layer_lock = state.layer.write().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
if Friend::is_friend(&db, &request.gid)? { |
|
debug!("had friend."); |
|
drop(layer_lock); |
|
return Ok(HandleResult::new()); |
|
} |
|
|
|
if let Some(req) = Request::get(&db, &request.gid)? { |
|
debug!("Had this request."); |
|
req.delete(&db)?; |
|
} |
|
request.insert(&db)?; |
|
drop(db); |
|
|
|
let mut results = HandleResult::rpc(json!(request.to_rpc())); |
|
|
|
state.group.write().await.broadcast( |
|
&gid, |
|
InnerEvent::SessionRequestCreate( |
|
true, |
|
User::new(remote_gid, remote_addr, remote_name, vec![])?, |
|
remark, |
|
), |
|
REQUEST_TABLE_PATH, |
|
request.id, |
|
&mut results, |
|
)?; |
|
|
|
results.layers.push(( |
|
gid, |
|
remote_gid, |
|
super::layer::req_message(&mut layer_lock, me, request), |
|
)); |
|
|
|
drop(layer_lock); |
|
|
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-request-agree", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let mut group_lock = state.group.write().await; |
|
let me = group_lock.clone_user(&gid)?; |
|
let mut layer_lock = state.layer.write().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
let mut results = HandleResult::new(); |
|
|
|
if let Some(mut request) = Request::get_id(&db, id)? { |
|
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 f = Friend::from_request(&db, request)?; |
|
results.rpcs.push(json!([id, f.to_rpc()])); |
|
|
|
let proof = group_lock.prove_addr(&gid, &f.addr)?; |
|
let msg = |
|
super::layer::rpc_agree_message(&mut layer_lock, id, proof, me, &gid, f.addr)?; |
|
results.layers.push((gid, f.gid, msg)); |
|
} |
|
db.close()?; |
|
drop(group_lock); |
|
drop(layer_lock); |
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-request-reject", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let mut layer_lock = state.layer.write().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
let mut req = Request::get_id(&db, id)??; |
|
req.is_ok = false; |
|
req.is_over = true; |
|
req.update(&db)?; |
|
drop(db); |
|
let msg = super::layer::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, |
|
)?; |
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-request-delete", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let layer_lock = state.layer.read().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
let base = layer_lock.base().clone(); |
|
drop(layer_lock); |
|
let req = Request::get_id(&db, id)??; |
|
req.delete(&db)?; |
|
|
|
// delete avatar. check had friend. |
|
if Friend::get(&db, &req.gid)?.is_none() { |
|
delete_avatar(&base, &gid, &req.gid).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, |
|
)?; |
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-message-list", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let fid = params[0].as_i64()?; |
|
|
|
let layer_lock = state.layer.read().await; |
|
let db = chat_db(layer_lock.base(), &gid)?; |
|
drop(layer_lock); |
|
|
|
let messages = Message::get(&db, &fid)?; |
|
drop(db); |
|
Ok(HandleResult::rpc(message_list(messages))) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-message-create", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let fid = params[0].as_i64()?; |
|
let fgid = GroupId::from_hex(params[1].as_str()?)?; |
|
let m_type = MessageType::from_int(params[2].as_i64()?); |
|
let content = params[3].as_str()?.to_string(); |
|
|
|
let mut layer_lock = state.layer.write().await; |
|
let base = layer_lock.base(); |
|
let faddr = layer_lock.running(&gid)?.online(&fgid)?; |
|
|
|
let (msg, nw) = LayerEvent::from_message(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 mut results = HandleResult::rpc(json!(msg.to_rpc())); |
|
results.layers.push((gid, fgid, s)); |
|
|
|
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, |
|
)?; |
|
} |
|
_ => {} |
|
} |
|
|
|
Ok(results) |
|
}, |
|
); |
|
|
|
handler.add_method( |
|
"chat-message-delete", |
|
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move { |
|
let id = params[0].as_i64()?; |
|
|
|
let layer_lock = state.layer.read().await; |
|
let db = chat_db(&layer_lock.base(), &gid)?; |
|
drop(layer_lock); |
|
|
|
let msg = Message::get_id(&db, id)??; |
|
msg.delete(&db)?; |
|
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) |
|
}, |
|
); |
|
}
|
|
|