use actix::Context;
use actix::Handler;
use actix::Message as ActixMessage;
use serde_json::json;
use crate::websocket::webchat::input::Action;
use crate::websocket::webchat::output::Level;
use crate::websocket::webchat::output::OutputMessageType;
use crate::websocket::webchat::server::Server;
use crate::websocket::webchat::services::save_chat_message;
use crate::websocket::webchat::ConnectId;
#[derive(ActixMessage)]
#[rtype(result = "()")]
pub struct SendMessageAction {
pub id: Option<String>, pub connect_id: ConnectId, pub to: String, pub msg: String,
}
impl SendMessageAction {
pub fn parse(
connection_id: &str,
data: &serde_json::Value,
) -> Result<SendMessageAction, String> {
match get_value(data) {
Ok((id, to, msg)) => Ok(SendMessageAction {
id: Some(id),
connect_id: connection_id.to_owned(),
to,
msg,
}),
Err(err) => Err(format!("invalid message: error={}", err)),
}
}
}
impl Handler<SendMessageAction> for Server {
type Result = ();
fn handle(&mut self, msg: SendMessageAction, _ctx: &mut Context<Self>) {
let _connection_id = msg.connect_id;
let _to = msg.to;
let _msg = msg.msg;
if let Some(from_user) = self.user_infos.get(&_connection_id) {
let _from_user_id = from_user.user_id().to_owned();
let _from_user_name = from_user.user_name.to_owned();
let _user_infos = &mut self.user_infos;
let _now = chrono::Utc::now().timestamp_millis();
if _from_user_id == _to {
log::info!(
"SendMessageAction-Ignore: _from={}, _to={}, _msg={}",
_from_user_name,
_to,
_msg
);
return;
}
let _found_connections: Vec<_> = _user_infos
.iter()
.filter(|(_, v)| v.user_id() == _to)
.map(|(k, _)| k)
.collect();
if !_found_connections.is_empty() {
log::info!(
"SendMessageAction-Online: _from={}, _to={}, _msg={}",
_from_user_name,
_to,
_msg
);
} else {
let _mongo = self.ctx.mongo();
match save_chat_message(_mongo, &_from_user_id, &_to, &_msg, _now) {
Ok(_) => {
log::info!(
"SendMessageAction-Offline: _from={}, _to={}, _msg={}",
_from_user_name,
_to,
_msg
);
}
Err(e) => {
log::info!(
"SendMessageAction-Error: _from={}, _to={}, error={}",
_from_user_name,
_to,
e
);
self.send_json(
Level::Err,
OutputMessageType::Failed,
&_connection_id,
json! ({"action": Action::SendMessage, "description": "send message failed, try again later."}),
msg.id,
);
}
}
}
}
}
}
fn get_value(data: &serde_json::Value) -> Result<(String, String, String), String> {
let id = crate::commons::get_value_as_string(data, "id").unwrap_or(None);
let to = crate::commons::get_value_as_string(data, "to").unwrap_or(None);
let msg = crate::commons::get_value_as_string(data, "msg").unwrap_or(None);
if let (Some(_to), Some(_msg)) = (to, msg) {
if _to.len() > 64 {
return Err("`to` invalid".to_string());
}
if _msg.len() > 128 {
return Err("`msg` to long".to_string());
}
Ok((
id.unwrap_or_else(|| uuid::Uuid::now_v7().to_string()),
_to,
_msg,
))
} else {
Err("`to`、`msg` are requried".to_string())
}
}