[FIX] Migrated to Tensamin Transport Protocol
This commit is contained in:
parent
d4a1b6922b
commit
c9d21fd3c6
24 changed files with 1451 additions and 2252 deletions
|
|
@ -1,27 +1,24 @@
|
|||
use async_tungstenite::tungstenite::Message;
|
||||
use async_tungstenite::{WebSocketReceiver, WebSocketSender};
|
||||
use json::JsonValue;
|
||||
use json::number::Number;
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
use epsilon_native::{Receiver, Sender};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_util::compat::Compat;
|
||||
use tungstenite::Utf8Bytes;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::anonymous_clients::anonymous_manager::{self, generate_username};
|
||||
use crate::calls::call_manager;
|
||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||
use crate::omega::omega_connection::get_omega_connection;
|
||||
use crate::rho::connection::GeneralConnection;
|
||||
use crate::rho::rho_manager;
|
||||
use crate::util::logger::PrintType;
|
||||
use crate::{log_in, log_out};
|
||||
use crate::{log_cv_in, log_cv_out, log_out};
|
||||
|
||||
pub struct AnonymousClientConnection {
|
||||
pub sender: Arc<RwLock<WebSocketSender<Compat<tokio::net::TcpStream>>>>,
|
||||
pub receiver: Arc<RwLock<WebSocketReceiver<Compat<tokio::net::TcpStream>>>>,
|
||||
pub user_id: Arc<RwLock<i64>>,
|
||||
user_id: u64,
|
||||
|
||||
pub sender: Arc<Sender>,
|
||||
pub receiver: Arc<Receiver>,
|
||||
pub ping: Arc<RwLock<i64>>,
|
||||
pub interested_users: Arc<RwLock<Vec<i64>>>,
|
||||
is_open: Arc<RwLock<bool>>,
|
||||
|
|
@ -31,33 +28,33 @@ pub struct AnonymousClientConnection {
|
|||
}
|
||||
|
||||
impl AnonymousClientConnection {
|
||||
/// Create a new AnonymousClientConnection
|
||||
pub fn new(
|
||||
sender: WebSocketSender<Compat<tokio::net::TcpStream>>,
|
||||
receiver: WebSocketReceiver<Compat<tokio::net::TcpStream>>,
|
||||
) -> Arc<Self> {
|
||||
pub async fn from_general(general: Arc<GeneralConnection>, user_id: u64) -> Arc<Self> {
|
||||
let username: String = generate_username();
|
||||
Arc::new(Self {
|
||||
sender: Arc::new(RwLock::new(sender)),
|
||||
receiver: Arc::new(RwLock::new(receiver)),
|
||||
user_id: Arc::new(RwLock::new(
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as i64,
|
||||
)),
|
||||
ping: Arc::new(RwLock::new(-1)),
|
||||
user_id: user_id,
|
||||
|
||||
ping: Arc::new(RwLock::new(0)),
|
||||
interested_users: Arc::new(RwLock::new(Vec::new())),
|
||||
is_open: Arc::new(RwLock::new(true)),
|
||||
sender: general.sender.clone(),
|
||||
receiver: general.receiver.clone(),
|
||||
user_name: Arc::new(RwLock::new(username.to_lowercase())),
|
||||
display_name: Arc::new(RwLock::new(username)),
|
||||
avatar: Arc::new(RwLock::new(String::new())),
|
||||
})
|
||||
}
|
||||
pub fn start(self: Arc<Self>) {
|
||||
let self_clone = self.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(cv) = self_clone.receiver.receive().await {
|
||||
self_clone.clone().handle_message(cv).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the user ID
|
||||
pub async fn get_user_id(&self) -> i64 {
|
||||
*self.user_id.read().await
|
||||
pub fn get_user_id(&self) -> u64 {
|
||||
self.user_id
|
||||
}
|
||||
|
||||
/// Get the user name
|
||||
|
|
@ -79,66 +76,35 @@ impl AnonymousClientConnection {
|
|||
self.avatar.read().await.clone()
|
||||
}
|
||||
|
||||
/// Send a string message to the client
|
||||
pub async fn send_message_str(self: Arc<Self>, message: &str) {
|
||||
let mut session = self.sender.write().await;
|
||||
if let Err(e) = session
|
||||
.send(Message::Text(Utf8Bytes::from(message.to_string())))
|
||||
.await
|
||||
{
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Failed to send message to anonymous client: {}",
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a CommunicationValue to the client
|
||||
pub async fn send_message(self: Arc<Self>, cv: &CommunicationValue) {
|
||||
if !*self.is_open.read().await {
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
self.user_id as i64,
|
||||
PrintType::Client,
|
||||
"Attempted to send message to a closed connection."
|
||||
);
|
||||
return;
|
||||
}
|
||||
if !cv.is_type(CommunicationType::pong) {
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"{}",
|
||||
&cv.to_json().to_string()
|
||||
);
|
||||
log_cv_out!(PrintType::Client, &cv);
|
||||
}
|
||||
self.send_message_str(&cv.to_json().to_string()).await;
|
||||
self.sender.send(&cv).await;
|
||||
}
|
||||
|
||||
/// Handle incoming message from client
|
||||
pub async fn handle_message(self: Arc<Self>, message: Utf8Bytes) {
|
||||
pub async fn handle_message(self: Arc<Self>, cv: CommunicationValue) {
|
||||
tokio::spawn(async move {
|
||||
let cv = CommunicationValue::from_json(&message);
|
||||
if cv.is_type(CommunicationType::ping) {
|
||||
self.handle_ping(cv).await;
|
||||
return;
|
||||
}
|
||||
log_in!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Anonymous: {}",
|
||||
&cv.to_json().to_string()
|
||||
);
|
||||
log_cv_in!(PrintType::Client, &cv);
|
||||
|
||||
if cv.is_type(CommunicationType::identification) {
|
||||
let call_id = Uuid::parse_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap_or(Uuid::new_v4());
|
||||
let call_id =
|
||||
Uuid::parse_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or(""))
|
||||
.unwrap_or(Uuid::new_v4());
|
||||
|
||||
let call = if let Some(call) = call_manager::get_call(call_id).await {
|
||||
if call.is_anonymous().await {
|
||||
|
|
@ -160,79 +126,62 @@ impl AnonymousClientConnection {
|
|||
return;
|
||||
};
|
||||
|
||||
let mut invited = JsonValue::new_array();
|
||||
let mut invited = Vec::new();
|
||||
for call_invitee in call.members.read().await.clone() {
|
||||
let call_invitee_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&CommunicationValue::new(CommunicationType::get_user_data).add_data(
|
||||
DataTypes::user_id,
|
||||
JsonValue::from(call_invitee.user_id),
|
||||
DataValue::Number(call_invitee.user_id as i64),
|
||||
),
|
||||
Some(Duration::from_secs(2)),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut json_invitee = JsonValue::new_object();
|
||||
let _ = json_invitee.insert(
|
||||
"user_id",
|
||||
call_invitee_cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.clone(),
|
||||
);
|
||||
let _ = json_invitee.insert(
|
||||
"username",
|
||||
call_invitee_cv
|
||||
.get_data(DataTypes::username)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.clone(),
|
||||
);
|
||||
let _ = json_invitee.insert(
|
||||
"display",
|
||||
call_invitee_cv
|
||||
.get_data(DataTypes::display)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.clone(),
|
||||
);
|
||||
let _ = json_invitee.insert(
|
||||
"avatar",
|
||||
call_invitee_cv
|
||||
.get_data(DataTypes::avatar)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.clone(),
|
||||
);
|
||||
let mut json_invitee = Vec::new();
|
||||
let _ = json_invitee.push((
|
||||
DataTypes::user_id,
|
||||
call_invitee_cv.get_data(DataTypes::user_id).clone(),
|
||||
));
|
||||
let _ = json_invitee.push((
|
||||
DataTypes::username,
|
||||
call_invitee_cv.get_data(DataTypes::username).clone(),
|
||||
));
|
||||
let _ = json_invitee.push((
|
||||
DataTypes::display,
|
||||
call_invitee_cv.get_data(DataTypes::display).clone(),
|
||||
));
|
||||
let _ = json_invitee.push((
|
||||
DataTypes::avatar,
|
||||
call_invitee_cv.get_data(DataTypes::avatar).clone(),
|
||||
));
|
||||
|
||||
let _ = invited.push(json_invitee);
|
||||
let _ = invited.push(DataValue::Container(json_invitee));
|
||||
}
|
||||
|
||||
let token = call.create_anonymous_token(self.get_user_id().await).await;
|
||||
let token = call.create_anonymous_token(self.get_user_id()).await;
|
||||
|
||||
let mut serialized = JsonValue::new_object();
|
||||
let _ = serialized.insert("call_id", JsonValue::String(call_id.to_string()));
|
||||
let _ = serialized.insert("call_invited", invited.clone());
|
||||
let _ = serialized.insert("call_members", invited);
|
||||
let _ = serialized.insert("call_token", JsonValue::String(token.unwrap()));
|
||||
let mut serialized = Vec::new();
|
||||
let _ = serialized.push((DataTypes::call_id, DataValue::Str(call_id.to_string())));
|
||||
let _ =
|
||||
serialized.push((DataTypes::call_invited, DataValue::Array(invited.clone())));
|
||||
let _ = serialized.push((DataTypes::call_members, DataValue::Array(invited)));
|
||||
let _ = serialized.push((DataTypes::call_token, DataValue::Str(token.unwrap())));
|
||||
self.clone()
|
||||
.send_message(
|
||||
&&CommunicationValue::new(CommunicationType::identification_response)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(
|
||||
DataTypes::user_id,
|
||||
JsonValue::from(self.get_user_id().await),
|
||||
)
|
||||
.add_data(DataTypes::user_id, DataValue::Number(self.user_id as i64))
|
||||
.add_data(
|
||||
DataTypes::username,
|
||||
JsonValue::String(self.clone().get_user_name().await),
|
||||
DataValue::Str(self.clone().get_user_name().await),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::display,
|
||||
JsonValue::String(self.get_display_name().await),
|
||||
DataValue::Str(self.get_display_name().await),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::avatar,
|
||||
JsonValue::String(self.get_avatar().await),
|
||||
)
|
||||
.add_data(DataTypes::call_state, serialized),
|
||||
.add_data(DataTypes::avatar, DataValue::Str(self.get_avatar().await))
|
||||
.add_data(DataTypes::call_state, DataValue::Container(serialized)),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -271,11 +220,7 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
|
||||
if cv.is_type(CommunicationType::change_user_data) {
|
||||
if let Some(display_name) = cv
|
||||
.get_data(DataTypes::display)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
{
|
||||
if let Some(display_name) = cv.get_data(DataTypes::display).as_str() {
|
||||
let _ = self.set_display_name(display_name.to_string()).await;
|
||||
}
|
||||
|
||||
|
|
@ -284,17 +229,9 @@ impl AnonymousClientConnection {
|
|||
|
||||
if cv.is_type(CommunicationType::get_user_data) {
|
||||
if let Some(anonymous) = {
|
||||
if let Some(user_id) = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
{
|
||||
anonymous_manager::get_anonymous_user(user_id).await
|
||||
} else if let Some(username) = cv
|
||||
.get_data(DataTypes::username)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
{
|
||||
if let Some(user_id) = cv.get_data(DataTypes::user_id).as_number() {
|
||||
anonymous_manager::get_anonymous_user(user_id as u64).await
|
||||
} else if let Some(username) = cv.get_data(DataTypes::username).as_str() {
|
||||
anonymous_manager::get_anonymous_user_by_name(username.to_string()).await
|
||||
} else {
|
||||
None
|
||||
|
|
@ -302,14 +239,23 @@ impl AnonymousClientConnection {
|
|||
} {
|
||||
let response = CommunicationValue::new(CommunicationType::get_user_data)
|
||||
.with_id(cv.get_id())
|
||||
.add_data_str(DataTypes::username, anonymous.get_user_name().await)
|
||||
.add_data(
|
||||
DataTypes::username,
|
||||
DataValue::Str(anonymous.get_user_name().await),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::user_id,
|
||||
JsonValue::Number(Number::from(anonymous.get_user_id().await)),
|
||||
DataValue::Number(anonymous.user_id as i64),
|
||||
)
|
||||
.add_data_str(DataTypes::display, anonymous.get_display_name().await)
|
||||
.add_data_str(DataTypes::user_state, "online".to_string())
|
||||
.add_data_str(DataTypes::avatar, anonymous.get_avatar().await);
|
||||
.add_data(
|
||||
DataTypes::display,
|
||||
DataValue::Str(anonymous.get_display_name().await),
|
||||
)
|
||||
.add_data(DataTypes::user_state, DataValue::Str("online".to_string()))
|
||||
.add_data(
|
||||
DataTypes::avatar,
|
||||
DataValue::Str(anonymous.get_avatar().await),
|
||||
);
|
||||
|
||||
self.send_message(&response).await;
|
||||
|
||||
|
|
@ -330,10 +276,7 @@ impl AnonymousClientConnection {
|
|||
let client_for_closure = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&cv.with_sender(*self.user_id.read().await),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await_response(&cv.with_sender(self.user_id), Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
if let Ok(response_cv) = response_cv {
|
||||
client_for_closure.send_message(&response_cv).await;
|
||||
|
|
@ -344,7 +287,7 @@ impl AnonymousClientConnection {
|
|||
/// Handle ping message
|
||||
async fn handle_ping(self: Arc<Self>, cv: CommunicationValue) {
|
||||
// Update our ping if provided
|
||||
if let Some(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
if let DataValue::Number(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
if let Ok(ping_val) = last_ping.to_string().parse::<i64>() {
|
||||
let mut ping_guard = self.ping.write().await;
|
||||
*ping_guard = ping_val;
|
||||
|
|
@ -367,11 +310,7 @@ impl AnonymousClientConnection {
|
|||
|
||||
/// Handle call invite
|
||||
async fn handle_call_invite(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let receiver_id: i64 = cv
|
||||
.get_data(DataTypes::receiver_id)
|
||||
.unwrap_or(&json::JsonValue::Number(Number::from(0)))
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let receiver_id: i64 = cv.get_data(DataTypes::receiver_id).as_number().unwrap_or(0);
|
||||
if receiver_id == 0 {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_no_user_id)
|
||||
.await;
|
||||
|
|
@ -379,7 +318,7 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
|
||||
let call_id = match cv.get_data(DataTypes::call_id) {
|
||||
Some(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
DataValue::Str(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
self.send_error_response(
|
||||
|
|
@ -397,8 +336,7 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
};
|
||||
|
||||
let invited =
|
||||
call_manager::add_invite(call_id, *self.user_id.read().await, receiver_id).await;
|
||||
let invited = call_manager::add_invite(call_id, self.user_id, receiver_id as u64).await;
|
||||
if !invited {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_call_id)
|
||||
.await;
|
||||
|
|
@ -416,15 +354,18 @@ impl AnonymousClientConnection {
|
|||
};
|
||||
|
||||
// Get sender user ID
|
||||
let sender_id = self.get_user_id().await;
|
||||
let sender_id = self.get_user_id();
|
||||
|
||||
// Create and send call distribution message
|
||||
let forward = CommunicationValue::new(CommunicationType::call_invite)
|
||||
.with_receiver(receiver_id)
|
||||
.with_receiver(receiver_id as u64)
|
||||
.with_sender(sender_id)
|
||||
.add_data_str(DataTypes::call_id, call_id.to_string())
|
||||
.add_data_str(DataTypes::receiver_id, receiver_id.to_string())
|
||||
.add_data_str(DataTypes::sender_id, sender_id.to_string());
|
||||
.add_data(DataTypes::call_id, DataValue::Str(call_id.to_string()))
|
||||
.add_data(
|
||||
DataTypes::receiver_id,
|
||||
DataValue::Str(receiver_id.to_string()),
|
||||
)
|
||||
.add_data(DataTypes::sender_id, DataValue::Str(sender_id.to_string()));
|
||||
|
||||
target_rho.message_to_client(forward).await;
|
||||
|
||||
|
|
@ -434,10 +375,10 @@ impl AnonymousClientConnection {
|
|||
|
||||
/// Handle get call request
|
||||
async fn handle_get_call(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let user_id = self.get_user_id().await;
|
||||
let user_id = self.get_user_id();
|
||||
|
||||
let call_id = match cv.get_data(DataTypes::call_id) {
|
||||
Some(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
DataValue::Str(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
|
|
@ -456,7 +397,7 @@ impl AnonymousClientConnection {
|
|||
let response = CommunicationValue::new(CommunicationType::call_token)
|
||||
.with_id(cv.get_id())
|
||||
.with_receiver(user_id)
|
||||
.add_data_str(DataTypes::call_token, token);
|
||||
.add_data(DataTypes::call_token, DataValue::Str(token.to_string()));
|
||||
self.send_message(&response).await;
|
||||
} else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
|
|
@ -465,33 +406,20 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
}
|
||||
async fn handle_call_timeout_user(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let call_id = Uuid::from_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap();
|
||||
let user_id = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let untill = cv
|
||||
.get_data(DataTypes::untill)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let call_id =
|
||||
Uuid::from_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or("")).unwrap();
|
||||
let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0);
|
||||
let untill = cv.get_data(DataTypes::untill).as_number().unwrap_or(0);
|
||||
|
||||
let call = call_manager::get_call(call_id).await;
|
||||
if let Some(call) = call {
|
||||
if call
|
||||
.get_caller(self.get_user_id().await)
|
||||
.get_caller(self.get_user_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.has_admin()
|
||||
{
|
||||
call.get_caller(user_id)
|
||||
call.get_caller(user_id as u64)
|
||||
.await
|
||||
.unwrap()
|
||||
.set_timeout(untill)
|
||||
|
|
@ -500,38 +428,25 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
}
|
||||
async fn handle_call_disconnect_user(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let call_id = Uuid::from_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap();
|
||||
let user_id = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let call_id =
|
||||
Uuid::from_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or("")).unwrap();
|
||||
let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0);
|
||||
|
||||
let call = call_manager::get_call(call_id).await;
|
||||
if let Some(call) = call {
|
||||
if call
|
||||
.get_caller(self.get_user_id().await)
|
||||
.get_caller(self.get_user_id())
|
||||
.await
|
||||
.unwrap()
|
||||
.has_admin()
|
||||
{
|
||||
call.remove_caller(user_id).await;
|
||||
call.remove_caller(user_id as u64).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Send error response
|
||||
async fn send_error_response(
|
||||
self: Arc<Self>,
|
||||
message_id: &Uuid,
|
||||
error_type: CommunicationType,
|
||||
) {
|
||||
async fn send_error_response(self: Arc<Self>, message_id: &u32, error_type: CommunicationType) {
|
||||
let error = CommunicationValue::new(error_type).with_id(*message_id);
|
||||
self.send_message(&error).await;
|
||||
}
|
||||
|
|
@ -544,8 +459,7 @@ impl AnonymousClientConnection {
|
|||
}
|
||||
*is_open_guard = false;
|
||||
|
||||
let mut session = self.sender.write().await;
|
||||
let _ = session.close(None).await;
|
||||
let _ = self.sender.close();
|
||||
}
|
||||
|
||||
/// Set interested users list
|
||||
|
|
@ -563,8 +477,8 @@ impl AnonymousClientConnection {
|
|||
let interested_guard = self.clone().get_interested_users().await;
|
||||
if interested_guard.contains(&user_id) {
|
||||
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
||||
.add_data_str(DataTypes::user_id, user_id.to_string())
|
||||
.add_data_str(DataTypes::user_state, format!("online"));
|
||||
.add_data(DataTypes::user_id, DataValue::Str(user_id.to_string()))
|
||||
.add_data(DataTypes::user_state, DataValue::Str("online".to_string()));
|
||||
|
||||
self.send_message(¬ification).await;
|
||||
}
|
||||
|
|
@ -583,7 +497,7 @@ impl Clone for AnonymousClientConnection {
|
|||
Self {
|
||||
sender: Arc::clone(&self.sender),
|
||||
receiver: Arc::clone(&self.receiver),
|
||||
user_id: Arc::clone(&self.user_id),
|
||||
user_id: self.user_id,
|
||||
ping: Arc::clone(&self.ping),
|
||||
interested_users: Arc::clone(&self.interested_users),
|
||||
is_open: Arc::clone(&self.is_open),
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@ use std::sync::Arc;
|
|||
|
||||
use crate::anonymous_clients::anonymous_client_connection::AnonymousClientConnection;
|
||||
|
||||
static ANONYMOUS_USERS: Lazy<DashMap<i64, Arc<AnonymousClientConnection>>> =
|
||||
static ANONYMOUS_USERS: Lazy<DashMap<u64, Arc<AnonymousClientConnection>>> =
|
||||
Lazy::new(|| DashMap::new());
|
||||
|
||||
pub async fn add_anonymous_user(connection: Arc<AnonymousClientConnection>) {
|
||||
ANONYMOUS_USERS.insert(connection.get_user_id().await, connection);
|
||||
ANONYMOUS_USERS.insert(connection.get_user_id(), connection);
|
||||
}
|
||||
|
||||
pub async fn remove_anonymous_user(user_id: i64) {
|
||||
pub async fn remove_anonymous_user(user_id: u64) {
|
||||
ANONYMOUS_USERS.remove(&user_id);
|
||||
}
|
||||
|
||||
pub async fn get_anonymous_user(user_id: i64) -> Option<Arc<AnonymousClientConnection>> {
|
||||
pub async fn get_anonymous_user(user_id: u64) -> Option<Arc<AnonymousClientConnection>> {
|
||||
ANONYMOUS_USERS.get(&user_id).map(|c| c.clone())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use json::JsonValue;
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
|
||||
use std::{env, sync::Arc, time::Duration};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
calls::{call_util, caller::Caller},
|
||||
data::communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||
omega::omega_connection::get_omega_connection,
|
||||
};
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ impl CallGroup {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_caller(&self, user_id: i64) -> Option<Arc<Caller>> {
|
||||
pub async fn get_caller(&self, user_id: u64) -> Option<Arc<Caller>> {
|
||||
self.members
|
||||
.read()
|
||||
.await
|
||||
|
|
@ -62,7 +62,7 @@ impl CallGroup {
|
|||
let response_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&CommunicationValue::new(CommunicationType::shorten_link)
|
||||
.add_data(DataTypes::link, JsonValue::from(long_link)),
|
||||
.add_data(DataTypes::link, DataValue::Str(long_link)),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await;
|
||||
|
|
@ -70,7 +70,6 @@ impl CallGroup {
|
|||
*self.short_link.write().await = Some(
|
||||
response
|
||||
.get_data(DataTypes::link)
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
|
|
@ -84,7 +83,7 @@ impl CallGroup {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn create_anonymous_token(&self, user_id: i64) -> Option<String> {
|
||||
pub async fn create_anonymous_token(&self, user_id: u64) -> Option<String> {
|
||||
if self.is_anonymous().await {
|
||||
if let Ok(token) = call_util::create_token(user_id, self.call_id, false) {
|
||||
return Some(token);
|
||||
|
|
@ -93,7 +92,7 @@ impl CallGroup {
|
|||
None
|
||||
}
|
||||
|
||||
pub async fn remove_caller(&self, user_id: i64) {
|
||||
pub async fn remove_caller(&self, user_id: u64) {
|
||||
let _ = call_util::remove_participant(self.call_id, user_id).await;
|
||||
self.members
|
||||
.write()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::calls::{call_group::CallGroup, caller::Caller};
|
|||
|
||||
pub static CALL_GROUPS: Lazy<DashMap<Uuid, Arc<CallGroup>>> = Lazy::new(|| DashMap::new());
|
||||
|
||||
pub async fn get_call_invites(user_id: i64) -> Vec<Arc<Caller>> {
|
||||
pub async fn get_call_invites(user_id: u64) -> Vec<Arc<Caller>> {
|
||||
let mut callers = Vec::new();
|
||||
for (_, cg) in CALL_GROUPS.clone().into_iter() {
|
||||
let members = cg.members.read().await;
|
||||
|
|
@ -28,7 +28,7 @@ pub async fn get_call(call_id: Uuid) -> Option<Arc<CallGroup>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_call_groups(user_id: i64) -> Vec<Arc<CallGroup>> {
|
||||
pub async fn get_call_groups(user_id: u64) -> Vec<Arc<CallGroup>> {
|
||||
let mut call_groups = Vec::new();
|
||||
for (_, cg) in CALL_GROUPS.clone().into_iter() {
|
||||
let is_member = {
|
||||
|
|
@ -43,7 +43,7 @@ pub async fn get_call_groups(user_id: i64) -> Vec<Arc<CallGroup>> {
|
|||
call_groups
|
||||
}
|
||||
|
||||
pub async fn get_call_token(user_id: i64, call_id: Uuid) -> Option<String> {
|
||||
pub async fn get_call_token(user_id: u64, call_id: Uuid) -> Option<String> {
|
||||
if let Some(cg) = CALL_GROUPS.get(&call_id) {
|
||||
let mut members = cg.members.write().await;
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ pub async fn get_call_token(user_id: i64, call_id: Uuid) -> Option<String> {
|
|||
Some(caller.create_token())
|
||||
}
|
||||
|
||||
pub async fn add_invite(call_id: Uuid, inviter_id: i64, invitee_id: i64) -> bool {
|
||||
pub async fn add_invite(call_id: Uuid, inviter_id: u64, invitee_id: u64) -> bool {
|
||||
if let Some(cg) = CALL_GROUPS.get(&call_id) {
|
||||
let mut members = cg.members.write().await;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub fn get_livekit() -> Result<(String, String, String), ()> {
|
|||
Ok((hostname, api_key, api_secret))
|
||||
}
|
||||
|
||||
pub fn create_token(user_id: i64, call_id: Uuid, has_admin: bool) -> Result<String, ()> {
|
||||
pub fn create_token(user_id: u64, call_id: Uuid, has_admin: bool) -> Result<String, ()> {
|
||||
let (_, api_key, api_secret) = get_livekit()?;
|
||||
|
||||
let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
|
||||
|
|
@ -69,7 +69,7 @@ pub async fn get_room(call_id: Uuid) -> Result<(RoomClient, Room), ()> {
|
|||
return Err(());
|
||||
}
|
||||
|
||||
pub async fn remove_participant(call_id: Uuid, user_id: i64) -> Result<(), ()> {
|
||||
pub async fn remove_participant(call_id: Uuid, user_id: u64) -> Result<(), ()> {
|
||||
if let Ok((hostname, api_key, api_secret)) = get_livekit() {
|
||||
let room_service = RoomClient::with_api_key(&hostname, &api_key, &api_secret);
|
||||
if let Ok(_) = room_service
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ use uuid::Uuid;
|
|||
use crate::calls::call_util;
|
||||
|
||||
pub struct Caller {
|
||||
pub user_id: i64,
|
||||
pub user_id: u64,
|
||||
pub call_id: Uuid,
|
||||
pub has_admin: bool,
|
||||
pub timeout: RwLock<i64>,
|
||||
}
|
||||
|
||||
impl Caller {
|
||||
pub fn new(user_id: i64, call_id: Uuid, has_admin: bool) -> Self {
|
||||
pub fn new(user_id: u64, call_id: Uuid, has_admin: bool) -> Self {
|
||||
Caller {
|
||||
user_id,
|
||||
call_id,
|
||||
|
|
|
|||
|
|
@ -1,403 +0,0 @@
|
|||
use json::number::Number;
|
||||
use json::{Array, JsonValue, object, parse};
|
||||
use std::collections::HashMap;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::EnumIter;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, EnumIter, Clone, Debug)]
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
pub enum DataTypes {
|
||||
error_type,
|
||||
accepted_ids,
|
||||
uuid,
|
||||
register_id,
|
||||
|
||||
link,
|
||||
|
||||
settings,
|
||||
settings_name,
|
||||
chat_partner_id,
|
||||
chat_partner_name,
|
||||
iota_id,
|
||||
user_id,
|
||||
user_ids,
|
||||
iota_ids,
|
||||
user_state,
|
||||
user_states,
|
||||
user_pings,
|
||||
call_state,
|
||||
screen_share,
|
||||
private_key_hash,
|
||||
accepted,
|
||||
accepted_profiles,
|
||||
denied_profiles,
|
||||
content,
|
||||
messages,
|
||||
notifications,
|
||||
send_time,
|
||||
get_time,
|
||||
get_variant,
|
||||
shared_secret_own,
|
||||
shared_secret_other,
|
||||
shared_secret_sign,
|
||||
shared_secret,
|
||||
call_id,
|
||||
call_token,
|
||||
untill,
|
||||
enabled,
|
||||
start_date,
|
||||
end_date,
|
||||
receiver_id,
|
||||
sender_id,
|
||||
signature,
|
||||
signed,
|
||||
message,
|
||||
message_state,
|
||||
last_ping,
|
||||
ping_iota,
|
||||
ping_clients,
|
||||
matches,
|
||||
omikron,
|
||||
offset,
|
||||
amount,
|
||||
position,
|
||||
name,
|
||||
path,
|
||||
codec,
|
||||
function,
|
||||
payload,
|
||||
result,
|
||||
interactables,
|
||||
want_to_watch,
|
||||
watcher,
|
||||
created_at,
|
||||
username,
|
||||
display,
|
||||
avatar,
|
||||
about,
|
||||
status,
|
||||
public_key,
|
||||
sub_level,
|
||||
sub_end,
|
||||
community_address,
|
||||
challenge,
|
||||
community_title,
|
||||
communities,
|
||||
rho_connections,
|
||||
user,
|
||||
online_status,
|
||||
omikron_id,
|
||||
omikron_connections,
|
||||
reset_token,
|
||||
new_token,
|
||||
}
|
||||
|
||||
impl DataTypes {
|
||||
pub fn parse(p0: String) -> DataTypes {
|
||||
for datatype in DataTypes::iter() {
|
||||
if datatype.to_string().to_lowercase().replace('_', "")
|
||||
== p0.to_lowercase().replace('_', "")
|
||||
{
|
||||
return datatype;
|
||||
}
|
||||
}
|
||||
DataTypes::error_type
|
||||
}
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("{:?}", self);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, EnumIter, Debug)]
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
pub enum CommunicationType {
|
||||
error,
|
||||
error_anonymous,
|
||||
error_internal,
|
||||
error_invalid_data,
|
||||
error_invalid_user_id,
|
||||
error_invalid_omikron_id,
|
||||
error_not_found,
|
||||
error_not_authenticated,
|
||||
error_no_iota,
|
||||
error_invalid_challenge,
|
||||
error_invalid_secret,
|
||||
error_invalid_private_key,
|
||||
error_invalid_public_key,
|
||||
error_no_user_id,
|
||||
error_no_call_id,
|
||||
error_invalid_call_id,
|
||||
success,
|
||||
|
||||
shorten_link,
|
||||
|
||||
settings_save,
|
||||
settings_load,
|
||||
settings_list,
|
||||
message,
|
||||
message_state,
|
||||
message_send,
|
||||
message_live,
|
||||
message_other_iota,
|
||||
message_chunk,
|
||||
messages_get,
|
||||
|
||||
push_notification,
|
||||
read_notification,
|
||||
get_notifications,
|
||||
|
||||
change_confirm,
|
||||
confirm_receive,
|
||||
confirm_read,
|
||||
get_chats,
|
||||
get_states,
|
||||
add_community,
|
||||
remove_community,
|
||||
get_communities,
|
||||
challenge,
|
||||
challenge_response,
|
||||
register,
|
||||
register_response,
|
||||
identification,
|
||||
identification_response,
|
||||
register_iota,
|
||||
register_iota_success,
|
||||
ping,
|
||||
pong,
|
||||
add_conversation,
|
||||
send_chat,
|
||||
client_changed,
|
||||
client_connected,
|
||||
client_disconnected,
|
||||
client_closed,
|
||||
public_key,
|
||||
private_key,
|
||||
webrtc_sdp,
|
||||
webrtc_ice,
|
||||
start_stream,
|
||||
end_stream,
|
||||
watch_stream,
|
||||
call_token,
|
||||
call_invite,
|
||||
call_disconnect_user,
|
||||
call_timeout_user,
|
||||
call_set_anonymous_joining,
|
||||
end_call,
|
||||
function,
|
||||
update,
|
||||
create_user,
|
||||
rho_update,
|
||||
|
||||
user_connected,
|
||||
user_disconnected,
|
||||
iota_connected,
|
||||
iota_disconnected,
|
||||
sync_client_iota_status,
|
||||
|
||||
get_user_data,
|
||||
get_iota_data,
|
||||
iota_user_data,
|
||||
|
||||
change_user_data,
|
||||
change_iota_data,
|
||||
|
||||
get_register,
|
||||
complete_register_user,
|
||||
complete_register_iota,
|
||||
delete_user,
|
||||
delete_iota,
|
||||
|
||||
start_register,
|
||||
complete_register,
|
||||
}
|
||||
impl CommunicationType {
|
||||
pub fn parse(p0: String) -> CommunicationType {
|
||||
for datatype in CommunicationType::iter() {
|
||||
if datatype.to_string().to_lowercase().replace('_', "")
|
||||
== p0.to_lowercase().replace('_', "")
|
||||
{
|
||||
return datatype;
|
||||
}
|
||||
}
|
||||
CommunicationType::error
|
||||
}
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("{:?}", self);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CommunicationValue {
|
||||
id: Uuid,
|
||||
comm_type: CommunicationType,
|
||||
sender: i64,
|
||||
receiver: i64,
|
||||
data: HashMap<DataTypes, JsonValue>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl CommunicationValue {
|
||||
pub fn new(comm_type: CommunicationType) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
comm_type,
|
||||
sender: 0,
|
||||
receiver: 0,
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn with_id(mut self, p0: Uuid) -> Self {
|
||||
self.id = p0;
|
||||
self
|
||||
}
|
||||
pub fn get_id(&self) -> Uuid {
|
||||
self.id.clone()
|
||||
}
|
||||
pub fn with_sender(mut self, sender: i64) -> Self {
|
||||
self.sender = sender;
|
||||
self
|
||||
}
|
||||
pub fn get_sender(&self) -> i64 {
|
||||
self.sender.clone()
|
||||
}
|
||||
pub fn with_receiver(mut self, receiver: i64) -> Self {
|
||||
self.receiver = receiver;
|
||||
self
|
||||
}
|
||||
pub fn get_receiver(&self) -> i64 {
|
||||
self.receiver.clone()
|
||||
}
|
||||
pub fn add_data_num(mut self, key: DataTypes, value: Number) -> Self {
|
||||
self.data.insert(key, JsonValue::Number(value));
|
||||
self
|
||||
}
|
||||
pub fn add_data_str(mut self, key: DataTypes, value: String) -> Self {
|
||||
self.data.insert(key, JsonValue::String(value));
|
||||
self
|
||||
}
|
||||
pub fn add_data(mut self, key: DataTypes, value: JsonValue) -> Self {
|
||||
self.data.insert(key, value);
|
||||
self
|
||||
}
|
||||
pub fn add_array(mut self, key: DataTypes, value: Array) -> Self {
|
||||
self.data.insert(key, JsonValue::Array(value));
|
||||
self
|
||||
}
|
||||
pub fn get_data(&self, key: DataTypes) -> Option<&JsonValue> {
|
||||
self.data.get(&key)
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> CommunicationType {
|
||||
self.comm_type.clone()
|
||||
}
|
||||
pub fn is_type(&self, p0: CommunicationType) -> bool {
|
||||
self.comm_type == p0
|
||||
}
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
let mut jdata = object! {};
|
||||
for (k, v) in &self.data {
|
||||
jdata[&format!("{:?}", k)] = JsonValue::from(v.clone());
|
||||
}
|
||||
if self.sender > 0 && self.receiver > 0 {
|
||||
object! {
|
||||
id: self.id.to_string(),
|
||||
type: format!("{:?}", self.comm_type),
|
||||
sender: self.sender,
|
||||
receiver: self.receiver,
|
||||
data: jdata
|
||||
}
|
||||
} else if self.sender > 0 {
|
||||
object! {
|
||||
id: self.id.to_string(),
|
||||
type: format!("{:?}", self.comm_type),
|
||||
sender: self.sender,
|
||||
data: jdata
|
||||
}
|
||||
} else if self.receiver > 0 {
|
||||
object! {
|
||||
id: self.id.to_string(),
|
||||
type: format!("{:?}", self.comm_type),
|
||||
receiver: self.receiver,
|
||||
data: jdata
|
||||
}
|
||||
} else {
|
||||
object! {
|
||||
id: self.id.to_string(),
|
||||
type: format!("{:?}", self.comm_type),
|
||||
data: jdata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_json(json_str: &str) -> Self {
|
||||
if let Ok(parsed) = parse(json_str) {
|
||||
let comm_type = CommunicationType::parse(parsed["type"].to_string());
|
||||
let mut sender: i64 = 0;
|
||||
if parsed.has_key("sender") {
|
||||
sender = parsed["sender"].as_i64().unwrap_or(0);
|
||||
}
|
||||
let mut receiver: i64 = 0;
|
||||
if parsed.has_key("receiver") {
|
||||
receiver = parsed["receiver"].as_i64().unwrap_or(0);
|
||||
}
|
||||
|
||||
let uuid =
|
||||
Uuid::parse_str(parsed["id"].as_str().unwrap_or("")).unwrap_or(Uuid::new_v4());
|
||||
let mut data = HashMap::new();
|
||||
if parsed["data"].is_object() {
|
||||
for (k, v) in parsed["data"].entries() {
|
||||
data.insert(DataTypes::parse(k.to_string()), v.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
id: uuid,
|
||||
comm_type,
|
||||
sender,
|
||||
receiver,
|
||||
data,
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
comm_type: CommunicationType::error,
|
||||
sender: 0,
|
||||
receiver: 0,
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn forward_to_other_iota(original: &mut CommunicationValue) -> CommunicationValue {
|
||||
let receiver = original
|
||||
.get_data(DataTypes::receiver_id)
|
||||
.unwrap_or(&JsonValue::Number(Number::from(0)))
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
|
||||
let now_ms = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as i64;
|
||||
|
||||
let sender = original.get_sender();
|
||||
CommunicationValue::new(CommunicationType::message_other_iota)
|
||||
.with_id(original.get_id())
|
||||
.with_receiver(receiver)
|
||||
.add_data(
|
||||
DataTypes::receiver_id,
|
||||
JsonValue::Number(Number::from(receiver)),
|
||||
)
|
||||
.with_sender(sender)
|
||||
.add_data(DataTypes::send_time, JsonValue::String(now_ms.to_string()))
|
||||
.add_data(
|
||||
DataTypes::sender_id,
|
||||
JsonValue::Number(Number::from(sender)),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::content,
|
||||
JsonValue::String(original.get_data(DataTypes::content).unwrap().to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1 @@
|
|||
pub mod communication;
|
||||
pub mod user;
|
||||
|
|
|
|||
200
src/main.rs
200
src/main.rs
|
|
@ -5,24 +5,17 @@ mod omega;
|
|||
mod rho;
|
||||
mod util;
|
||||
|
||||
use async_tungstenite::accept_hdr_async;
|
||||
use std::env;
|
||||
|
||||
use dotenv::dotenv;
|
||||
use futures::StreamExt;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{env, sync::Arc};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_util::compat::TokioAsyncReadCompatExt;
|
||||
use tungstenite::handshake::server::{Request, Response};
|
||||
|
||||
use crate::{
|
||||
anonymous_clients::{
|
||||
anonymous_client_connection::AnonymousClientConnection, anonymous_manager,
|
||||
},
|
||||
calls::call_util::garbage_collect_calls,
|
||||
rho::{client_connection::ClientConnection, iota_connection::IotaConnection},
|
||||
rho::server::start,
|
||||
util::{
|
||||
crypto_helper::{load_public_key, load_secret_key},
|
||||
logger::{PrintType, startup},
|
||||
logger::startup,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -39,191 +32,8 @@ pub fn get_public_key() -> x448::PublicKey {
|
|||
async fn main() {
|
||||
dotenv().ok();
|
||||
startup();
|
||||
let address = format!(
|
||||
"{}:{}",
|
||||
env::var("IP").unwrap_or("0.0.0.0".to_string()),
|
||||
env::var("PORT").unwrap_or("959".to_string())
|
||||
);
|
||||
let listener = TcpListener::bind(&address).await.unwrap();
|
||||
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"WebSocket server listening on {}",
|
||||
address,
|
||||
);
|
||||
start(959).await;
|
||||
|
||||
garbage_collect_calls();
|
||||
|
||||
while let Ok((stream, _)) = listener.accept().await {
|
||||
tokio::spawn(async move {
|
||||
let mut path: String = "/".to_string();
|
||||
|
||||
let callback = |req: &Request, response: Response| {
|
||||
path = req.uri().path().to_string();
|
||||
Ok(response)
|
||||
};
|
||||
let ws_stream = match accept_hdr_async(stream.compat(), callback).await {
|
||||
Ok(ws) => ws,
|
||||
Err(e) => {
|
||||
log!(0, PrintType::General, "WebSocket upgrade failed: {}", e,);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let (sender, receiver) = ws_stream.split();
|
||||
if path.starts_with("/ws/client") {
|
||||
log_in!(0, PrintType::Client, "New Client connection");
|
||||
let client_conn: Arc<ClientConnection> =
|
||||
Arc::from(ClientConnection::new(sender, receiver));
|
||||
loop {
|
||||
let msg_result = {
|
||||
let mut session_lock = client_conn.receiver.write().await;
|
||||
session_lock.next().await
|
||||
};
|
||||
|
||||
match msg_result {
|
||||
Some(Ok(msg)) => {
|
||||
if msg.is_text() {
|
||||
let text = msg.into_text().unwrap();
|
||||
client_conn.clone().handle_message(text).await;
|
||||
} else if msg.is_close() {
|
||||
log_in!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Client disconnected"
|
||||
);
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
log_err!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"WebSocket error: {}",
|
||||
e
|
||||
);
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
log_in!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Client stream ended"
|
||||
);
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if path.starts_with("/ws/anonymous_client") {
|
||||
log_in!(0, PrintType::Client, "New Anonymous Client connection");
|
||||
let client_conn: Arc<AnonymousClientConnection> =
|
||||
Arc::from(AnonymousClientConnection::new(sender, receiver));
|
||||
anonymous_manager::add_anonymous_user(client_conn.clone()).await;
|
||||
loop {
|
||||
let msg_result = {
|
||||
let mut session_lock = client_conn.receiver.write().await;
|
||||
session_lock.next().await
|
||||
};
|
||||
|
||||
match msg_result {
|
||||
Some(Ok(msg)) => {
|
||||
if msg.is_text() {
|
||||
let text = msg.into_text().unwrap();
|
||||
client_conn.clone().handle_message(text).await;
|
||||
} else if msg.is_close() {
|
||||
log_in!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Anonymous Client disconnected"
|
||||
);
|
||||
anonymous_manager::remove_anonymous_user(
|
||||
client_conn.get_user_id().await,
|
||||
)
|
||||
.await;
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
log_err!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"WebSocket error: {}",
|
||||
e
|
||||
);
|
||||
anonymous_manager::remove_anonymous_user(
|
||||
client_conn.get_user_id().await,
|
||||
)
|
||||
.await;
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
log_in!(
|
||||
client_conn.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Anonymous Client stream ended"
|
||||
);
|
||||
anonymous_manager::remove_anonymous_user(
|
||||
client_conn.get_user_id().await,
|
||||
)
|
||||
.await;
|
||||
client_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if path.starts_with("/ws/iota") {
|
||||
log_in!(0, PrintType::Iota, "New Iota connection");
|
||||
let iota_conn: Arc<IotaConnection> =
|
||||
Arc::from(IotaConnection::new(sender, receiver));
|
||||
loop {
|
||||
let msg_result = {
|
||||
let mut session_lock = iota_conn.receiver.write().await;
|
||||
session_lock.next().await
|
||||
};
|
||||
|
||||
match msg_result {
|
||||
Some(Ok(msg)) => {
|
||||
if msg.is_text() {
|
||||
let text = msg.into_text().unwrap();
|
||||
iota_conn.clone().handle_message(text).await;
|
||||
} else if msg.is_close() {
|
||||
log_in!(
|
||||
iota_conn.get_iota_id().await,
|
||||
PrintType::Iota,
|
||||
"Iota disconnected"
|
||||
);
|
||||
iota_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
log_err!(
|
||||
iota_conn.get_iota_id().await,
|
||||
PrintType::Iota,
|
||||
"WebSocket error: {}",
|
||||
e
|
||||
);
|
||||
iota_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
// Stream ended
|
||||
log_in!(
|
||||
iota_conn.get_iota_id().await,
|
||||
PrintType::Iota,
|
||||
"Iota stream ended"
|
||||
);
|
||||
iota_conn.handle_close().await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
pub mod omega_connection;
|
||||
pub mod ping_pong_task;
|
||||
|
|
|
|||
|
|
@ -1,392 +1,165 @@
|
|||
use async_tungstenite::{
|
||||
WebSocketReceiver, WebSocketSender,
|
||||
stream::Stream,
|
||||
tokio::{TokioAdapter, connect_async},
|
||||
tungstenite::protocol::Message,
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use crossterm::style::Print;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use futures::prelude::*;
|
||||
use json::{JsonValue, number::Number};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{collections::HashMap, env, sync::Arc, time::Duration};
|
||||
use tokio::{
|
||||
net::TcpStream,
|
||||
sync::{Mutex, RwLock, mpsc},
|
||||
time::{Instant, sleep},
|
||||
};
|
||||
use tokio_native_tls::TlsStream;
|
||||
use uuid::Uuid;
|
||||
use tokio::sync::{Mutex, RwLock, mpsc};
|
||||
|
||||
use crate::{
|
||||
data::{
|
||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||
user::UserStatus,
|
||||
},
|
||||
get_private_key, log, log_cv_out, log_in, log_out,
|
||||
rho::rho_manager::{self, RHO_CONNECTIONS, connection_count},
|
||||
util::{
|
||||
crypto_helper::{decrypt_b64, secret_key_to_base64},
|
||||
logger::PrintType,
|
||||
},
|
||||
};
|
||||
use crate::{log_cv_in, log_err};
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
use epsilon_native::{Receiver, Sender, connect};
|
||||
|
||||
pub struct WaitingTask {
|
||||
pub task: Box<dyn Fn(Arc<OmegaConnection>, CommunicationValue) -> bool + Send + Sync>,
|
||||
pub inserted_at: Instant,
|
||||
}
|
||||
use crate::{data::user::UserStatus, rho::rho_manager};
|
||||
|
||||
pub static WAITING_TASKS: Lazy<DashMap<Uuid, WaitingTask>> = Lazy::new(DashMap::new);
|
||||
static WAITING: Lazy<
|
||||
DashMap<
|
||||
u32,
|
||||
(
|
||||
Instant,
|
||||
Box<dyn Fn(Arc<OmegaConnection>, CommunicationValue) -> bool + Send + Sync>,
|
||||
),
|
||||
>,
|
||||
> = Lazy::new(DashMap::new);
|
||||
|
||||
static OMEGA_CONNECTION: Lazy<Arc<OmegaConnection>> = Lazy::new(|| {
|
||||
let conn = Arc::new(OmegaConnection::new());
|
||||
let conn_clone = conn.clone();
|
||||
tokio::spawn(async move {
|
||||
conn_clone.connect_internal(0).await;
|
||||
});
|
||||
static OMEGA_CONNECTION: Lazy<Arc<OmegaConnection>> = Lazy::new(|| OmegaConnection::new());
|
||||
|
||||
tokio::spawn(async {
|
||||
loop {
|
||||
sleep(Duration::from_secs(60)).await;
|
||||
WAITING_TASKS.retain(|_, v| v.inserted_at.elapsed() < Duration::from_secs(60));
|
||||
}
|
||||
});
|
||||
|
||||
conn
|
||||
});
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_omega_connection() -> Arc<OmegaConnection> {
|
||||
OMEGA_CONNECTION.clone()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OmegaConnection {
|
||||
write: Arc<
|
||||
Mutex<
|
||||
Option<
|
||||
WebSocketSender<
|
||||
Stream<TokioAdapter<TcpStream>, TokioAdapter<TlsStream<TcpStream>>>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
read: Arc<
|
||||
Mutex<
|
||||
Option<
|
||||
WebSocketReceiver<
|
||||
Stream<TokioAdapter<TcpStream>, TokioAdapter<TlsStream<TcpStream>>>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
pingpong: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
|
||||
pub last_ping: Arc<Mutex<i64>>,
|
||||
pub message_send_times: Arc<Mutex<HashMap<Uuid, Instant>>>,
|
||||
state: Arc<RwLock<ConnectionState>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
enum ConnectionState {
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum State {
|
||||
Disconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
pub struct OmegaConnection {
|
||||
sender: Arc<Mutex<Option<Sender>>>,
|
||||
receiver: Arc<Mutex<Option<Receiver>>>,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
|
||||
impl OmegaConnection {
|
||||
pub fn new() -> Self {
|
||||
OmegaConnection {
|
||||
read: Arc::new(Mutex::new(None)),
|
||||
write: Arc::new(Mutex::new(None)),
|
||||
pingpong: Arc::new(Mutex::new(None)),
|
||||
last_ping: Arc::new(Mutex::new(-1)),
|
||||
message_send_times: Arc::new(Mutex::new(HashMap::new())),
|
||||
state: Arc::new(RwLock::new(ConnectionState::Disconnected)),
|
||||
}
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
sender: Arc::new(Mutex::new(None)),
|
||||
receiver: Arc::new(Mutex::new(None)),
|
||||
state: Arc::new(RwLock::new(State::Disconnected)),
|
||||
})
|
||||
}
|
||||
async fn connect_internal(self: Arc<OmegaConnection>, mut retry: usize) {
|
||||
if self.state.read().await.eq(&ConnectionState::Connected) {
|
||||
return;
|
||||
}
|
||||
if self.state.read().await.eq(&ConnectionState::Connecting) {
|
||||
let start = Instant::now();
|
||||
let timeout = Duration::from_secs(10);
|
||||
while self.state.read().await.eq(&ConnectionState::Connecting)
|
||||
&& start.elapsed() < timeout
|
||||
{
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
*self.state.write().await = ConnectionState::Connecting;
|
||||
pub async fn connect(self: Arc<Self>, addr: &str) -> Result<(), String> {
|
||||
*self.state.write().await = State::Connecting;
|
||||
|
||||
if let Some(handle) = self.pingpong.lock().await.take() {
|
||||
handle.abort();
|
||||
}
|
||||
let (sender, receiver) = connect(addr)
|
||||
.await
|
||||
.map_err(|e| format!("Connect error: {e:?}"))?;
|
||||
|
||||
loop {
|
||||
if retry > 500 {
|
||||
log_err!(
|
||||
0,
|
||||
PrintType::Omega,
|
||||
"Max retry attempts reached, giving up."
|
||||
);
|
||||
*self.state.write().await = ConnectionState::Disconnected;
|
||||
return;
|
||||
}
|
||||
*self.sender.lock().await = Some(sender);
|
||||
*self.receiver.lock().await = Some(receiver);
|
||||
|
||||
let url_str =
|
||||
env::var("OMEGA_HOST").unwrap_or("wss://omega.tensamin.net/ws/omikron".to_string());
|
||||
match connect_async(&url_str).await {
|
||||
Ok((ws_stream, _)) => {
|
||||
log_in!(0, PrintType::Omega, "WebSocket connected to {}", url_str);
|
||||
retry = 0;
|
||||
let (write, read) = ws_stream.split();
|
||||
*self.read.lock().await = Some(read);
|
||||
*self.write.lock().await = Some(write);
|
||||
*self.state.write().await = State::Connected;
|
||||
|
||||
*self.state.write().await = ConnectionState::Connected;
|
||||
let read_self = self.clone();
|
||||
tokio::spawn(async move {
|
||||
read_self.read_loop().await;
|
||||
});
|
||||
|
||||
let read_loop_self = self.clone();
|
||||
let read_loop_handle = tokio::spawn(async move {
|
||||
read_loop_self.read_loop().await;
|
||||
});
|
||||
self.identify().await?;
|
||||
|
||||
let cloned_self = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let id = Uuid::new_v4();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let identify_msg =
|
||||
CommunicationValue::new(CommunicationType::identification)
|
||||
.with_id(id)
|
||||
.add_data(
|
||||
DataTypes::omikron,
|
||||
JsonValue::Number(Number::from(
|
||||
env::var("ID")
|
||||
.unwrap_or("0".to_string())
|
||||
.parse::<i64>()
|
||||
.unwrap_or(0),
|
||||
)),
|
||||
);
|
||||
WAITING_TASKS.insert(
|
||||
id,
|
||||
WaitingTask {
|
||||
task: Box::new(|selfc, cv| {
|
||||
if cv.is_type(CommunicationType::error_not_found) {
|
||||
log_err!(0,
|
||||
PrintType::Omega,
|
||||
"Identification failed: Omikron ID not found on Omega.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if !cv.is_type(CommunicationType::challenge) {
|
||||
return false;
|
||||
}
|
||||
tokio::spawn(async move {
|
||||
let task = async move {
|
||||
let challenge = cv
|
||||
.get_data(DataTypes::challenge)
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| {
|
||||
"Challenge not found or not a string".to_string()
|
||||
})?;
|
||||
async fn identify(&self) -> Result<(), String> {
|
||||
let msg = CommunicationValue::new(CommunicationType::identification)
|
||||
.add_data(DataTypes::omikron, DataValue::Number(1));
|
||||
|
||||
let server_pub_key = cv
|
||||
.get_data(DataTypes::public_key)
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| {
|
||||
"Public key from server not found or not a string"
|
||||
.to_string()
|
||||
})?;
|
||||
self.await_response(&msg, Some(Duration::from_secs(10)))
|
||||
.await?;
|
||||
|
||||
let decrypted_challenge = decrypt_b64(
|
||||
&secret_key_to_base64(&get_private_key()),
|
||||
server_pub_key,
|
||||
challenge,
|
||||
)
|
||||
.map_err(|e| {
|
||||
format!("Failed to decrypt challenge: {:?}", e)
|
||||
})?;
|
||||
|
||||
let response_msg = CommunicationValue::new(
|
||||
CommunicationType::challenge_response,
|
||||
)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(
|
||||
DataTypes::challenge,
|
||||
JsonValue::String(decrypted_challenge),
|
||||
);
|
||||
|
||||
let response_id = response_msg.get_id();
|
||||
WAITING_TASKS.insert(
|
||||
response_id,
|
||||
WaitingTask {
|
||||
task: Box::new(|selfc, final_cv| {
|
||||
if !final_cv
|
||||
.is_type(CommunicationType::identification_response)
|
||||
{
|
||||
log_err!(0,
|
||||
PrintType::Omega,
|
||||
"Expected identification_response, got something else.",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(accepted) = final_cv.get_data(DataTypes::accepted).and_then(|v| v.as_bool()) {
|
||||
if !accepted {
|
||||
log_err!(0, PrintType::Omega, "Omega did not accept identification.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
log_err!(0, PrintType::Omega, "Omega response did not contain 'accepted' field.");
|
||||
return false;
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut connected_iota_ids: Vec<JsonValue> = Vec::new();
|
||||
let mut connected_user_ids: Vec<JsonValue> = Vec::new();
|
||||
let rho_connections_reader = RHO_CONNECTIONS.read().await;
|
||||
|
||||
for iota_id in rho_connections_reader.keys() {
|
||||
connected_iota_ids.push(JsonValue::from(*iota_id));
|
||||
}
|
||||
|
||||
for rho in rho_connections_reader.values() {
|
||||
for client_conn in rho.get_client_connections().await {
|
||||
connected_user_ids.push(JsonValue::from(client_conn.get_user_id().await));
|
||||
}
|
||||
}
|
||||
|
||||
drop(rho_connections_reader);
|
||||
|
||||
let sync_msg = CommunicationValue::new(CommunicationType::sync_client_iota_status)
|
||||
.add_data(DataTypes::iota_ids, JsonValue::Array(connected_iota_ids))
|
||||
.add_data(DataTypes::user_ids, JsonValue::Array(connected_user_ids))
|
||||
.add_data(DataTypes::rho_connections, JsonValue::from(connection_count().await));
|
||||
|
||||
selfc.send_message(&sync_msg).await;
|
||||
});
|
||||
log!(0,
|
||||
PrintType::Omega,
|
||||
"Successfully identified with Omega.",
|
||||
);
|
||||
true
|
||||
}),
|
||||
inserted_at: Instant::now(),
|
||||
}
|
||||
);
|
||||
|
||||
selfc.send_message(&response_msg).await;
|
||||
|
||||
Ok::<(), String>(())
|
||||
};
|
||||
|
||||
if let Err(e) = task.await {
|
||||
log_err!(0, PrintType::Omega, "{}", &e);
|
||||
}
|
||||
});
|
||||
|
||||
true
|
||||
}),
|
||||
inserted_at: Instant::now(),
|
||||
}
|
||||
);
|
||||
cloned_self.send_message(&identify_msg).await
|
||||
});
|
||||
|
||||
let ping_pong_self = self.clone();
|
||||
let handle = tokio::spawn(async move {
|
||||
loop {
|
||||
if *ping_pong_self.state.read().await != ConnectionState::Connected {
|
||||
break;
|
||||
}
|
||||
ping_pong_self.send_ping().await;
|
||||
sleep(Duration::from_secs(5)).await;
|
||||
}
|
||||
});
|
||||
|
||||
*self.pingpong.lock().await = Some(handle);
|
||||
|
||||
read_loop_handle.await.unwrap_or_else(|e| {
|
||||
log_err!(0, PrintType::Omega, "Read loop task failed: {}", e)
|
||||
});
|
||||
|
||||
*self.read.lock().await = None;
|
||||
*self.write.lock().await = None;
|
||||
*self.state.write().await = ConnectionState::Disconnected;
|
||||
|
||||
log_err!(0, PrintType::Omega, "Connection lost. Retrying...");
|
||||
retry += 1;
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
}
|
||||
Err(e) => {
|
||||
*self.state.write().await = ConnectionState::Disconnected;
|
||||
log_err!(
|
||||
0,
|
||||
PrintType::Omega,
|
||||
"WebSocket connection failed (attempt {}): {}",
|
||||
retry + 1,
|
||||
e,
|
||||
);
|
||||
retry += 1;
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn read_loop(self: Arc<Self>) {
|
||||
let mut reader = match self.read.lock().await.take() {
|
||||
Some(reader) => reader,
|
||||
None => return,
|
||||
};
|
||||
|
||||
loop {
|
||||
let msg = reader.next().await;
|
||||
|
||||
match msg {
|
||||
Some(Ok(Message::Text(msg))) => {
|
||||
let cv = CommunicationValue::from_json(&msg);
|
||||
log_cv_in!(PrintType::Omega, cv);
|
||||
if cv.is_type(CommunicationType::pong) || cv.is_type(CommunicationType::ping) {
|
||||
self.handle_pong(&cv, true).await;
|
||||
continue;
|
||||
}
|
||||
let msg_id = cv.get_id();
|
||||
if let Some(task) = WAITING_TASKS.remove(&msg_id) {
|
||||
if (task.1.task)(self.clone(), cv.clone()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
let result = {
|
||||
let mut guard = self.receiver.lock().await;
|
||||
match guard.as_mut() {
|
||||
Some(receiver) => receiver.receive().await,
|
||||
None => return,
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
Some(Ok(Message::Close(_))) | None => break,
|
||||
Some(Err(_)) => break,
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let cv = match result {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
*self.state.write().await = State::Disconnected;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let id = cv.get_id();
|
||||
|
||||
if let Some((_, task)) = WAITING.remove(&id) {
|
||||
(task.1)(self.clone(), cv);
|
||||
continue;
|
||||
}
|
||||
|
||||
if cv.is_type(CommunicationType::ping) {
|
||||
let pong = CommunicationValue::new(CommunicationType::pong).with_id(id);
|
||||
let _ = self.send(&pong).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_message(&self, cv: &CommunicationValue) {
|
||||
log_cv_out!(PrintType::Omega, cv);
|
||||
let msg = cv.to_json().to_string();
|
||||
|
||||
let mut guard = self.write.lock().await;
|
||||
if let Some(ws) = guard.as_mut() {
|
||||
let _ = ws.send(Message::Text(msg.into())).await;
|
||||
pub async fn send(&self, cv: &CommunicationValue) -> Result<(), String> {
|
||||
let guard = self.sender.lock().await;
|
||||
if let Some(sender) = guard.as_ref() {
|
||||
sender
|
||||
.send(cv)
|
||||
.await
|
||||
.map_err(|e| format!("Send error: {e:?}"))
|
||||
} else {
|
||||
Err("Not connected".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn await_response(
|
||||
&self,
|
||||
cv: &CommunicationValue,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<CommunicationValue, String> {
|
||||
let (tx, mut rx) = mpsc::channel(1);
|
||||
let id = cv.get_id();
|
||||
|
||||
WAITING.insert(
|
||||
id.into(),
|
||||
(
|
||||
Instant::now(),
|
||||
Box::new(move |_, response| {
|
||||
let _ = tx.try_send(response);
|
||||
true
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
self.send(cv).await?;
|
||||
|
||||
match tokio::time::timeout(timeout.unwrap_or(Duration::from_secs(10)), rx.recv()).await {
|
||||
Ok(Some(v)) => Ok(v),
|
||||
_ => {
|
||||
WAITING.remove(&id.into());
|
||||
Err("Timeout waiting for response".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub async fn close_iota(iota_id: i64) {
|
||||
let cv = CommunicationValue::new(CommunicationType::iota_disconnected)
|
||||
.add_data(DataTypes::iota_id, JsonValue::from(iota_id));
|
||||
.add_data(DataTypes::iota_id, DataValue::Number(iota_id));
|
||||
OmegaConnection::send_global(cv).await;
|
||||
}
|
||||
|
||||
pub async fn client_changed(_iota_id: i64, user_id: i64, state: UserStatus) {
|
||||
let msg_type = match state {
|
||||
UserStatus::iota_offline => Some(CommunicationType::user_disconnected),
|
||||
|
|
@ -396,25 +169,28 @@ impl OmegaConnection {
|
|||
|
||||
if let Some(t) = msg_type {
|
||||
let cv =
|
||||
CommunicationValue::new(t).add_data(DataTypes::user_id, JsonValue::from(user_id));
|
||||
CommunicationValue::new(t).add_data(DataTypes::user_id, DataValue::Number(user_id));
|
||||
OmegaConnection::send_global(cv).await;
|
||||
}
|
||||
}
|
||||
async fn send_global(cv: CommunicationValue) {
|
||||
OMEGA_CONNECTION.send(&cv).await;
|
||||
}
|
||||
|
||||
pub async fn user_states(user_id: i64, user_ids: Vec<i64>) {
|
||||
let user_ids_str = user_ids
|
||||
.iter()
|
||||
.map(|id| id.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
.map(|id| DataValue::Number(*id))
|
||||
.collect::<Vec<_>>();
|
||||
let cv = CommunicationValue::new(CommunicationType::get_states)
|
||||
.add_data(DataTypes::user_ids, JsonValue::from(user_ids_str));
|
||||
.add_data(DataTypes::user_ids, DataValue::Array(user_ids_str));
|
||||
let msg_id = cv.get_id();
|
||||
|
||||
WAITING_TASKS.insert(
|
||||
WAITING.insert(
|
||||
msg_id,
|
||||
WaitingTask {
|
||||
task: Box::new(
|
||||
(
|
||||
Instant::now(),
|
||||
Box::new(
|
||||
move |_: Arc<OmegaConnection>, response: CommunicationValue| {
|
||||
tokio::spawn(async move {
|
||||
let rho = rho_manager::get_rho_con_for_user(user_id).await;
|
||||
|
|
@ -427,84 +203,9 @@ impl OmegaConnection {
|
|||
true
|
||||
},
|
||||
),
|
||||
inserted_at: Instant::now(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
OmegaConnection::send_global(cv).await;
|
||||
}
|
||||
|
||||
async fn send_global(cv: CommunicationValue) {
|
||||
OMEGA_CONNECTION.send_message(&cv).await;
|
||||
}
|
||||
|
||||
pub async fn await_connection(&self, timeout_duration: Option<Duration>) -> Result<(), String> {
|
||||
if *self.state.read().await == ConnectionState::Connected {
|
||||
return Ok(());
|
||||
}
|
||||
let timeout = timeout_duration.unwrap_or(Duration::from_secs(10));
|
||||
|
||||
let start = Instant::now();
|
||||
loop {
|
||||
if *self.state.read().await == ConnectionState::Connected {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if start.elapsed() >= timeout {
|
||||
return Err(format!(
|
||||
"Connection not established within {} seconds",
|
||||
timeout.as_secs()
|
||||
));
|
||||
}
|
||||
|
||||
sleep(Duration::from_millis(100)).await; // short interval polling
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn await_response(
|
||||
&self,
|
||||
cv: &CommunicationValue,
|
||||
timeout_duration: Option<Duration>,
|
||||
) -> Result<CommunicationValue, String> {
|
||||
self.await_connection(timeout_duration).await?;
|
||||
let (tx, mut rx) = mpsc::channel(1);
|
||||
let msg_id = cv.get_id();
|
||||
|
||||
let task_tx = tx.clone();
|
||||
WAITING_TASKS.insert(
|
||||
msg_id,
|
||||
WaitingTask {
|
||||
task: Box::new(move |_, response_cv| {
|
||||
let inner_tx = task_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
if inner_tx.send(response_cv).await.is_err() {
|
||||
log_err!(
|
||||
0,
|
||||
PrintType::Omega,
|
||||
"Failed to send response back to awaiter",
|
||||
);
|
||||
}
|
||||
});
|
||||
true
|
||||
}),
|
||||
inserted_at: Instant::now(),
|
||||
},
|
||||
);
|
||||
|
||||
self.send_message(cv).await;
|
||||
|
||||
let timeout = timeout_duration.unwrap_or(Duration::from_secs(10));
|
||||
|
||||
match tokio::time::timeout(timeout, rx.recv()).await {
|
||||
Ok(Some(response_cv)) => Ok(response_cv),
|
||||
Ok(_) => Err("Failed to receive response, channel was closed.".to_string()),
|
||||
Err(_) => {
|
||||
WAITING_TASKS.remove(&msg_id);
|
||||
Err(format!(
|
||||
"Request timed out after {} seconds.",
|
||||
timeout.as_secs()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||
use crate::omega::omega_connection::OmegaConnection;
|
||||
use json::number::Number;
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue, rand_u32};
|
||||
use std::time::Duration;
|
||||
use tokio::time::Instant;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::omega::omega_connection::OmegaConnection;
|
||||
|
||||
const PING_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
impl OmegaConnection {
|
||||
pub async fn send_ping(&self) {
|
||||
let uuid = Uuid::new_v4();
|
||||
let id = rand_u32();
|
||||
let send_time = Instant::now();
|
||||
|
||||
let mut message_send_times = self.message_send_times.lock().await;
|
||||
message_send_times.retain(|_uuid, time| time.elapsed() < PING_TIMEOUT);
|
||||
message_send_times.insert(uuid, send_time);
|
||||
message_send_times.insert(id as i64, send_time);
|
||||
|
||||
self.send_ping_message(uuid).await;
|
||||
self.send_ping_message(id).await;
|
||||
}
|
||||
|
||||
pub async fn send_ping_message(&self, uuid: Uuid) {
|
||||
pub async fn send_ping_message(&self, id: u32) {
|
||||
let ping_message = CommunicationValue::new(CommunicationType::ping)
|
||||
.with_id(uuid)
|
||||
.add_data_num(
|
||||
.with_id(id)
|
||||
.add_data(
|
||||
DataTypes::last_ping,
|
||||
Number::from(*self.last_ping.lock().await),
|
||||
DataValue::Number(self.last_ping.lock().await.unwrap()),
|
||||
);
|
||||
|
||||
self.send_message(&ping_message).await;
|
||||
|
|
@ -34,7 +33,7 @@ impl OmegaConnection {
|
|||
pub async fn handle_pong(&self, cv: &CommunicationValue, _log: bool) {
|
||||
let id = cv.get_id();
|
||||
let mut message_send_times = self.message_send_times.lock().await;
|
||||
if let Some(send_time) = message_send_times.remove(&id) {
|
||||
if let Some(send_time) = message_send_times.remove(&(id as i64)) {
|
||||
let ping = Instant::now().duration_since(send_time).as_millis() as i64;
|
||||
*self.last_ping.lock().await = ping;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,24 @@
|
|||
use async_tungstenite::tungstenite::Message;
|
||||
use async_tungstenite::{WebSocketReceiver, WebSocketSender};
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use json::JsonValue;
|
||||
use json::number::Number;
|
||||
use rand::Rng;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use sysinfo::System;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_util::compat::Compat;
|
||||
use tungstenite::Utf8Bytes;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{rho_connection::RhoConnection, rho_manager};
|
||||
use crate::anonymous_clients::anonymous_manager;
|
||||
use crate::calls::{call_manager, call_util};
|
||||
use crate::omega::omega_connection::get_omega_connection;
|
||||
use crate::util::crypto_helper::{load_public_key, public_key_to_base64};
|
||||
use crate::util::crypto_util::{DataFormat, SecurePayload};
|
||||
use crate::rho::connection::GeneralConnection;
|
||||
use crate::rho::{rho_connection::RhoConnection, rho_manager};
|
||||
use crate::util::logger::PrintType;
|
||||
use crate::{
|
||||
data::{
|
||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||
user::UserStatus,
|
||||
},
|
||||
omega::omega_connection::OmegaConnection,
|
||||
};
|
||||
use crate::{get_private_key, get_public_key, log_cv_in, log_in, log_out};
|
||||
use crate::{data::user::UserStatus, omega::omega_connection::OmegaConnection};
|
||||
use crate::{log_cv_in, log_cv_out, log_out};
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
use epsilon_native::{Receiver, Sender};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct ClientConnection {
|
||||
pub sender: Arc<RwLock<WebSocketSender<Compat<tokio::net::TcpStream>>>>,
|
||||
pub receiver: Arc<RwLock<WebSocketReceiver<Compat<tokio::net::TcpStream>>>>,
|
||||
pub user_id: Arc<RwLock<i64>>,
|
||||
identified: Arc<RwLock<bool>>,
|
||||
challenged: Arc<RwLock<bool>>,
|
||||
challenge: Arc<RwLock<String>>,
|
||||
pub user_id: u64,
|
||||
|
||||
pub sender: Arc<Sender>,
|
||||
pub receiver: Arc<Receiver>,
|
||||
pub ping: Arc<RwLock<i64>>,
|
||||
pub_key: Arc<RwLock<Option<Vec<u8>>>>,
|
||||
pub rho_connection: Arc<RwLock<Option<Arc<RhoConnection>>>>,
|
||||
|
|
@ -46,34 +27,30 @@ pub struct ClientConnection {
|
|||
}
|
||||
|
||||
impl ClientConnection {
|
||||
/// Create a new ClientConnection
|
||||
pub fn new(
|
||||
sender: WebSocketSender<Compat<tokio::net::TcpStream>>,
|
||||
receiver: WebSocketReceiver<Compat<tokio::net::TcpStream>>,
|
||||
) -> Arc<Self> {
|
||||
pub async fn from_general(general: Arc<GeneralConnection>, user_id: u64) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
sender: Arc::new(RwLock::new(sender)),
|
||||
receiver: Arc::new(RwLock::new(receiver)),
|
||||
user_id: Arc::new(RwLock::new(0)),
|
||||
identified: Arc::new(RwLock::new(false)),
|
||||
challenged: Arc::new(RwLock::new(false)),
|
||||
challenge: Arc::new(RwLock::new(String::new())),
|
||||
ping: Arc::new(RwLock::new(-1)),
|
||||
ping: Arc::new(RwLock::new(0)),
|
||||
pub_key: Arc::new(RwLock::new(None)),
|
||||
rho_connection: Arc::new(RwLock::new(None)),
|
||||
interested_users: Arc::new(RwLock::new(Vec::new())),
|
||||
is_open: Arc::new(RwLock::new(true)),
|
||||
sender: general.sender.clone(),
|
||||
receiver: general.receiver.clone(),
|
||||
user_id: user_id,
|
||||
})
|
||||
}
|
||||
pub fn start(self: Arc<Self>) {
|
||||
let self_clone = self.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(cv) = self_clone.receiver.receive().await {
|
||||
self_clone.clone().handle_message(cv).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the user ID
|
||||
pub async fn get_user_id(&self) -> i64 {
|
||||
*self.user_id.read().await
|
||||
}
|
||||
|
||||
/// Check if connection is identified
|
||||
pub async fn is_identified(&self) -> bool {
|
||||
*self.identified.read().await
|
||||
pub async fn get_user_id(&self) -> u64 {
|
||||
self.user_id
|
||||
}
|
||||
|
||||
/// Get current ping
|
||||
|
|
@ -86,211 +63,30 @@ impl ClientConnection {
|
|||
self.rho_connection.read().await.clone()
|
||||
}
|
||||
|
||||
/// Send a string message to the client
|
||||
pub async fn send_message_str(self: Arc<Self>, message: &str) {
|
||||
let mut session = self.sender.write().await;
|
||||
if let Err(e) = session
|
||||
.send(Message::Text(Utf8Bytes::from(message.to_string())))
|
||||
.await
|
||||
{
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Failed to send message to client: {}",
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a CommunicationValue to the client
|
||||
pub async fn send_message(self: Arc<Self>, cv: &CommunicationValue) {
|
||||
if !*self.is_open.read().await {
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
self.user_id as i64,
|
||||
PrintType::Client,
|
||||
"Attempted to send message to a closed connection."
|
||||
);
|
||||
return;
|
||||
}
|
||||
if !cv.is_type(CommunicationType::pong) && !cv.is_type(CommunicationType::ping) {
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"{}",
|
||||
&cv.to_json().to_string()
|
||||
);
|
||||
log_cv_out!(PrintType::Client, &cv);
|
||||
}
|
||||
self.send_message_str(&cv.to_json().to_string()).await;
|
||||
self.sender.send(&cv).await;
|
||||
}
|
||||
|
||||
/// Handle incoming message from client
|
||||
pub async fn handle_message(self: Arc<Self>, message: Utf8Bytes) {
|
||||
pub async fn handle_message(self: Arc<Self>, cv: CommunicationValue) {
|
||||
tokio::spawn(async move {
|
||||
let cv = CommunicationValue::from_json(&message);
|
||||
if cv.is_type(CommunicationType::ping) {
|
||||
self.handle_ping(cv).await;
|
||||
return;
|
||||
}
|
||||
log_cv_in!(PrintType::Client, cv);
|
||||
let identified = *self.identified.read().await;
|
||||
let challenged = *self.challenged.read().await;
|
||||
|
||||
// Handle identification
|
||||
if !identified && cv.is_type(CommunicationType::identification) {
|
||||
let user_id = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(0);
|
||||
if user_id == 0 {
|
||||
log_out!(
|
||||
self.get_user_id().await,
|
||||
PrintType::Client,
|
||||
"Invalid USER ID"
|
||||
);
|
||||
self.clone()
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_invalid_data)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
*self.user_id.write().await = user_id;
|
||||
|
||||
let get_pub_key_msg = CommunicationValue::new(CommunicationType::get_user_data)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::user_id, JsonValue::from(user_id));
|
||||
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(&get_pub_key_msg, Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
|
||||
if let Ok(response_cv) = response_cv {
|
||||
if !response_cv.is_type(CommunicationType::get_user_data) {
|
||||
self.clone()
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
let base64_pub = response_cv
|
||||
.get_data(DataTypes::public_key)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let pub_key = match load_public_key(base64_pub) {
|
||||
Some(pk) => pk,
|
||||
_ => {
|
||||
self.clone()
|
||||
.send_error_response(
|
||||
&cv.get_id(),
|
||||
CommunicationType::error_invalid_public_key,
|
||||
)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
*self.pub_key.write().await = Some(pub_key.as_bytes().to_vec());
|
||||
|
||||
let challenge: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
*self.challenge.write().await = challenge.clone();
|
||||
|
||||
let encrypted_challenge =
|
||||
SecurePayload::new(&challenge, DataFormat::Raw, get_private_key())
|
||||
.unwrap()
|
||||
.encrypt_x448(pub_key)
|
||||
.unwrap()
|
||||
.export(DataFormat::Base64);
|
||||
|
||||
*self.identified.write().await = true;
|
||||
|
||||
let challenge_msg = CommunicationValue::new(CommunicationType::challenge)
|
||||
.with_id(cv.get_id())
|
||||
.add_data_str(
|
||||
DataTypes::public_key,
|
||||
public_key_to_base64(&get_public_key()),
|
||||
)
|
||||
.add_data_str(DataTypes::challenge, encrypted_challenge);
|
||||
|
||||
self.send_message(&challenge_msg).await;
|
||||
} else {
|
||||
self.clone()
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if identified && !challenged && cv.is_type(CommunicationType::challenge_response) {
|
||||
let client_response = cv
|
||||
.get_data(DataTypes::challenge)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let debase64d = STANDARD.decode(&client_response).unwrap();
|
||||
if String::from_utf8(debase64d.clone()).unwrap() == *self.challenge.read().await {
|
||||
*self.challenged.write().await = true;
|
||||
|
||||
let user_id = self.get_user_id().await;
|
||||
|
||||
let rho_connection = match rho_manager::get_rho_con_for_user(user_id).await {
|
||||
Some(rho) => rho,
|
||||
_ => {
|
||||
self.send_error_response(
|
||||
&cv.get_id(),
|
||||
CommunicationType::error_no_iota,
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
rho_connection.add_client_connection(self.clone()).await;
|
||||
|
||||
// Set identification data
|
||||
{
|
||||
let mut user_id_guard = self.user_id.write().await;
|
||||
*user_id_guard = user_id;
|
||||
}
|
||||
{
|
||||
let mut identified_guard = self.identified.write().await;
|
||||
*identified_guard = true;
|
||||
}
|
||||
*self.rho_connection.write().await = Some(Arc::clone(&rho_connection));
|
||||
|
||||
let response =
|
||||
CommunicationValue::new(CommunicationType::identification_response)
|
||||
.with_id(cv.get_id());
|
||||
self.send_message(&response).await;
|
||||
} else {
|
||||
self.clone()
|
||||
.send_error_response(
|
||||
&cv.get_id(),
|
||||
CommunicationType::error_not_authenticated,
|
||||
)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.is_identified().await {
|
||||
self.clone()
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_not_authenticated)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle client status changes
|
||||
if cv.is_type(CommunicationType::client_changed) {
|
||||
|
|
@ -326,17 +122,9 @@ impl ClientConnection {
|
|||
}
|
||||
if cv.is_type(CommunicationType::get_user_data) {
|
||||
if let Some(anonymous) = {
|
||||
if let Some(user_id) = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
{
|
||||
anonymous_manager::get_anonymous_user(user_id).await
|
||||
} else if let Some(username) = cv
|
||||
.get_data(DataTypes::username)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
{
|
||||
if let Some(user_id) = cv.get_data(DataTypes::user_id).as_number() {
|
||||
anonymous_manager::get_anonymous_user(user_id as u64).await
|
||||
} else if let Some(username) = cv.get_data(DataTypes::username).as_str() {
|
||||
anonymous_manager::get_anonymous_user_by_name(username.to_string()).await
|
||||
} else {
|
||||
None
|
||||
|
|
@ -344,14 +132,23 @@ impl ClientConnection {
|
|||
} {
|
||||
let response = CommunicationValue::new(CommunicationType::get_user_data)
|
||||
.with_id(cv.get_id())
|
||||
.add_data_str(DataTypes::username, anonymous.get_user_name().await)
|
||||
.add_data(
|
||||
DataTypes::username,
|
||||
DataValue::Str(anonymous.get_user_name().await),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::user_id,
|
||||
JsonValue::Number(Number::from(anonymous.get_user_id().await)),
|
||||
DataValue::Number(anonymous.get_user_id() as i64),
|
||||
)
|
||||
.add_data_str(DataTypes::display, anonymous.get_display_name().await)
|
||||
.add_data_str(DataTypes::user_state, "online".to_string())
|
||||
.add_data_str(DataTypes::avatar, anonymous.get_avatar().await);
|
||||
.add_data(
|
||||
DataTypes::display,
|
||||
DataValue::Str(anonymous.get_display_name().await),
|
||||
)
|
||||
.add_data(
|
||||
DataTypes::avatar,
|
||||
DataValue::Str(anonymous.get_avatar().await),
|
||||
)
|
||||
.add_data(DataTypes::user_state, DataValue::Str("online".to_string()));
|
||||
|
||||
self.send_message(&response).await;
|
||||
|
||||
|
|
@ -367,7 +164,8 @@ impl ClientConnection {
|
|||
|| cv.is_type(CommunicationType::delete_user)
|
||||
{
|
||||
let sender = self.get_user_id().await;
|
||||
self.handle_omega_forward(cv.with_sender(sender)).await;
|
||||
self.handle_omega_forward(cv.with_sender(sender as u64))
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
// Forward other messages to Iota
|
||||
|
|
@ -378,10 +176,7 @@ impl ClientConnection {
|
|||
let client_for_closure = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&cv.with_sender(*self.user_id.read().await),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await_response(&cv.with_sender(self.user_id), Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
if let Ok(response_cv) = response_cv {
|
||||
client_for_closure.send_message(&response_cv).await;
|
||||
|
|
@ -392,13 +187,13 @@ impl ClientConnection {
|
|||
/// Handle ping message
|
||||
async fn handle_ping(self: Arc<Self>, cv: CommunicationValue) {
|
||||
// Update our ping if provided
|
||||
if let Some(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
if let DataValue::Number(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
let current = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
let mut ping_guard = self.ping.write().await;
|
||||
*ping_guard = current as i64 - last_ping.as_i64().unwrap();
|
||||
*ping_guard = current as i64 - last_ping;
|
||||
}
|
||||
|
||||
// Get Iota ping from RhoConnection
|
||||
|
|
@ -411,7 +206,7 @@ impl ClientConnection {
|
|||
// Send pong response
|
||||
let response = CommunicationValue::new(CommunicationType::pong)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::ping_iota, JsonValue::from(iota_ping));
|
||||
.add_data(DataTypes::ping_iota, DataValue::Number(iota_ping));
|
||||
|
||||
self.send_message(&response).await;
|
||||
}
|
||||
|
|
@ -419,51 +214,47 @@ impl ClientConnection {
|
|||
/// Handle client status change
|
||||
async fn handle_client_changed(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let user_id = self.get_user_id().await;
|
||||
if let Some(_status_str) = cv.get_data(DataTypes::user_state) {
|
||||
if let DataValue::Str(_status_str) = cv.get_data(DataTypes::user_state) {
|
||||
let user_status = UserStatus::user_online;
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
OmegaConnection::client_changed(rho_conn.get_iota_id().await, user_id, user_status)
|
||||
.await;
|
||||
OmegaConnection::client_changed(
|
||||
rho_conn.get_iota_id().await as i64,
|
||||
user_id as i64,
|
||||
user_status,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle call invite
|
||||
async fn handle_call_invite(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let receiver_id: i64 = cv
|
||||
.get_data(DataTypes::receiver_id)
|
||||
.unwrap_or(&json::JsonValue::Number(Number::from(0)))
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let receiver_id: i64 = cv.get_data(DataTypes::receiver_id).as_number().unwrap_or(0);
|
||||
if receiver_id == 0 {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_no_user_id)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error_no_user_id)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let call_id = match cv.get_data(DataTypes::call_id) {
|
||||
Some(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
DataValue::Str(id_str) => match Uuid::parse_str(id_str.as_str()) {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
self.send_error_response(
|
||||
&cv.get_id(),
|
||||
CommunicationType::error_invalid_call_id,
|
||||
)
|
||||
.await;
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error_invalid_call_id)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_no_call_id)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error_no_call_id)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let invited =
|
||||
call_manager::add_invite(call_id, *self.user_id.read().await, receiver_id).await;
|
||||
let invited = call_manager::add_invite(call_id, self.user_id, receiver_id as u64).await;
|
||||
if !invited {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_call_id)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error_invalid_call_id)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -472,7 +263,7 @@ impl ClientConnection {
|
|||
let target_rho = match rho_manager::get_rho_con_for_user(receiver_id).await {
|
||||
Some(rho) => rho,
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -483,11 +274,14 @@ impl ClientConnection {
|
|||
|
||||
// Create and send call distribution message
|
||||
let forward = CommunicationValue::new(CommunicationType::call_invite)
|
||||
.with_receiver(receiver_id)
|
||||
.with_sender(sender_id)
|
||||
.add_data_str(DataTypes::call_id, call_id.to_string())
|
||||
.add_data_str(DataTypes::receiver_id, receiver_id.to_string())
|
||||
.add_data_str(DataTypes::sender_id, sender_id.to_string());
|
||||
.with_receiver(receiver_id as u64)
|
||||
.with_sender(sender_id as u64)
|
||||
.add_data(DataTypes::call_id, DataValue::Str(call_id.to_string()))
|
||||
.add_data(
|
||||
DataTypes::receiver_id,
|
||||
DataValue::Str(receiver_id.to_string()),
|
||||
)
|
||||
.add_data(DataTypes::sender_id, DataValue::Str(sender_id.to_string()));
|
||||
|
||||
target_rho.message_to_client(forward).await;
|
||||
|
||||
|
|
@ -500,16 +294,16 @@ impl ClientConnection {
|
|||
let user_id = self.get_user_id().await;
|
||||
|
||||
let call_id = match cv.get_data(DataTypes::call_id) {
|
||||
Some(id_str) => match Uuid::parse_str(&id_str.to_string()) {
|
||||
DataValue::Str(id_str) => match Uuid::parse_str(id_str.as_str()) {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -518,33 +312,20 @@ impl ClientConnection {
|
|||
if let Some(token) = call_manager::get_call_token(user_id, call_id).await {
|
||||
let response = CommunicationValue::new(CommunicationType::call_token)
|
||||
.with_id(cv.get_id())
|
||||
.with_receiver(user_id)
|
||||
.add_data_str(DataTypes::call_token, token);
|
||||
.with_receiver(user_id as u64)
|
||||
.add_data(DataTypes::call_token, DataValue::Str(token));
|
||||
self.send_message(&response).await;
|
||||
} else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
async fn handle_call_timeout_user(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let call_id = Uuid::from_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap();
|
||||
let user_id = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let untill = cv
|
||||
.get_data(DataTypes::untill)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let call_id =
|
||||
Uuid::from_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or("")).unwrap();
|
||||
let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0);
|
||||
let untill = cv.get_data(DataTypes::untill).as_number().unwrap_or(0);
|
||||
|
||||
let call = call_manager::get_call(call_id).await;
|
||||
if let Some(call) = call {
|
||||
|
|
@ -554,8 +335,8 @@ impl ClientConnection {
|
|||
.unwrap()
|
||||
.has_admin()
|
||||
{
|
||||
let _ = call_util::remove_participant(call_id, user_id).await;
|
||||
call.get_caller(user_id)
|
||||
let _ = call_util::remove_participant(call_id, user_id as u64).await;
|
||||
call.get_caller(user_id as u64)
|
||||
.await
|
||||
.unwrap()
|
||||
.set_timeout(untill)
|
||||
|
|
@ -564,18 +345,9 @@ impl ClientConnection {
|
|||
}
|
||||
}
|
||||
async fn handle_call_disconnect_user(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let call_id = Uuid::from_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap();
|
||||
let user_id = cv
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_i64()
|
||||
.unwrap_or(0);
|
||||
let call_id =
|
||||
Uuid::from_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or("")).unwrap();
|
||||
let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0);
|
||||
|
||||
let call = call_manager::get_call(call_id).await;
|
||||
if let Some(call) = call {
|
||||
|
|
@ -585,23 +357,14 @@ impl ClientConnection {
|
|||
.unwrap()
|
||||
.has_admin()
|
||||
{
|
||||
call.remove_caller(user_id).await;
|
||||
call.remove_caller(user_id as u64).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn handle_call_set_anonymous_joining(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let call_id = Uuid::from_str(
|
||||
cv.get_data(DataTypes::call_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or(""),
|
||||
)
|
||||
.unwrap();
|
||||
let enable = cv
|
||||
.get_data(DataTypes::enabled)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_bool()
|
||||
.unwrap_or(true);
|
||||
let call_id =
|
||||
Uuid::from_str(cv.get_data(DataTypes::call_id).as_str().unwrap_or("")).unwrap();
|
||||
let enable = cv.get_data(DataTypes::enabled).as_bool().unwrap_or(true);
|
||||
|
||||
let call = call_manager::get_call(call_id).await;
|
||||
|
||||
|
|
@ -620,10 +383,10 @@ impl ClientConnection {
|
|||
let mut response_cv =
|
||||
CommunicationValue::new(CommunicationType::call_set_anonymous_joining)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::call_id, JsonValue::String(call_id.to_string()))
|
||||
.add_data(DataTypes::enabled, JsonValue::Boolean(enable));
|
||||
.add_data(DataTypes::call_id, DataValue::Str(call_id.to_string()))
|
||||
.add_data(DataTypes::enabled, DataValue::Bool(enable));
|
||||
if let Some(short_link) = short_link {
|
||||
response_cv = response_cv.add_data(DataTypes::link, JsonValue::String(short_link));
|
||||
response_cv = response_cv.add_data(DataTypes::link, DataValue::Str(short_link));
|
||||
}
|
||||
self.send_message(&response_cv).await;
|
||||
}
|
||||
|
|
@ -631,11 +394,13 @@ impl ClientConnection {
|
|||
/// Forward message to Iota
|
||||
async fn forward_to_iota(self: Arc<Self>, cv: CommunicationValue) {
|
||||
if cv.is_type(CommunicationType::add_conversation)
|
||||
&& cv.get_data(DataTypes::chat_partner_id).is_none()
|
||||
&& cv
|
||||
.get_data(DataTypes::chat_partner_id)
|
||||
.as_number()
|
||||
.is_some()
|
||||
{
|
||||
let chat_partner_name = cv
|
||||
.get_data(DataTypes::chat_partner_name)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.as_str()
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
|
|
@ -644,7 +409,7 @@ impl ClientConnection {
|
|||
.await
|
||||
.is_some()
|
||||
{
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_anonymous)
|
||||
self.send_error_response(cv.get_id(), CommunicationType::error_anonymous)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -655,25 +420,22 @@ impl ClientConnection {
|
|||
.with_id(cv.clone().get_id())
|
||||
.add_data(
|
||||
DataTypes::username,
|
||||
JsonValue::from(chat_partner_name.clone()),
|
||||
DataValue::Str(chat_partner_name.clone()),
|
||||
),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await;
|
||||
let chat_partner_id = {
|
||||
if let Ok(load_uuid_response) = load_uuid_response {
|
||||
load_uuid_response
|
||||
.get_data(DataTypes::user_id)
|
||||
.unwrap_or(&JsonValue::Null)
|
||||
.clone()
|
||||
load_uuid_response.get_data(DataTypes::user_id).clone()
|
||||
} else {
|
||||
JsonValue::Null
|
||||
DataValue::Null
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
let updated_cv = cv
|
||||
.with_sender(self.get_user_id().await)
|
||||
.with_sender(self.get_user_id().await as u64)
|
||||
.add_data(DataTypes::chat_partner_id, chat_partner_id);
|
||||
rho_conn.message_to_iota(updated_cv).await;
|
||||
}
|
||||
|
|
@ -681,18 +443,14 @@ impl ClientConnection {
|
|||
}
|
||||
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
let updated_cv = cv.with_sender(self.get_user_id().await);
|
||||
let updated_cv = cv.with_sender(self.get_user_id().await as u64);
|
||||
rho_conn.message_to_iota(updated_cv).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Send error response
|
||||
async fn send_error_response(
|
||||
self: Arc<Self>,
|
||||
message_id: &Uuid,
|
||||
error_type: CommunicationType,
|
||||
) {
|
||||
let error = CommunicationValue::new(error_type).with_id(*message_id);
|
||||
async fn send_error_response(self: Arc<Self>, message_id: u32, error_type: CommunicationType) {
|
||||
let error = CommunicationValue::new(error_type).with_id(message_id);
|
||||
self.send_message(&error).await;
|
||||
}
|
||||
|
||||
|
|
@ -704,8 +462,7 @@ impl ClientConnection {
|
|||
}
|
||||
*is_open_guard = false;
|
||||
|
||||
let mut session = self.sender.write().await;
|
||||
let _ = session.close(None).await;
|
||||
let _ = self.sender.close();
|
||||
}
|
||||
|
||||
/// Set interested users list
|
||||
|
|
@ -723,8 +480,8 @@ impl ClientConnection {
|
|||
let interested_guard = self.clone().get_interested_users().await;
|
||||
if interested_guard.contains(&user_id) {
|
||||
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
||||
.add_data_str(DataTypes::user_id, user_id.to_string())
|
||||
.add_data_str(DataTypes::user_state, format!("online"));
|
||||
.add_data(DataTypes::user_id, DataValue::Str(user_id.to_string()))
|
||||
.add_data(DataTypes::user_state, DataValue::Str("online".to_string()));
|
||||
|
||||
self.send_message(¬ification).await;
|
||||
}
|
||||
|
|
@ -732,13 +489,11 @@ impl ClientConnection {
|
|||
|
||||
/// Handle connection close
|
||||
pub async fn handle_close(&self) {
|
||||
if self.is_identified().await {
|
||||
let user_id = self.get_user_id().await;
|
||||
if let Some(rho_conn) = rho_manager::get_rho_con_for_user(user_id).await {
|
||||
rho_conn
|
||||
.close_client_connection(Arc::new(self.clone()))
|
||||
.await;
|
||||
}
|
||||
let user_id = self.get_user_id().await;
|
||||
if let Some(rho_conn) = rho_manager::get_rho_con_for_user(user_id as i64).await {
|
||||
rho_conn
|
||||
.close_client_connection(Arc::new(self.clone()))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -749,10 +504,7 @@ impl Clone for ClientConnection {
|
|||
Self {
|
||||
sender: Arc::clone(&self.sender),
|
||||
receiver: Arc::clone(&self.receiver),
|
||||
user_id: Arc::clone(&self.user_id),
|
||||
identified: Arc::clone(&self.identified),
|
||||
challenged: Arc::clone(&self.challenged),
|
||||
challenge: Arc::clone(&self.challenge),
|
||||
user_id: self.user_id,
|
||||
ping: Arc::clone(&self.ping),
|
||||
pub_key: Arc::clone(&self.pub_key),
|
||||
rho_connection: Arc::clone(&self.rho_connection),
|
||||
|
|
|
|||
174
src/rho/connection.rs
Normal file
174
src/rho/connection.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
use epsilon_native::{Receiver, Sender};
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::{
|
||||
anonymous_clients::anonymous_client_connection::AnonymousClientConnection,
|
||||
get_private_key, get_public_key,
|
||||
omega::omega_connection::get_omega_connection,
|
||||
rho::{client_connection::ClientConnection, iota_connection::IotaConnection},
|
||||
util::{
|
||||
crypto_helper::{load_public_key, public_key_to_base64},
|
||||
crypto_util::{DataFormat, SecurePayload},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ConnectionKind {
|
||||
Client,
|
||||
Iota,
|
||||
AnonymousClient,
|
||||
Phi,
|
||||
}
|
||||
|
||||
pub struct GeneralConnection {
|
||||
pub sender: Arc<Sender>,
|
||||
pub receiver: Arc<Receiver>,
|
||||
|
||||
identified: Arc<RwLock<bool>>,
|
||||
challenged: Arc<RwLock<bool>>,
|
||||
challenge: Arc<RwLock<String>>,
|
||||
|
||||
connection_kind: Arc<RwLock<Option<ConnectionKind>>>,
|
||||
id: Arc<RwLock<u64>>,
|
||||
|
||||
pub_key: Arc<RwLock<Option<Vec<u8>>>>,
|
||||
}
|
||||
impl GeneralConnection {
|
||||
pub fn new(sender: Sender, receiver: Receiver) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
sender: Arc::new(sender),
|
||||
receiver: Arc::new(receiver),
|
||||
identified: Arc::new(RwLock::new(false)),
|
||||
challenged: Arc::new(RwLock::new(false)),
|
||||
challenge: Arc::new(RwLock::new(String::new())),
|
||||
connection_kind: Arc::new(RwLock::new(None)),
|
||||
id: Arc::new(RwLock::new(0)),
|
||||
pub_key: Arc::new(RwLock::new(None)),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl GeneralConnection {
|
||||
pub async fn handle(self: Arc<Self>) {
|
||||
loop {
|
||||
let cv = match self.receiver.receive().await {
|
||||
Ok(v) => v,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
if !*self.identified.read().await {
|
||||
self.handle_identification(cv).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !*self.challenged.read().await {
|
||||
self.handle_challenge_response(cv).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.migrate().await {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn handle_identification(self: &Arc<Self>, cv: CommunicationValue) {
|
||||
if !cv.is_type(CommunicationType::identification) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let DataValue::Number(iota_id) = cv.get_data(DataTypes::iota_id) {
|
||||
*self.id.write().await = *iota_id as u64;
|
||||
*self.connection_kind.write().await = Some(ConnectionKind::Iota);
|
||||
|
||||
let get_pub_key_msg = CommunicationValue::new(CommunicationType::get_iota_data)
|
||||
.add_data(DataTypes::iota_id, DataValue::Number(*iota_id));
|
||||
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(&get_pub_key_msg, Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
|
||||
let response_cv = match response_cv {
|
||||
Ok(r) => r,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let base64_pub = response_cv
|
||||
.get_data(DataTypes::public_key)
|
||||
.as_str()
|
||||
.unwrap_or("");
|
||||
|
||||
let pub_key = match load_public_key(base64_pub) {
|
||||
Some(pk) => pk,
|
||||
None => return,
|
||||
};
|
||||
|
||||
*self.pub_key.write().await = Some(pub_key.as_bytes().to_vec());
|
||||
|
||||
let challenge: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
*self.challenge.write().await = challenge.clone();
|
||||
*self.identified.write().await = true;
|
||||
|
||||
let encrypted_challenge =
|
||||
SecurePayload::new(&challenge, DataFormat::Base64, get_private_key())
|
||||
.unwrap()
|
||||
.encrypt_x448(pub_key)
|
||||
.unwrap()
|
||||
.export(DataFormat::Base64);
|
||||
|
||||
let response = CommunicationValue::new(CommunicationType::challenge)
|
||||
.add_data(
|
||||
DataTypes::public_key,
|
||||
DataValue::Str(public_key_to_base64(&get_public_key())),
|
||||
)
|
||||
.add_data(DataTypes::challenge, DataValue::Str(encrypted_challenge));
|
||||
|
||||
let _ = self.sender.send(&response).await;
|
||||
}
|
||||
}
|
||||
async fn handle_challenge_response(self: &Arc<Self>, cv: CommunicationValue) {
|
||||
if !cv.is_type(CommunicationType::challenge_response) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let DataValue::Str(response) = cv.get_data(DataTypes::challenge) {
|
||||
if *response == *self.challenge.read().await {
|
||||
*self.challenged.write().await = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn migrate(self: &Arc<Self>) -> bool {
|
||||
let kind = match *self.connection_kind.read().await {
|
||||
Some(kind) => kind,
|
||||
None => return false,
|
||||
};
|
||||
let id = *self.id.read().await;
|
||||
|
||||
match kind {
|
||||
ConnectionKind::Client => {
|
||||
let client = ClientConnection::from_general(self.clone(), id).await;
|
||||
client.start();
|
||||
}
|
||||
ConnectionKind::Iota => {
|
||||
let iota = IotaConnection::from_general(self.clone(), id).await;
|
||||
iota.start();
|
||||
}
|
||||
ConnectionKind::AnonymousClient => {
|
||||
let client = AnonymousClientConnection::from_general(self.clone(), id).await;
|
||||
client.start();
|
||||
}
|
||||
ConnectionKind::Phi => {
|
||||
let iota = ClientConnection::from_general(self.clone(), id).await;
|
||||
iota.start();
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,18 @@
|
|||
use crate::calls::call_group::CallGroup;
|
||||
use crate::calls::call_manager;
|
||||
use crate::get_private_key;
|
||||
use crate::get_public_key;
|
||||
use crate::log_cv_in;
|
||||
use crate::log_cv_out;
|
||||
use crate::log_err;
|
||||
use crate::log_in;
|
||||
use crate::log_out;
|
||||
use crate::omega::omega_connection::get_omega_connection;
|
||||
use crate::util::crypto_helper::load_public_key;
|
||||
use crate::util::crypto_helper::public_key_to_base64;
|
||||
use crate::util::crypto_util::DataFormat;
|
||||
use crate::util::crypto_util::SecurePayload;
|
||||
use crate::rho::connection::GeneralConnection;
|
||||
use crate::util::logger::PrintType;
|
||||
use async_tungstenite::WebSocketReceiver;
|
||||
use async_tungstenite::WebSocketSender;
|
||||
use async_tungstenite::tungstenite::Message;
|
||||
use dashmap::DashMap;
|
||||
use json::JsonValue;
|
||||
use rand::Rng;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use epsilon_core::CommunicationType;
|
||||
use epsilon_core::CommunicationValue;
|
||||
use epsilon_core::DataTypes;
|
||||
use epsilon_core::DataValue;
|
||||
use epsilon_native::Receiver;
|
||||
use epsilon_native::Sender;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Weak},
|
||||
|
|
@ -26,56 +20,48 @@ use std::{
|
|||
};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_util::compat::Compat;
|
||||
use tungstenite::Utf8Bytes;
|
||||
use uuid::Uuid;
|
||||
use x448::PublicKey;
|
||||
|
||||
use super::{rho_connection::RhoConnection, rho_manager};
|
||||
use crate::{
|
||||
data::communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||
omega::omega_connection::OmegaConnection,
|
||||
};
|
||||
use crate::omega::omega_connection::OmegaConnection;
|
||||
|
||||
pub struct IotaConnection {
|
||||
pub sender: Arc<RwLock<WebSocketSender<Compat<tokio::net::TcpStream>>>>,
|
||||
pub receiver: Arc<RwLock<WebSocketReceiver<Compat<tokio::net::TcpStream>>>>,
|
||||
pub iota_id: Arc<RwLock<i64>>,
|
||||
pub user_ids: Arc<RwLock<Vec<i64>>>,
|
||||
identified: Arc<RwLock<bool>>,
|
||||
challenged: Arc<RwLock<bool>>,
|
||||
challenge: Arc<RwLock<String>>,
|
||||
pub iota_id: u64,
|
||||
pub sender: Arc<Sender>,
|
||||
pub receiver: Arc<Receiver>,
|
||||
pub user_ids: Arc<RwLock<Vec<u64>>>,
|
||||
pub ping: Arc<RwLock<i64>>,
|
||||
pub_key: Arc<RwLock<Option<Vec<u8>>>>,
|
||||
pub waiting_tasks:
|
||||
DashMap<Uuid, Box<dyn Fn(Arc<IotaConnection>, CommunicationValue) -> bool + Send + Sync>>,
|
||||
DashMap<u32, Box<dyn Fn(Arc<IotaConnection>, CommunicationValue) -> bool + Send + Sync>>,
|
||||
pub rho_connection: Arc<RwLock<Option<Weak<RhoConnection>>>>,
|
||||
}
|
||||
|
||||
impl IotaConnection {
|
||||
/// Create a new IotaConnection
|
||||
pub fn new(
|
||||
sender: WebSocketSender<Compat<tokio::net::TcpStream>>,
|
||||
receiver: WebSocketReceiver<Compat<tokio::net::TcpStream>>,
|
||||
) -> Arc<Self> {
|
||||
pub async fn from_general(general: Arc<GeneralConnection>, iota_id: u64) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
sender: Arc::new(RwLock::new(sender)),
|
||||
receiver: Arc::new(RwLock::new(receiver)),
|
||||
iota_id: Arc::new(RwLock::new(0)),
|
||||
user_ids: Arc::new(RwLock::new(Vec::new())),
|
||||
identified: Arc::new(RwLock::new(false)),
|
||||
challenged: Arc::new(RwLock::new(false)),
|
||||
challenge: Arc::new(RwLock::new(String::new())),
|
||||
ping: Arc::new(RwLock::new(0)),
|
||||
pub_key: Arc::new(RwLock::new(None)),
|
||||
waiting_tasks: DashMap::new(),
|
||||
rho_connection: Arc::new(RwLock::new(None)),
|
||||
user_ids: Arc::new(RwLock::new(Vec::new())),
|
||||
sender: general.sender.clone(),
|
||||
receiver: general.receiver.clone(),
|
||||
iota_id: iota_id,
|
||||
waiting_tasks: DashMap::new(),
|
||||
})
|
||||
}
|
||||
pub fn start(self: Arc<Self>) {
|
||||
let self_clone = self.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(cv) = self_clone.receiver.receive().await {
|
||||
self_clone.clone().handle_message(cv).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the Iota ID
|
||||
pub async fn get_iota_id(&self) -> i64 {
|
||||
*self.iota_id.read().await
|
||||
pub async fn get_iota_id(&self) -> u64 {
|
||||
self.iota_id
|
||||
}
|
||||
|
||||
pub async fn get_public_key(&self) -> Option<PublicKey> {
|
||||
|
|
@ -87,15 +73,10 @@ impl IotaConnection {
|
|||
}
|
||||
|
||||
/// Get the user IDs
|
||||
pub async fn get_user_ids(&self) -> Vec<i64> {
|
||||
pub async fn get_user_ids(&self) -> Vec<u64> {
|
||||
self.user_ids.read().await.clone()
|
||||
}
|
||||
|
||||
/// Check if connection is identified
|
||||
pub async fn is_identified(&self) -> bool {
|
||||
*self.identified.read().await
|
||||
}
|
||||
|
||||
/// Get current ping
|
||||
pub async fn get_ping(&self) -> i64 {
|
||||
*self.ping.read().await
|
||||
|
|
@ -117,38 +98,16 @@ impl IotaConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/// Send a message to the Iota
|
||||
pub async fn send_message_str(&self, message: &str) {
|
||||
let mut session = self.sender.write().await;
|
||||
if let Err(e) = session
|
||||
.send(Message::Text(Utf8Bytes::from(message.to_string())))
|
||||
.await
|
||||
{
|
||||
log_err!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::Iota,
|
||||
"Failed to send WebSocket message: {:?}",
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a CommunicationValue to the Iota
|
||||
pub async fn send_message(&self, cv: &CommunicationValue) {
|
||||
if !cv.is_type(CommunicationType::pong) {
|
||||
log_out!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::Iota,
|
||||
"{}",
|
||||
cv.to_json().to_string()
|
||||
);
|
||||
log_cv_out!(PrintType::Iota, cv);
|
||||
}
|
||||
self.send_message_str(&cv.to_json().to_string()).await;
|
||||
self.sender.send(&cv).await;
|
||||
}
|
||||
|
||||
/// Handle incoming message from Iota
|
||||
pub async fn handle_message(self: Arc<Self>, message: Utf8Bytes) {
|
||||
let cv = CommunicationValue::from_json(&message);
|
||||
pub async fn handle_message(self: Arc<Self>, cv: CommunicationValue) {
|
||||
// Handle ping
|
||||
if cv.is_type(CommunicationType::ping) || cv.is_type(CommunicationType::pong) {
|
||||
self.handle_ping(cv).await;
|
||||
|
|
@ -157,261 +116,6 @@ impl IotaConnection {
|
|||
|
||||
log_cv_in!(PrintType::Iota, cv);
|
||||
|
||||
let identified = *self.identified.read().await;
|
||||
let challenged = *self.challenged.read().await;
|
||||
|
||||
if !identified && cv.is_type(CommunicationType::identification) {
|
||||
let iota_id = cv
|
||||
.get_data(DataTypes::iota_id)
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(0);
|
||||
if iota_id == 0 {
|
||||
log_out!(self.get_iota_id().await, PrintType::Iota, "Invalid IOTA ID");
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_data)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
*self.iota_id.write().await = iota_id;
|
||||
|
||||
let get_pub_key_msg = CommunicationValue::new(CommunicationType::get_iota_data)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::iota_id, JsonValue::from(iota_id));
|
||||
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(&get_pub_key_msg, Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
|
||||
if let Ok(response_cv) = response_cv {
|
||||
if !response_cv.is_type(CommunicationType::get_iota_data) {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
let base64_pub = response_cv
|
||||
.get_data(DataTypes::public_key)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let pub_key = match load_public_key(base64_pub) {
|
||||
Some(pk) => pk,
|
||||
_ => {
|
||||
self.send_error_response(
|
||||
&cv.get_id(),
|
||||
CommunicationType::error_invalid_public_key,
|
||||
)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
*self.pub_key.write().await = Some(pub_key.as_bytes().to_vec());
|
||||
|
||||
let challenge: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
*self.challenge.write().await = challenge.clone();
|
||||
|
||||
let encrypted_challenge =
|
||||
SecurePayload::new(&challenge, DataFormat::Base64, get_private_key())
|
||||
.unwrap()
|
||||
.encrypt_x448(pub_key)
|
||||
.unwrap()
|
||||
.export(DataFormat::Base64);
|
||||
|
||||
*self.identified.write().await = true;
|
||||
|
||||
let challenge_msg = CommunicationValue::new(CommunicationType::challenge)
|
||||
.with_id(cv.get_id())
|
||||
.add_data_str(
|
||||
DataTypes::public_key,
|
||||
public_key_to_base64(&get_public_key()),
|
||||
)
|
||||
.add_data_str(DataTypes::challenge, encrypted_challenge);
|
||||
|
||||
self.send_message(&challenge_msg).await;
|
||||
} else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
} else if !identified && cv.is_type(CommunicationType::register_iota) {
|
||||
let base64_pub = cv
|
||||
.get_data(DataTypes::public_key)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if base64_pub.is_empty() {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_public_key)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
let register_msg = CommunicationValue::new(CommunicationType::complete_register_iota)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(
|
||||
DataTypes::public_key,
|
||||
JsonValue::String(base64_pub.to_string()),
|
||||
);
|
||||
|
||||
let iota_conn_clone = self.clone();
|
||||
let register_response: Result<CommunicationValue, _> = get_omega_connection()
|
||||
.await_response(®ister_msg, Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
let iota_conn_for_task = iota_conn_clone.clone();
|
||||
if let Ok(register_response) = register_response {
|
||||
if !register_response.is_type(CommunicationType::complete_register_iota) {
|
||||
iota_conn_for_task
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
iota_conn_for_task.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
let new_iota_id = register_response
|
||||
.get_data(DataTypes::iota_id)
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(0);
|
||||
|
||||
if new_iota_id == 0 {
|
||||
iota_conn_for_task
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
iota_conn_for_task.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
*iota_conn_for_task.iota_id.write().await = new_iota_id;
|
||||
*iota_conn_for_task.identified.write().await = true;
|
||||
|
||||
let success_msg = CommunicationValue::new(CommunicationType::success)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::iota_id, JsonValue::from(new_iota_id));
|
||||
|
||||
iota_conn_for_task.send_message(&success_msg).await;
|
||||
} else {
|
||||
iota_conn_for_task
|
||||
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
|
||||
.await;
|
||||
iota_conn_for_task.close().await;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if identified && !challenged && cv.is_type(CommunicationType::challenge_response) {
|
||||
let client_response = cv
|
||||
.get_data(DataTypes::challenge)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if client_response == *self.challenge.read().await {
|
||||
*self.challenged.write().await = true;
|
||||
|
||||
let iota_id = self.get_iota_id().await;
|
||||
|
||||
if rho_manager::contains_iota(iota_id).await {
|
||||
if let Some(existing_rho) = rho_manager::get_rho_by_iota(iota_id).await {
|
||||
existing_rho.close_iota_connection().await;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform Omega & Verify Users
|
||||
let iota_users_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&CommunicationValue::new(CommunicationType::iota_connected).add_data(
|
||||
DataTypes::iota_id,
|
||||
JsonValue::from(self.get_iota_id().await),
|
||||
),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut user_ids: Vec<i64> = Vec::new();
|
||||
if let Ok(iota_users_cv) = iota_users_cv {
|
||||
if !iota_users_cv.is_type(CommunicationType::iota_user_data) {
|
||||
log_err!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::Omikron,
|
||||
"Invalid communication type {:?}",
|
||||
iota_users_cv.get_type()
|
||||
);
|
||||
return;
|
||||
}
|
||||
let val_user_ids = iota_users_cv.get_data(DataTypes::user_ids).unwrap().clone();
|
||||
|
||||
match val_user_ids {
|
||||
JsonValue::Array(arr) => {
|
||||
for item in arr {
|
||||
if let JsonValue::Number(_) = item {
|
||||
user_ids.push(item.as_i64().unwrap_or(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
log_err!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::Omikron,
|
||||
"Failed to retrieve user IDs"
|
||||
);
|
||||
}
|
||||
log_in!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::General,
|
||||
"User IDs: {:?}",
|
||||
user_ids.clone()
|
||||
);
|
||||
|
||||
*self.user_ids.write().await = user_ids.clone();
|
||||
let rho_connection =
|
||||
Arc::new(RhoConnection::new(self.clone(), user_ids.clone()).await);
|
||||
|
||||
self.set_rho_connection(Arc::downgrade(&rho_connection))
|
||||
.await;
|
||||
|
||||
rho_manager::add_rho(rho_connection).await;
|
||||
|
||||
let mut str = String::new();
|
||||
for id in &user_ids {
|
||||
str.push_str(&format!(",{}", id));
|
||||
}
|
||||
if !str.is_empty() {
|
||||
str.remove(0);
|
||||
}
|
||||
|
||||
self.send_message(
|
||||
&CommunicationValue::new(CommunicationType::identification_response)
|
||||
.with_id(cv.get_id())
|
||||
.add_data_str(DataTypes::accepted_ids, str)
|
||||
.add_data_str(DataTypes::accepted, user_ids.len().to_string()),
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_challenge)
|
||||
.await;
|
||||
self.close().await;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.is_identified().await {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::error_not_authenticated)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
}
|
||||
// Handle GET_CHATS
|
||||
if cv.is_type(CommunicationType::get_chats) {
|
||||
self.handle_get_chats(cv).await;
|
||||
|
|
@ -420,7 +124,7 @@ impl IotaConnection {
|
|||
|
||||
// Handle forwarding to other Iotas or clients
|
||||
let receiver_id = cv.get_receiver();
|
||||
if (receiver_id != 0 && !self.get_user_ids().await.contains(&receiver_id))
|
||||
if (receiver_id != 0 && !self.get_user_ids().await.contains(&(receiver_id as u64)))
|
||||
|| cv.is_type(CommunicationType::message_other_iota)
|
||||
|| cv.is_type(CommunicationType::send_chat)
|
||||
{
|
||||
|
|
@ -437,31 +141,28 @@ impl IotaConnection {
|
|||
|| cv.is_type(CommunicationType::delete_iota)
|
||||
{
|
||||
let sender = self.get_iota_id().await;
|
||||
self.handle_omega_forward(cv.with_sender(sender)).await;
|
||||
self.handle_omega_forward(cv.with_sender(sender as u64))
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
// Forward to client
|
||||
self.forward_to_client(cv).await;
|
||||
}
|
||||
|
||||
async fn send_error_response(&self, message_id: &Uuid, error_type: CommunicationType) {
|
||||
let error = CommunicationValue::new(error_type).with_id(*message_id);
|
||||
async fn send_error_response(&self, message_id: u32, error_type: CommunicationType) {
|
||||
let error = CommunicationValue::new(error_type).with_id(message_id);
|
||||
self.send_message(&error).await;
|
||||
}
|
||||
|
||||
async fn close(&self) {
|
||||
let mut sender = self.sender.write().await;
|
||||
let _ = sender.close(None).await;
|
||||
let _ = self.sender.close();
|
||||
}
|
||||
|
||||
async fn handle_omega_forward(self: Arc<Self>, cv: CommunicationValue) {
|
||||
let iota_for_closure = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let response_cv = get_omega_connection()
|
||||
.await_response(
|
||||
&cv.with_sender(*self.iota_id.read().await),
|
||||
Some(Duration::from_secs(20)),
|
||||
)
|
||||
.await_response(&cv.with_sender(self.iota_id), Some(Duration::from_secs(20)))
|
||||
.await;
|
||||
if let Ok(response_cv) = response_cv {
|
||||
iota_for_closure.send_message(&response_cv).await;
|
||||
|
|
@ -470,7 +171,7 @@ impl IotaConnection {
|
|||
}
|
||||
/// Handle ping message
|
||||
async fn handle_ping(&self, cv: CommunicationValue) {
|
||||
if let Some(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
if let DataValue::Number(last_ping) = cv.get_data(DataTypes::last_ping) {
|
||||
if let Ok(ping_val) = last_ping.to_string().parse::<i64>() {
|
||||
let mut ping_guard = self.ping.write().await;
|
||||
*ping_guard = ping_val;
|
||||
|
|
@ -483,13 +184,13 @@ impl IotaConnection {
|
|||
HashMap::new()
|
||||
};
|
||||
|
||||
let pings = client_pings
|
||||
let pings: Vec<(DataTypes, DataValue)> = client_pings
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, JsonValue::String(v.to_string())))
|
||||
.map(|(k, v)| (DataTypes::parse(k), DataValue::Number(v)))
|
||||
.collect();
|
||||
let response = CommunicationValue::new(CommunicationType::pong)
|
||||
.with_id(cv.get_id())
|
||||
.add_data(DataTypes::ping_clients, JsonValue::Object(pings));
|
||||
.add_data(DataTypes::ping_clients, DataValue::Container(pings));
|
||||
self.send_message(&response).await;
|
||||
}
|
||||
|
||||
|
|
@ -498,8 +199,8 @@ impl IotaConnection {
|
|||
let receiver_id = cv.get_receiver();
|
||||
let sender_id = cv.get_sender();
|
||||
|
||||
if self.get_user_ids().await.contains(&sender_id) {
|
||||
if let Some(target_rho) = rho_manager::get_rho_con_for_user(receiver_id).await {
|
||||
if self.get_user_ids().await.contains(&(sender_id as u64)) {
|
||||
if let Some(target_rho) = rho_manager::get_rho_con_for_user(receiver_id as i64).await {
|
||||
target_rho.message_to_iota(cv).await;
|
||||
} else {
|
||||
let error = CommunicationValue::new(CommunicationType::error_no_iota)
|
||||
|
|
@ -511,7 +212,7 @@ impl IotaConnection {
|
|||
self.send_message(
|
||||
&CommunicationValue::new(CommunicationType::error_invalid_user_id).add_data(
|
||||
DataTypes::error_type,
|
||||
JsonValue::String(
|
||||
DataValue::Str(
|
||||
"You are sending to another User without authority.".to_string(),
|
||||
),
|
||||
),
|
||||
|
|
@ -525,77 +226,98 @@ impl IotaConnection {
|
|||
let receiver_id = cv.get_receiver();
|
||||
let mut interested_ids: Vec<i64> = Vec::new();
|
||||
|
||||
// loading Calls
|
||||
// ============================
|
||||
// Load Calls
|
||||
// ============================
|
||||
let calls: Vec<Arc<CallGroup>> = call_manager::get_call_groups(receiver_id).await;
|
||||
let mut invites: HashMap<i64, Vec<JsonValue>> = HashMap::new();
|
||||
let empty = &calls.is_empty();
|
||||
|
||||
let mut invites: HashMap<i64, Vec<DataValue>> = HashMap::new();
|
||||
let empty = calls.is_empty();
|
||||
|
||||
for call in calls {
|
||||
for inviter in call.members.read().await.iter() {
|
||||
let call_self = call.get_caller(receiver_id).await.unwrap();
|
||||
let admin = call_self.has_admin();
|
||||
|
||||
let inviter_id = inviter.user_id;
|
||||
let timeout = *call_self.timeout.read().await;
|
||||
let admin = call_self.has_admin();
|
||||
|
||||
// Build call container
|
||||
let mut call_map: HashMap<DataTypes, DataValue> = HashMap::new();
|
||||
|
||||
call_map.insert(DataTypes::call_id, DataValue::Str(call.call_id.to_string()));
|
||||
|
||||
let mut call_obj = JsonValue::new_object();
|
||||
let _ = call_obj.insert("call_id", JsonValue::String(call.call_id.to_string()));
|
||||
if timeout > 0 {
|
||||
let _ = call_obj.insert("timeout", JsonValue::from(timeout));
|
||||
}
|
||||
if admin {
|
||||
let _ = call_obj.insert("admin", JsonValue::Boolean(admin));
|
||||
call_map.insert(DataTypes::timeout, DataValue::Number(timeout as i64));
|
||||
}
|
||||
|
||||
if let Some(call_ids) = invites.get_mut(&inviter_id) {
|
||||
call_ids.push(call_obj);
|
||||
} else {
|
||||
invites.insert(inviter_id, vec![call_obj]);
|
||||
if admin {
|
||||
call_map.insert(DataTypes::has_admin, DataValue::Bool(true));
|
||||
}
|
||||
|
||||
let call_container = DataValue::container_from_map(&call_map);
|
||||
|
||||
invites
|
||||
.entry(inviter_id as i64)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(call_container);
|
||||
}
|
||||
}
|
||||
|
||||
// Process contacts and add call information
|
||||
let enriched_contacts = if *empty {
|
||||
if let Some(contacts_data) = cv.get_data(DataTypes::user_ids) {
|
||||
log_in!(self.get_iota_id().await, PrintType::Call, "Call empty");
|
||||
contacts_data.clone()
|
||||
} else {
|
||||
log_in!(
|
||||
self.get_iota_id().await,
|
||||
PrintType::Call,
|
||||
"Call empty No Data"
|
||||
);
|
||||
JsonValue::new_array()
|
||||
// ============================
|
||||
// Enrich Contacts
|
||||
// ============================
|
||||
let enriched_contacts = if empty {
|
||||
match cv.get_data(DataTypes::user_ids) {
|
||||
DataValue::Array(arr) => DataValue::Array(arr.clone()),
|
||||
_ => DataValue::Array(vec![]),
|
||||
}
|
||||
} else {
|
||||
let mut enrc_contacts = JsonValue::new_array();
|
||||
if let Some(contacts_data) = cv.get_data(DataTypes::user_ids) {
|
||||
if let JsonValue::Array(user_ids) = contacts_data {
|
||||
for user_json in user_ids {
|
||||
let user_id = user_json["user_id"].as_i64().unwrap_or(0);
|
||||
interested_ids.push(user_id);
|
||||
let mut enriched_contact = user_json.clone();
|
||||
if let Some(calls) = invites.get(&user_id) {
|
||||
let _ =
|
||||
enriched_contact.insert("calls", JsonValue::Array(calls.clone()));
|
||||
let mut enriched: Vec<DataValue> = Vec::new();
|
||||
|
||||
if let DataValue::Array(users) = cv.get_data(DataTypes::user_ids) {
|
||||
for user_val in users {
|
||||
if let DataValue::Container(entries) = user_val {
|
||||
let mut user_map: HashMap<DataTypes, DataValue> =
|
||||
entries.iter().cloned().collect();
|
||||
|
||||
// extract user_id
|
||||
if let Some(DataValue::Number(user_id)) = user_map.get(&DataTypes::user_id)
|
||||
{
|
||||
interested_ids.push(*user_id);
|
||||
|
||||
// attach calls if exists
|
||||
if let Some(call_list) = invites.get(user_id) {
|
||||
user_map
|
||||
.insert(DataTypes::calls, DataValue::Array(call_list.clone()));
|
||||
}
|
||||
}
|
||||
let _ = enrc_contacts.push(enriched_contact);
|
||||
|
||||
enriched.push(DataValue::container_from_map(&user_map));
|
||||
}
|
||||
} else {
|
||||
enrc_contacts = contacts_data.clone();
|
||||
}
|
||||
}
|
||||
enrc_contacts
|
||||
|
||||
DataValue::Array(enriched)
|
||||
};
|
||||
|
||||
// Notify OmegaConnection about user states
|
||||
OmegaConnection::user_states(receiver_id, interested_ids.clone()).await;
|
||||
// ============================
|
||||
// Notify Omega
|
||||
// ============================
|
||||
OmegaConnection::user_states(receiver_id as i64, interested_ids.clone()).await;
|
||||
|
||||
// Set interested users in RhoConnection
|
||||
// ============================
|
||||
// Notify Rho
|
||||
// ============================
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
rho_conn.set_interested(receiver_id, interested_ids).await;
|
||||
rho_conn
|
||||
.set_interested(receiver_id as i64, interested_ids)
|
||||
.await;
|
||||
}
|
||||
|
||||
// ============================
|
||||
// Forward to client
|
||||
// ============================
|
||||
self.forward_to_client(cv.add_data(DataTypes::user_ids, enriched_contacts))
|
||||
.await;
|
||||
}
|
||||
|
|
@ -607,7 +329,7 @@ impl IotaConnection {
|
|||
rho_conn.message_to_client(updated_cv).await;
|
||||
} else {
|
||||
log_err!(
|
||||
self.get_iota_id().await,
|
||||
self.get_iota_id().await as i64,
|
||||
PrintType::General,
|
||||
"Failed to forward message to client"
|
||||
);
|
||||
|
|
@ -615,10 +337,8 @@ impl IotaConnection {
|
|||
}
|
||||
|
||||
pub async fn handle_close(&self) {
|
||||
if self.is_identified().await {
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
rho_conn.close_iota_connection().await;
|
||||
}
|
||||
if let Some(rho_conn) = self.get_rho_connection().await {
|
||||
rho_conn.close_iota_connection().await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +358,7 @@ impl IotaConnection {
|
|||
tokio::spawn(async move {
|
||||
if let Err(e) = inner_tx.send(response_cv).await {
|
||||
log_err!(
|
||||
io.get_iota_id().await,
|
||||
io.get_iota_id().await as i64,
|
||||
PrintType::Iota,
|
||||
"Failed to send response back to awaiter: {}",
|
||||
e
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
pub mod client_connection;
|
||||
pub mod connection;
|
||||
pub mod iota_connection;
|
||||
pub mod rho_connection;
|
||||
pub mod rho_manager;
|
||||
pub mod server;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use super::{client_connection::ClientConnection, iota_connection::IotaConnection, rho_manager};
|
||||
use crate::data::{
|
||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||
user::UserStatus,
|
||||
};
|
||||
|
||||
use crate::data::user::UserStatus;
|
||||
use crate::omega::omega_connection::OmegaConnection;
|
||||
use json::{JsonValue, number::Number};
|
||||
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
|
@ -27,8 +25,8 @@ impl RhoConnection {
|
|||
rho_connection
|
||||
}
|
||||
|
||||
pub async fn get_iota_id(&self) -> i64 {
|
||||
self.iota_connection.get_iota_id().await
|
||||
pub async fn get_iota_id(&self) -> u64 {
|
||||
self.iota_connection.iota_id
|
||||
}
|
||||
|
||||
pub fn get_user_ids(&self) -> &Vec<i64> {
|
||||
|
|
@ -52,7 +50,7 @@ impl RhoConnection {
|
|||
let connections = self.client_connections.read().await;
|
||||
let mut collections = Vec::new();
|
||||
for con in connections.iter() {
|
||||
if con.get_user_id().await == user_id {
|
||||
if con.get_user_id().await == user_id as u64 {
|
||||
collections.push(con.clone());
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +61,7 @@ impl RhoConnection {
|
|||
pub async fn add_client_connection(&self, connection: Arc<ClientConnection>) {
|
||||
let notification = CommunicationValue::new(CommunicationType::client_connected).add_data(
|
||||
DataTypes::user_id,
|
||||
JsonValue::Number(Number::from(connection.get_user_id().await)),
|
||||
DataValue::Number(connection.get_user_id().await as i64),
|
||||
);
|
||||
|
||||
self.iota_connection.send_message(¬ification).await;
|
||||
|
|
@ -74,8 +72,8 @@ impl RhoConnection {
|
|||
}
|
||||
|
||||
OmegaConnection::client_changed(
|
||||
self.get_iota_id().await,
|
||||
connection.get_user_id().await,
|
||||
self.get_iota_id().await as i64,
|
||||
connection.get_user_id().await as i64,
|
||||
UserStatus::user_online,
|
||||
)
|
||||
.await;
|
||||
|
|
@ -93,8 +91,8 @@ impl RhoConnection {
|
|||
|
||||
// Notify OmegaConnection
|
||||
OmegaConnection::client_changed(
|
||||
self.get_iota_id().await,
|
||||
connection.get_user_id().await,
|
||||
self.get_iota_id().await as i64,
|
||||
connection.get_user_id().await as i64,
|
||||
UserStatus::user_offline,
|
||||
)
|
||||
.await;
|
||||
|
|
@ -109,10 +107,10 @@ impl RhoConnection {
|
|||
}
|
||||
|
||||
// Remove from manager
|
||||
rho_manager::remove_rho(self.get_iota_id().await).await;
|
||||
rho_manager::remove_rho(self.get_iota_id().await as i64).await;
|
||||
|
||||
// Notify OmegaConnection
|
||||
OmegaConnection::close_iota(self.get_iota_id().await).await;
|
||||
OmegaConnection::close_iota(self.get_iota_id().await as i64).await;
|
||||
}
|
||||
|
||||
/// Send message from Iota to specific client
|
||||
|
|
@ -136,7 +134,7 @@ impl RhoConnection {
|
|||
let connections = self.client_connections.read().await;
|
||||
for connection in connections.iter() {
|
||||
let conn_user_id = connection.get_user_id().await;
|
||||
if conn_user_id == user_id {
|
||||
if conn_user_id == user_id as u64 {
|
||||
connection
|
||||
.clone()
|
||||
.set_interested_users(interested_ids.clone())
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub async fn remove_rho(iota_id: i64) -> Option<Arc<RhoConnection>> {
|
|||
pub async fn add_rho(rho_connection: Arc<RhoConnection>) {
|
||||
let mut connections = RHO_CONNECTIONS.write().await;
|
||||
let iota_id = rho_connection.get_iota_id().await;
|
||||
connections.insert(iota_id, rho_connection);
|
||||
connections.insert(iota_id as i64, rho_connection);
|
||||
}
|
||||
|
||||
/// Get a RhoConnection by Iota ID directly
|
||||
|
|
|
|||
57
src/rho/server.rs
Normal file
57
src/rho/server.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use crate::{rho::connection::GeneralConnection, util::file_util::load_file_buf};
|
||||
use epsilon_native::Host;
|
||||
use quinn::ServerConfig;
|
||||
use rustls::pki_types::PrivateKeyDer;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::unix::AsyncFd;
|
||||
|
||||
pub async fn start(port: u16) {
|
||||
let tls_cfg = load_tls().expect("TLS config failed");
|
||||
|
||||
let server_crypto = quinn::crypto::rustls::QuicServerConfig::try_from(tls_cfg)
|
||||
.expect("Failed to convert to QuicServerConfig");
|
||||
|
||||
let server_cfg = ServerConfig::with_crypto(Arc::new(server_crypto));
|
||||
|
||||
let mut host: Host = epsilon_native::host(port, server_cfg).await.unwrap();
|
||||
tokio::spawn(async move {
|
||||
while let Some((sender, receiver)) = host.next().await {
|
||||
tokio::spawn(async move {
|
||||
GeneralConnection::new(sender, receiver).handle().await;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn load_tls() -> Option<rustls::ServerConfig> {
|
||||
let mut cert_file_buf = load_file_buf("certs", "cert.pem").ok()?;
|
||||
let mut key_file_buf = load_file_buf("certs", "cert.key").ok()?;
|
||||
|
||||
let cert_chain = rustls_pemfile::certs(&mut cert_file_buf)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()?;
|
||||
|
||||
let mut keys: Vec<PrivateKeyDer> = rustls_pemfile::pkcs8_private_keys(&mut key_file_buf)
|
||||
.map(|k| k.map(Into::into))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()?;
|
||||
|
||||
if keys.is_empty() {
|
||||
let mut key_file_buf = load_file_buf("certs", "cert.key").ok()?;
|
||||
keys = rustls_pemfile::rsa_private_keys(&mut key_file_buf)
|
||||
.map(|k| k.map(Into::into))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
if keys.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cfg = rustls::ServerConfig::builder()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(cert_chain, keys.remove(0))
|
||||
.ok()?;
|
||||
|
||||
Some(cfg)
|
||||
}
|
||||
179
src/util/file_util.rs
Normal file
179
src/util/file_util.rs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
use std::fs::{self, File};
|
||||
use std::io::{self, BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::log;
|
||||
use crate::util::logger::PrintType;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn delete_directory(path: &str) -> bool {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
delete_dir_recursive(&dir)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn delete_dir_recursive(directory: &Path) -> bool {
|
||||
if !directory.exists() {
|
||||
return false;
|
||||
}
|
||||
if let Err(e) = fs::remove_dir_all(directory) {
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"[IMPORTANT] Couldn't delete directory {}: {}",
|
||||
directory.display(),
|
||||
e,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn delete_user_directory(user_id: i64) {
|
||||
let user_dir = Path::new(&get_directory())
|
||||
.join("users")
|
||||
.join(user_id.to_string());
|
||||
let _ = delete_dir_recursive(&user_dir);
|
||||
}
|
||||
|
||||
pub fn load_file_buf(path: &str, name: &str) -> io::Result<BufReader<File>> {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let file_path = dir.join(name);
|
||||
|
||||
// Ensure the directory exists, create if necessary
|
||||
if !dir.exists() {
|
||||
if let Err(_) = fs::create_dir_all(&dir) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"Directory creation failed",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the file if it doesn't exist
|
||||
if !file_path.exists() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"File creation failed",
|
||||
));
|
||||
}
|
||||
|
||||
// Open the file and return a BufReader for efficient reading
|
||||
let file = File::open(&file_path)?;
|
||||
Ok(BufReader::new(file))
|
||||
}
|
||||
pub fn has_file(path: &str, name: &str) -> bool {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let file_path = dir.join(name);
|
||||
|
||||
if !dir.exists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !file_path.exists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
pub fn has_dir(path: &str) -> bool {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
|
||||
if !dir.exists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn load_file(path: &str, name: &str) -> String {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let file_path = dir.join(name);
|
||||
|
||||
if !dir.exists() {
|
||||
if let Err(e) = fs::create_dir_all(&dir) {
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"[IMPORTANT] Couldn't create directories: {}",
|
||||
e
|
||||
);
|
||||
return String::new();
|
||||
}
|
||||
return String::new();
|
||||
}
|
||||
|
||||
if !file_path.exists() {
|
||||
if let Err(e) = File::create(&file_path) {
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"[IMPORTANT] Couldn't create file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let mut content = String::new();
|
||||
if let Ok(mut f) = File::open(&file_path) {
|
||||
let _ = f.read_to_string(&mut content);
|
||||
}
|
||||
content
|
||||
}
|
||||
|
||||
pub fn load_file_vec(path: &str, name: &str) -> Result<Vec<u8>, std::io::Error> {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let file_path = dir.join(name);
|
||||
|
||||
std::fs::read(file_path)
|
||||
}
|
||||
|
||||
pub fn save_file(path: &str, name: &str, value: &str) {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let file_path = dir.join(name);
|
||||
|
||||
if !dir.exists() {
|
||||
if let Err(e) = fs::create_dir_all(&dir) {
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"[IMPORTANT] Couldn't create directories: {}",
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = fs::write(&file_path, value) {
|
||||
log!(
|
||||
0,
|
||||
PrintType::General,
|
||||
"[IMPORTANT] Couldn't write file {}: {}",
|
||||
file_path.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_children(path: &str) -> Vec<String> {
|
||||
let dir = Path::new(&get_directory()).join(path);
|
||||
let mut children = Vec::new();
|
||||
if let Ok(entries) = fs::read_dir(&dir) {
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
children.push(entry.file_name().to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
children
|
||||
}
|
||||
|
||||
pub fn get_directory() -> String {
|
||||
let exe = std::env::current_exe().unwrap_or_else(|_| PathBuf::from("."));
|
||||
exe.parent()
|
||||
.unwrap_or(Path::new("."))
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{self, OpenOptions},
|
||||
io::Write,
|
||||
path::Path,
|
||||
|
|
@ -8,9 +9,7 @@ use std::{
|
|||
};
|
||||
|
||||
use ansi_term::Color;
|
||||
use json::JsonValue;
|
||||
|
||||
use crate::data::communication::CommunicationValue;
|
||||
use epsilon_core::{CommunicationValue, DataTypes, DataValue};
|
||||
|
||||
static LOGGER: OnceLock<mpsc::Sender<LogMessage>> = OnceLock::new();
|
||||
|
||||
|
|
@ -151,7 +150,7 @@ pub fn log_cv_internal(
|
|||
let formatted = format_cv(cv);
|
||||
|
||||
log_internal(
|
||||
cv.get_sender(),
|
||||
cv.get_sender() as i64,
|
||||
print_type.unwrap_or(PrintType::General),
|
||||
prefix,
|
||||
false,
|
||||
|
|
@ -176,24 +175,80 @@ pub fn format_cv(cv: &CommunicationValue) -> String {
|
|||
let comm_type = cv.get_type().to_string();
|
||||
parts.push(format!("{}", comm_type));
|
||||
|
||||
let mut data_parts = Vec::new();
|
||||
if let JsonValue::Object(data) = &cv.clone().to_json()["data"] {
|
||||
for (key, value) in data.iter() {
|
||||
let val_string = match value {
|
||||
JsonValue::String(s) => s.clone(),
|
||||
_ => value.dump(),
|
||||
};
|
||||
let data: &HashMap<DataTypes, DataValue> = cv.get_data_container();
|
||||
|
||||
data_parts.push(format!("{} {}", key, val_string));
|
||||
}
|
||||
}
|
||||
let formated_data =
|
||||
format_data_container(data.iter().map(|(k, v)| (k.clone(), v.clone())).collect());
|
||||
|
||||
if !data_parts.is_empty() {
|
||||
parts.push(format!("{}", data_parts.join(", ")));
|
||||
}
|
||||
parts.push(format!("{}", formated_data));
|
||||
|
||||
parts.join(": ")
|
||||
}
|
||||
|
||||
fn format_data_container(data: Vec<(DataTypes, DataValue)>) -> String {
|
||||
let parts: Vec<String> = data
|
||||
.into_iter()
|
||||
.map(|(key, value)| {
|
||||
let key_str = key.to_string();
|
||||
|
||||
match value {
|
||||
DataValue::Str(s) => format!("{}=\"{}\"", key_str, s),
|
||||
|
||||
DataValue::Container(inner) => {
|
||||
let inner_formatted = format_data_container(inner);
|
||||
format!("{}={{ {} }}", key_str, inner_formatted)
|
||||
}
|
||||
|
||||
DataValue::Array(arr) => {
|
||||
let arr_formatted = format_array(arr);
|
||||
format!("{}=[{}]", key_str, arr_formatted)
|
||||
}
|
||||
|
||||
DataValue::Bool(b) => format!("{}={}", key_str, b),
|
||||
|
||||
DataValue::BoolTrue => format!("{}=true", key_str),
|
||||
DataValue::BoolFalse => format!("{}=false", key_str),
|
||||
|
||||
DataValue::Number(num) => format!("{}={}", key_str, num),
|
||||
|
||||
_ => "".to_string(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
parts.join(", ")
|
||||
}
|
||||
|
||||
fn format_array(arr: Vec<DataValue>) -> String {
|
||||
let parts: Vec<String> = arr
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
DataValue::Str(s) => format!("\"{}\"", s),
|
||||
|
||||
DataValue::Container(inner) => {
|
||||
let inner_formatted = format_data_container(inner);
|
||||
format!("{{ {} }}", inner_formatted)
|
||||
}
|
||||
|
||||
DataValue::Array(inner_arr) => {
|
||||
let formatted = format_array(inner_arr);
|
||||
format!("[{}]", formatted)
|
||||
}
|
||||
|
||||
DataValue::Bool(b) => b.to_string(),
|
||||
|
||||
DataValue::BoolTrue => "true".to_string(),
|
||||
DataValue::BoolFalse => "false".to_string(),
|
||||
|
||||
DataValue::Number(num) => num.to_string(),
|
||||
|
||||
_ => String::new(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
parts.join(", ")
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_cv {
|
||||
($kind:expr, $cv:expr) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod crypto_helper;
|
||||
pub mod crypto_util;
|
||||
pub mod file_util;
|
||||
pub mod logger;
|
||||
|
|
|
|||
Loading…
Reference in a new issue