add a conversation by name, more stable client connection

This commit is contained in:
Alex-Emmet 2026-01-20 00:05:14 +01:00
commit 494e08241c
6 changed files with 203 additions and 280 deletions

57
Cargo.lock generated
View file

@ -15,7 +15,6 @@ dependencies = [
"block-modes", "block-modes",
"bytes", "bytes",
"cbc", "cbc",
"chacha20poly1305",
"chrono", "chrono",
"cmake", "cmake",
"crossterm", "crossterm",
@ -41,6 +40,8 @@ dependencies = [
"rustls 0.23.36", "rustls 0.23.36",
"serde", "serde",
"sha2", "sha2",
"strum",
"strum_macros",
"sys-info", "sys-info",
"sysinfo", "sysinfo",
"tokio", "tokio",
@ -552,30 +553,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
"zeroize",
]
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.42" version = "0.4.42"
@ -597,7 +574,6 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [ dependencies = [
"crypto-common", "crypto-common",
"inout", "inout",
"zeroize",
] ]
[[package]] [[package]]
@ -2427,17 +2403,6 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]] [[package]]
name = "polyval" name = "polyval"
version = "0.6.2" version = "0.6.2"
@ -3279,6 +3244,24 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
[[package]]
name = "strum_macros"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"

View file

@ -5,7 +5,38 @@ edition = "2024"
[dependencies] [dependencies]
ansi_term = "*" ansi_term = "*"
async-tungstenite = { version = "0.32.0", features = ["futures-03-sink", "futures-util", "handshake", "__rustls-tls", "async-native-tls", "async-std", "async-std-runtime", "async-tls", "gio", "gio-runtime", "glib", "openssl", "real-async-native-tls", "real-async-tls", "real-native-tls", "real-tokio-native-tls", "real-tokio-openssl", "real-tokio-rustls", "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-native-tls", "tokio-openssl", "tokio-runtime", "tokio-rustls-manual-roots", "tokio-rustls-native-certs", "tokio-rustls-webpki-roots", "url", "verbose-logging", "webpki-roots"] } async-tungstenite = { version = "0.32.0", features = [
"futures-03-sink",
"futures-util",
"handshake",
"__rustls-tls",
"async-native-tls",
"async-std",
"async-std-runtime",
"async-tls",
"gio",
"gio-runtime",
"glib",
"openssl",
"real-async-native-tls",
"real-async-tls",
"real-native-tls",
"real-tokio-native-tls",
"real-tokio-openssl",
"real-tokio-rustls",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
"tokio-native-tls",
"tokio-openssl",
"tokio-runtime",
"tokio-rustls-manual-roots",
"tokio-rustls-native-certs",
"tokio-rustls-webpki-roots",
"url",
"verbose-logging",
"webpki-roots",
] }
axum = "*" axum = "*"
base64 = "0.22.1" base64 = "0.22.1"
bytes = "*" bytes = "*"
@ -52,7 +83,8 @@ dotenv = "0.15.0"
aes-gcm = "0.10.3" aes-gcm = "0.10.3"
tokio-native-tls = "0.3.1" tokio-native-tls = "0.3.1"
hkdf = "0.12.4" hkdf = "0.12.4"
chacha20poly1305 = "0.10.1"
block-modes = "0.9.1" block-modes = "0.9.1"
cbc = "0.1.2" cbc = "0.1.2"
aes = "0.8.4" aes = "0.8.4"
strum = "0.27.2"
strum_macros = "0.27.2"

View file

@ -2,9 +2,11 @@ use json::number::Number;
use json::{Array, JsonValue, object, parse}; use json::{Array, JsonValue, object, parse};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use uuid::Uuid; use uuid::Uuid;
#[derive(Eq, Hash, PartialEq, Clone, Debug)] #[derive(Eq, Hash, PartialEq, EnumIter, Clone, Debug)]
#[allow(non_camel_case_types, dead_code)] #[allow(non_camel_case_types, dead_code)]
pub enum DataTypes { pub enum DataTypes {
error_type, error_type,
@ -14,6 +16,7 @@ pub enum DataTypes {
settings, settings,
settings_name, settings_name,
chat_partner_id, chat_partner_id,
chat_partner_name,
iota_id, iota_id,
user_id, user_id,
user_ids, user_ids,
@ -88,91 +91,21 @@ pub enum DataTypes {
impl DataTypes { impl DataTypes {
pub fn parse(p0: String) -> DataTypes { pub fn parse(p0: String) -> DataTypes {
let normalized = p0.to_lowercase().replace('_', ""); for datatype in DataTypes::iter() {
if datatype.to_string().to_lowercase().replace('_', "")
match normalized.as_str() { == p0.to_lowercase().replace('_', "")
"errortype" => DataTypes::error_type, {
"chatpartnerid" => DataTypes::chat_partner_id, return datatype;
"registerid" => DataTypes::register_id, }
"uuid" => DataTypes::uuid,
"settings" => DataTypes::settings,
"settingsname" => DataTypes::settings_name,
"iotaid" => DataTypes::iota_id,
"userid" => DataTypes::user_id,
"userids" => DataTypes::user_ids,
"iotaids" => DataTypes::iota_ids,
"userstate" => DataTypes::user_state,
"userstates" => DataTypes::user_states,
"userpings" => DataTypes::user_pings,
"callstate" => DataTypes::call_state,
"screenshare" => DataTypes::screen_share,
"privatekeyhash" => DataTypes::private_key_hash,
"accepted" => DataTypes::accepted,
"acceptedprofiles" => DataTypes::accepted_profiles,
"deniedprofiles" => DataTypes::denied_profiles,
"content" => DataTypes::content,
"messages" => DataTypes::messages,
"sendtime" => DataTypes::send_time,
"gettime" => DataTypes::get_time,
"getvariant" => DataTypes::get_variant,
"sharedsecretown" => DataTypes::shared_secret_own,
"sharedsecretother" => DataTypes::shared_secret_other,
"sharedsecretsign" => DataTypes::shared_secret_sign,
"sharedsecret" => DataTypes::shared_secret,
"callid" => DataTypes::call_id,
"calltoken" => DataTypes::call_token,
"untill" => DataTypes::untill,
"enable" => DataTypes::enable,
"startdate" => DataTypes::start_date,
"enddate" => DataTypes::end_date,
"receiverid" => DataTypes::receiver_id,
"senderid" => DataTypes::sender_id,
"signature" => DataTypes::signature,
"signed" => DataTypes::signed,
"message" => DataTypes::message,
"lastping" => DataTypes::last_ping,
"pingiota" => DataTypes::ping_iota,
"pingclients" => DataTypes::ping_clients,
"matches" => DataTypes::matches,
"omikron" => DataTypes::omikron,
"offset" => DataTypes::offset,
"amount" => DataTypes::amount,
"position" => DataTypes::position,
"name" => DataTypes::name,
"path" => DataTypes::path,
"codec" => DataTypes::codec,
"function" => DataTypes::function,
"payload" => DataTypes::payload,
"result" => DataTypes::result,
"interactables" => DataTypes::interactables,
"wanttowatch" => DataTypes::want_to_watch,
"watcher" => DataTypes::watcher,
"createdat" => DataTypes::created_at,
"username" => DataTypes::username,
"display" => DataTypes::display,
"avatar" => DataTypes::avatar,
"about" => DataTypes::about,
"status" => DataTypes::status,
"publickey" => DataTypes::public_key,
"sublevel" => DataTypes::sub_level,
"subend" => DataTypes::sub_end,
"communityaddress" => DataTypes::community_address,
"challenge" => DataTypes::challenge,
"communitytitle" => DataTypes::community_title,
"communities" => DataTypes::communities,
"rhoconnections" => DataTypes::rho_connections,
"user" => DataTypes::user,
"onlinestatus" => DataTypes::online_status,
"omikronid" => DataTypes::omikron_id,
"omikronconnections" => DataTypes::omikron_connections,
"resettoken" => DataTypes::reset_token,
"newtoken" => DataTypes::new_token,
_ => DataTypes::error_type, // fallback if unknown
} }
DataTypes::error_type
}
pub fn to_string(&self) -> String {
return format!("{:?}", self);
} }
} }
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, EnumIter, Debug)]
#[allow(non_camel_case_types, dead_code)] #[allow(non_camel_case_types, dead_code)]
pub enum CommunicationType { pub enum CommunicationType {
error, error,
@ -218,7 +151,7 @@ pub enum CommunicationType {
register_iota_success, register_iota_success,
ping, ping,
pong, pong,
add_chat, add_conversation,
send_chat, send_chat,
client_changed, client_changed,
client_connected, client_connected,
@ -266,99 +199,17 @@ pub enum CommunicationType {
} }
impl CommunicationType { impl CommunicationType {
pub fn parse(p0: String) -> CommunicationType { pub fn parse(p0: String) -> CommunicationType {
let normalized = p0.to_lowercase().replace('_', ""); for datatype in CommunicationType::iter() {
if datatype.to_string().to_lowercase().replace('_', "")
match normalized.as_str() { == p0.to_lowercase().replace('_', "")
"watchstream" => CommunicationType::watch_stream, {
"calltoken" => CommunicationType::call_token, return datatype;
"callinvite" => CommunicationType::call_invite, }
"calldisconnectuser" => CommunicationType::call_disconnect_user,
"calltimeoutuser" => CommunicationType::call_timeout_user,
"callsetanonymousjoining" => CommunicationType::call_set_anonymous_joining,
"endcall" => CommunicationType::end_call,
"function" => CommunicationType::function,
"update" => CommunicationType::update,
"createuser" => CommunicationType::create_user,
"errorinternal" => CommunicationType::error_internal,
"errorinvaliddata" => CommunicationType::error_invalid_data,
"errorinvaliduserid" => CommunicationType::error_invalid_user_id,
"errorinvalidomikronid" => CommunicationType::error_invalid_omikron_id,
"errornotfound" => CommunicationType::error_not_found,
"errornotauthenticated" => CommunicationType::error_not_authenticated,
"errornoiota" => CommunicationType::error_no_iota,
"errorinvalidchallenge" => CommunicationType::error_invalid_challenge,
"errorinvalidpublickey" => CommunicationType::error_invalid_public_key,
"errorinvalidsecret" => CommunicationType::error_invalid_secret,
"errorinvalidprivatekey" => CommunicationType::error_invalid_private_key,
"errornouserid" => CommunicationType::error_no_user_id,
"errornocallid" => CommunicationType::error_no_call_id,
"errorinvalidcallid" => CommunicationType::error_invalid_call_id,
"success" => CommunicationType::success,
"settingssave" => CommunicationType::settings_save,
"settingsload" => CommunicationType::settings_load,
"settingslist" => CommunicationType::settings_list,
"message" => CommunicationType::message,
"messagesend" => CommunicationType::message_send,
"messagelive" => CommunicationType::message_live,
"messageotheriota" => CommunicationType::message_other_iota,
"messagechunk" => CommunicationType::message_chunk,
"messagesget" => CommunicationType::messages_get,
"changeconfirm" => CommunicationType::change_confirm,
"confirmreceive" => CommunicationType::confirm_receive,
"confirmread" => CommunicationType::confirm_read,
"getchats" => CommunicationType::get_chats,
"getstates" => CommunicationType::get_states,
"addcommunity" => CommunicationType::add_community,
"removecommunity" => CommunicationType::remove_community,
"getcommunities" => CommunicationType::get_communities,
"challenge" => CommunicationType::challenge,
"challengeresponse" => CommunicationType::challenge_response,
"register" => CommunicationType::register,
"registerresponse" => CommunicationType::register_response,
"identification" => CommunicationType::identification,
"identificationresponse" => CommunicationType::identification_response,
"registeriota" => CommunicationType::register_iota,
"registeriotasuccess" => CommunicationType::register_iota_success,
"ping" => CommunicationType::ping,
"pong" => CommunicationType::pong,
"addchat" => CommunicationType::add_chat,
"sendchat" => CommunicationType::send_chat,
"clientchanged" => CommunicationType::client_changed,
"clientconnected" => CommunicationType::client_connected,
"clientdisconnected" => CommunicationType::client_disconnected,
"clientclosed" => CommunicationType::client_closed,
"publickey" => CommunicationType::public_key,
"privatekey" => CommunicationType::private_key,
"webrtcsdp" => CommunicationType::webrtc_sdp,
"webrtcice" => CommunicationType::webrtc_ice,
"startstream" => CommunicationType::start_stream,
"endstream" => CommunicationType::end_stream,
"rhoupdate" => CommunicationType::rho_update,
"iotaconnected" => CommunicationType::iota_connected,
"iotadisconnected" => CommunicationType::iota_disconnected,
"userconnected" => CommunicationType::user_connected,
"userdisconnected" => CommunicationType::user_disconnected,
"syncclientiotastatus" => CommunicationType::sync_client_iota_status,
"getuserdata" => CommunicationType::get_user_data,
"getiotadata" => CommunicationType::get_iota_data,
"iotauserdata" => CommunicationType::iota_user_data,
"changeuserdata" => CommunicationType::change_user_data,
"changeiotadata" => CommunicationType::change_iota_data,
"getregister" => CommunicationType::get_register,
"completeregisteruser" => CommunicationType::complete_register_user,
"completeregisteriota" => CommunicationType::complete_register_iota,
"deleteuser" => CommunicationType::delete_user,
"deleteiota" => CommunicationType::delete_iota,
"startregister" => CommunicationType::start_register,
"completeregister" => CommunicationType::complete_register,
_ => CommunicationType::error,
} }
CommunicationType::error
}
pub fn to_string(&self) -> String {
return format!("{:?}", self);
} }
} }

View file

@ -4,7 +4,7 @@ use json::JsonValue;
use json::number::Number; use json::number::Number;
use rand::Rng; use rand::Rng;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
use std::sync::{Arc, Weak}; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tokio_util::compat::Compat; use tokio_util::compat::Compat;
@ -38,6 +38,7 @@ pub struct ClientConnection {
pub_key: Arc<RwLock<Option<Vec<u8>>>>, pub_key: Arc<RwLock<Option<Vec<u8>>>>,
pub rho_connection: Arc<RwLock<Option<Arc<RhoConnection>>>>, pub rho_connection: Arc<RwLock<Option<Arc<RhoConnection>>>>,
pub interested_users: Arc<RwLock<Vec<i64>>>, pub interested_users: Arc<RwLock<Vec<i64>>>,
is_open: Arc<RwLock<bool>>,
} }
impl ClientConnection { impl ClientConnection {
@ -57,6 +58,7 @@ impl ClientConnection {
pub_key: Arc::new(RwLock::new(None)), pub_key: Arc::new(RwLock::new(None)),
rho_connection: Arc::new(RwLock::new(None)), rho_connection: Arc::new(RwLock::new(None)),
interested_users: Arc::new(RwLock::new(Vec::new())), interested_users: Arc::new(RwLock::new(Vec::new())),
is_open: Arc::new(RwLock::new(true)),
}) })
} }
@ -81,7 +83,7 @@ impl ClientConnection {
} }
/// Send a string message to the client /// Send a string message to the client
pub async fn send_message_str(&self, message: &str) { pub async fn send_message_str(self: Arc<Self>, message: &str) {
let mut session = self.sender.write().await; let mut session = self.sender.write().await;
if let Err(e) = session if let Err(e) = session
.send(Message::Text(Utf8Bytes::from(message.to_string()))) .send(Message::Text(Utf8Bytes::from(message.to_string())))
@ -92,7 +94,14 @@ impl ClientConnection {
} }
/// Send a CommunicationValue to the client /// Send a CommunicationValue to the client
pub async fn send_message(&self, cv: &CommunicationValue) { pub async fn send_message(self: Arc<Self>, cv: &CommunicationValue) {
if !*self.is_open.read().await {
log_out!(
PrintType::Client,
"Attempted to send message to a closed connection."
);
return;
}
if !cv.is_type(CommunicationType::pong) { if !cv.is_type(CommunicationType::pong) {
log_out!(PrintType::Client, "{}", &cv.to_json().to_string()); log_out!(PrintType::Client, "{}", &cv.to_json().to_string());
} }
@ -119,7 +128,8 @@ impl ClientConnection {
.unwrap_or(0); .unwrap_or(0);
if user_id == 0 { if user_id == 0 {
log_out!(PrintType::Client, "Invalid USER ID"); log_out!(PrintType::Client, "Invalid USER ID");
self.send_error_response(&cv.get_id(), CommunicationType::error_invalid_data) self.clone()
.send_error_response(&cv.get_id(), CommunicationType::error_invalid_data)
.await; .await;
self.close().await; self.close().await;
return; return;
@ -137,7 +147,8 @@ impl ClientConnection {
if let Ok(response_cv) = response_cv { if let Ok(response_cv) = response_cv {
if !response_cv.is_type(CommunicationType::get_user_data) { if !response_cv.is_type(CommunicationType::get_user_data) {
self.send_error_response(&cv.get_id(), CommunicationType::error_internal) self.clone()
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
.await; .await;
self.close().await; self.close().await;
return; return;
@ -151,11 +162,12 @@ impl ClientConnection {
let pub_key = match load_public_key(base64_pub) { let pub_key = match load_public_key(base64_pub) {
Some(pk) => pk, Some(pk) => pk,
None => { None => {
self.send_error_response( self.clone()
&cv.get_id(), .send_error_response(
CommunicationType::error_invalid_public_key, &cv.get_id(),
) CommunicationType::error_invalid_public_key,
.await; )
.await;
self.close().await; self.close().await;
return; return;
} }
@ -190,7 +202,8 @@ impl ClientConnection {
self.send_message(&challenge_msg).await; self.send_message(&challenge_msg).await;
} else { } else {
self.send_error_response(&cv.get_id(), CommunicationType::error_internal) self.clone()
.send_error_response(&cv.get_id(), CommunicationType::error_internal)
.await; .await;
self.close().await; self.close().await;
return; return;
@ -221,6 +234,7 @@ impl ClientConnection {
return; return;
} }
}; };
rho_connection.add_client_connection(self.clone()).await;
// Set identification data // Set identification data
{ {
@ -238,11 +252,12 @@ impl ClientConnection {
.with_id(cv.get_id()); .with_id(cv.get_id());
self.send_message(&response).await; self.send_message(&response).await;
} else { } else {
self.send_error_response( self.clone()
&cv.get_id(), .send_error_response(
CommunicationType::error_not_authenticated, &cv.get_id(),
) CommunicationType::error_not_authenticated,
.await; )
.await;
self.close().await; self.close().await;
return; return;
} }
@ -250,7 +265,8 @@ impl ClientConnection {
} }
if !self.is_identified().await { if !self.is_identified().await {
self.send_error_response(&cv.get_id(), CommunicationType::error_not_authenticated) self.clone()
.send_error_response(&cv.get_id(), CommunicationType::error_not_authenticated)
.await; .await;
self.close().await; self.close().await;
return; return;
@ -288,12 +304,11 @@ impl ClientConnection {
self.handle_omega_forward(cv).await; self.handle_omega_forward(cv).await;
return; return;
} }
// Forward other messages to Iota // Forward other messages to Iota
self.forward_to_iota(cv).await; self.forward_to_iota(cv).await;
}); });
} }
async fn handle_omega_forward(&self, cv: CommunicationValue) { async fn handle_omega_forward(self: Arc<Self>, cv: CommunicationValue) {
let client_for_closure = self.clone(); let client_for_closure = self.clone();
WAITING_TASKS.insert( WAITING_TASKS.insert(
cv.get_id(), cv.get_id(),
@ -311,7 +326,7 @@ impl ClientConnection {
} }
/// Handle ping message /// Handle ping message
async fn handle_ping(&self, cv: CommunicationValue) { async fn handle_ping(self: Arc<Self>, cv: CommunicationValue) {
// Update our ping if provided // Update our ping if provided
if let Some(last_ping) = cv.get_data(DataTypes::last_ping) { if let Some(last_ping) = cv.get_data(DataTypes::last_ping) {
if let Ok(ping_val) = last_ping.to_string().parse::<i64>() { if let Ok(ping_val) = last_ping.to_string().parse::<i64>() {
@ -336,7 +351,7 @@ impl ClientConnection {
} }
/// Handle client status change /// Handle client status change
async fn handle_client_changed(&self, cv: CommunicationValue) { async fn handle_client_changed(self: Arc<Self>, cv: CommunicationValue) {
let user_id = self.get_user_id().await; let user_id = self.get_user_id().await;
if let Some(_status_str) = cv.get_data(DataTypes::user_state) { if let Some(_status_str) = cv.get_data(DataTypes::user_state) {
let user_status = UserStatus::online; let user_status = UserStatus::online;
@ -348,7 +363,7 @@ impl ClientConnection {
} }
/// Handle call invite /// Handle call invite
async fn handle_call_invite(&self, cv: CommunicationValue) { async fn handle_call_invite(self: Arc<Self>, cv: CommunicationValue) {
let receiver_id: i64 = cv let receiver_id: i64 = cv
.get_data(DataTypes::receiver_id) .get_data(DataTypes::receiver_id)
.unwrap_or(&json::JsonValue::Number(Number::from(0))) .unwrap_or(&json::JsonValue::Number(Number::from(0)))
@ -415,7 +430,7 @@ impl ClientConnection {
} }
/// Handle get call request /// Handle get call request
async fn handle_get_call(&self, cv: CommunicationValue) { 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().await;
let call_id = match cv.get_data(DataTypes::call_id) { let call_id = match cv.get_data(DataTypes::call_id) {
@ -446,22 +461,59 @@ impl ClientConnection {
return; return;
} }
} }
async fn handle_call_timeout_user(&self, cv: CommunicationValue) { async fn handle_call_timeout_user(self: Arc<Self>, cv: CommunicationValue) {
let user_id = cv.get_data(DataTypes::call_id).unwrap(); let user_id = cv.get_data(DataTypes::call_id).unwrap();
let call_id = cv.get_data(DataTypes::user_id).unwrap(); // JA man braucht CALL_ID let call_id = cv.get_data(DataTypes::user_id).unwrap(); // JA man braucht CALL_ID
} }
async fn handle_call_disconnect_user(&self, cv: CommunicationValue) { async fn handle_call_disconnect_user(self: Arc<Self>, cv: CommunicationValue) {
let user_id = cv.get_data(DataTypes::call_id).unwrap(); let user_id = cv.get_data(DataTypes::call_id).unwrap();
let call_id = cv.get_data(DataTypes::user_id).unwrap(); // JA man braucht CALL_ID let call_id = cv.get_data(DataTypes::user_id).unwrap(); // JA man braucht CALL_ID
let untill = cv.get_data(DataTypes::untill).unwrap(); let untill = cv.get_data(DataTypes::untill).unwrap();
} }
async fn handle_call_set_anonymous_joining(&self, cv: CommunicationValue) { async fn handle_call_set_anonymous_joining(self: Arc<Self>, cv: CommunicationValue) {
let call_id = cv.get_data(DataTypes::user_id).unwrap(); let call_id = cv.get_data(DataTypes::user_id).unwrap();
let enable = cv.get_data(DataTypes::enable).unwrap(); let enable = cv.get_data(DataTypes::enable).unwrap();
} }
/// Forward message to Iota /// Forward message to Iota
async fn forward_to_iota(&self, cv: CommunicationValue) { 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()
{
let chat_partner_name = cv
.get_data(DataTypes::chat_partner_name)
.unwrap_or(&JsonValue::Null)
.as_str()
.unwrap_or("");
let load_uuid_response = get_omega_connection()
.await_response(
&CommunicationValue::new(CommunicationType::get_user_data)
.with_id(cv.get_id())
.add_data(DataTypes::username, JsonValue::from(chat_partner_name)),
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()
} else {
JsonValue::Null
}
};
if let Some(rho_conn) = self.get_rho_connection().await {
let updated_cv = cv
.with_sender(self.get_user_id().await)
.add_data(DataTypes::chat_partner_id, chat_partner_id);
rho_conn.message_to_iota(updated_cv).await;
}
return;
}
if let Some(rho_conn) = self.get_rho_connection().await { 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);
rho_conn.message_to_iota(updated_cv).await; rho_conn.message_to_iota(updated_cv).await;
@ -469,26 +521,40 @@ impl ClientConnection {
} }
/// Send error response /// Send error response
async fn send_error_response(&self, message_id: &Uuid, error_type: CommunicationType) { async fn send_error_response(
self: Arc<Self>,
message_id: &Uuid,
error_type: CommunicationType,
) {
let error = CommunicationValue::new(error_type).with_id(*message_id); let error = CommunicationValue::new(error_type).with_id(*message_id);
self.send_message(&error).await; self.send_message(&error).await;
} }
/// Close the connection /// Close the connection
pub async fn close(&self) { pub async fn close(&self) {
let mut is_open_guard = self.is_open.write().await;
if *is_open_guard {
return;
}
*is_open_guard = false;
let mut session = self.sender.write().await; let mut session = self.sender.write().await;
let _ = session.close(None).await; let _ = session.close(None).await;
} }
/// Set interested users list /// Set interested users list
pub async fn set_interested_users(&self, interested_ids: Vec<i64>) { pub async fn set_interested_users(self: Arc<Self>, interested_ids: Vec<i64>) {
let mut interested_guard = self.interested_users.write().await; let mut interested_guard = self.interested_users.write().await;
*interested_guard = interested_ids; *interested_guard = interested_ids;
} }
pub async fn get_interested_users(self: Arc<Self>) -> Vec<i64> {
let interested_guard = self.interested_users.read().await;
interested_guard.clone()
}
/// Check if interested in a user and send notification /// Check if interested in a user and send notification
pub async fn are_you_interested(&self, user: &User) { pub async fn are_you_interested(self: Arc<Self>, user: &User) {
let interested_guard = self.interested_users.read().await; let interested_guard = self.clone().get_interested_users().await;
if interested_guard.contains(&user.user_id) { if interested_guard.contains(&user.user_id) {
let notification = CommunicationValue::new(CommunicationType::client_changed) let notification = CommunicationValue::new(CommunicationType::client_changed)
.add_data_str(DataTypes::user_id, user.user_id.to_string()) .add_data_str(DataTypes::user_id, user.user_id.to_string())
@ -528,16 +594,7 @@ impl Clone for ClientConnection {
pub_key: Arc::clone(&self.pub_key), pub_key: Arc::clone(&self.pub_key),
rho_connection: Arc::clone(&self.rho_connection), rho_connection: Arc::clone(&self.rho_connection),
interested_users: Arc::clone(&self.interested_users), interested_users: Arc::clone(&self.interested_users),
is_open: Arc::clone(&self.is_open),
} }
} }
} }
impl std::fmt::Debug for ClientConnection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientConnection")
.field("user_id", &"[async]")
.field("identified", &"[async]")
.field("ping", &"[async]")
.finish()
}
}

View file

@ -2,12 +2,12 @@ use crate::calls::call_group::CallGroup;
use crate::calls::call_manager; use crate::calls::call_manager;
use crate::get_private_key; use crate::get_private_key;
use crate::get_public_key; use crate::get_public_key;
use crate::log;
use crate::log_err; use crate::log_err;
use crate::log_in; use crate::log_in;
use crate::log_out; use crate::log_out;
use crate::omega::omega_connection::WAITING_TASKS; use crate::omega::omega_connection::WAITING_TASKS;
use crate::omega::omega_connection::get_omega_connection; use crate::omega::omega_connection::get_omega_connection;
use crate::util::crypto_helper::encrypt;
use crate::util::crypto_helper::load_public_key; use crate::util::crypto_helper::load_public_key;
use crate::util::crypto_helper::public_key_to_base64; use crate::util::crypto_helper::public_key_to_base64;
use crate::util::crypto_util::DataFormat; use crate::util::crypto_util::DataFormat;
@ -30,7 +30,6 @@ use tokio::sync::mpsc;
use tokio_util::compat::Compat; use tokio_util::compat::Compat;
use tungstenite::Utf8Bytes; use tungstenite::Utf8Bytes;
use uuid::Uuid; use uuid::Uuid;
use warp::filters::method::get;
use x448::PublicKey; use x448::PublicKey;
use super::{rho_connection::RhoConnection, rho_manager}; use super::{rho_connection::RhoConnection, rho_manager};
@ -395,11 +394,15 @@ impl IotaConnection {
self.close().await; self.close().await;
return; return;
} }
// Handle GET_CHATS
if cv.is_type(CommunicationType::get_chats) {
self.handle_get_chats(cv).await;
return;
}
log_in!(PrintType::Iota, "{}", &cv.to_json().to_string());
// Handle forwarding to other Iotas or clients // Handle forwarding to other Iotas or clients
let receiver_id = cv.get_receiver(); let receiver_id = cv.get_receiver();
if !self.get_user_ids().await.contains(&receiver_id) if (receiver_id != 0 && !self.get_user_ids().await.contains(&receiver_id))
|| cv.is_type(CommunicationType::message_other_iota) || cv.is_type(CommunicationType::message_other_iota)
|| cv.is_type(CommunicationType::send_chat) || cv.is_type(CommunicationType::send_chat)
{ {
@ -407,12 +410,6 @@ impl IotaConnection {
return; return;
} }
// Handle GET_CHATS
if cv.is_type(CommunicationType::get_chats) {
self.handle_get_chats(cv).await;
return;
}
if cv.is_type(CommunicationType::change_iota_data) if cv.is_type(CommunicationType::change_iota_data)
|| cv.is_type(CommunicationType::get_user_data) || cv.is_type(CommunicationType::get_user_data)
|| cv.is_type(CommunicationType::get_iota_data) || cv.is_type(CommunicationType::get_iota_data)
@ -510,6 +507,7 @@ impl IotaConnection {
let receiver_id = cv.get_receiver(); let receiver_id = cv.get_receiver();
let mut interested_ids: Vec<i64> = Vec::new(); let mut interested_ids: Vec<i64> = Vec::new();
// loading Calls
let calls: Vec<Arc<CallGroup>> = call_manager::get_call_groups(receiver_id).await; let calls: Vec<Arc<CallGroup>> = call_manager::get_call_groups(receiver_id).await;
let mut invites: HashMap<i64, Vec<JsonValue>> = HashMap::new(); let mut invites: HashMap<i64, Vec<JsonValue>> = HashMap::new();
let empty = &calls.is_empty(); let empty = &calls.is_empty();
@ -543,8 +541,7 @@ impl IotaConnection {
for user_json in user_ids { for user_json in user_ids {
let user_id = user_json["user_id"].as_i64().unwrap_or(0); let user_id = user_json["user_id"].as_i64().unwrap_or(0);
interested_ids.push(user_id); interested_ids.push(user_id);
let mut enriched_contact = JsonValue::new_object(); let mut enriched_contact = user_json.clone();
let _ = enriched_contact.insert("user_id", user_id);
if let Some(calls) = invites.get(&user_id) { if let Some(calls) = invites.get(&user_id) {
let _ = let _ =
enriched_contact.insert("calls", JsonValue::Array(calls.clone())); enriched_contact.insert("calls", JsonValue::Array(calls.clone()));
@ -575,8 +572,9 @@ impl IotaConnection {
async fn forward_to_client(&self, cv: CommunicationValue) { async fn forward_to_client(&self, cv: CommunicationValue) {
if let Some(rho_conn) = self.get_rho_connection().await { if let Some(rho_conn) = self.get_rho_connection().await {
let updated_cv = cv.with_sender(self.get_iota_id().await); let updated_cv = cv.with_sender(self.get_iota_id().await);
let _receiver_id = updated_cv.get_receiver();
rho_conn.message_to_client(updated_cv).await; rho_conn.message_to_client(updated_cv).await;
} else {
log_err!(PrintType::General, "Failed to forward message to client");
} }
} }

View file

@ -1,9 +1,13 @@
use super::{client_connection::ClientConnection, iota_connection::IotaConnection, rho_manager}; use super::{client_connection::ClientConnection, iota_connection::IotaConnection, rho_manager};
use crate::data::{
communication::{CommunicationType, CommunicationValue, DataTypes},
user::UserStatus,
};
use crate::omega::omega_connection::OmegaConnection; use crate::omega::omega_connection::OmegaConnection;
use crate::util::logger::PrintType;
use crate::{
data::{
communication::{CommunicationType, CommunicationValue, DataTypes},
user::UserStatus,
},
log,
};
use json::{JsonValue, number::Number}; use json::{JsonValue, number::Number};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@ -83,16 +87,12 @@ impl RhoConnection {
/// Remove a client connection /// Remove a client connection
pub async fn close_client_connection(&self, connection: Arc<ClientConnection>) { pub async fn close_client_connection(&self, connection: Arc<ClientConnection>) {
let target_user_id = connection.get_user_id().await;
{ {
let mut connections = self.client_connections.write().await; let mut connections = self.client_connections.write().await;
let target_user_id = connection.get_user_id().await;
connections.retain(|con| { connections.retain(|con| {
futures::executor::block_on(async { con.get_user_id().await != target_user_id }) futures::executor::block_on(async { con.get_user_id().await != target_user_id })
}); });
connections.push(Arc::clone(&connection));
} }
// Notify OmegaConnection // Notify OmegaConnection
@ -122,9 +122,10 @@ impl RhoConnection {
/// Send message from Iota to specific client /// Send message from Iota to specific client
pub async fn message_to_client(&self, cv: CommunicationValue) { pub async fn message_to_client(&self, cv: CommunicationValue) {
let connections = self.client_connections.read().await; let connections = self.client_connections.read().await;
let receiver_id = cv.get_receiver();
for connection in connections.iter() { for connection in connections.iter() {
if connection.get_user_id().await == cv.get_receiver() { if connection.get_user_id().await == receiver_id {
connection.send_message(&cv).await; connection.clone().send_message(&cv).await;
} }
} }
} }
@ -141,6 +142,7 @@ impl RhoConnection {
let conn_user_id = connection.get_user_id().await; let conn_user_id = connection.get_user_id().await;
if conn_user_id == user_id { if conn_user_id == user_id {
connection connection
.clone()
.set_interested_users(interested_ids.clone()) .set_interested_users(interested_ids.clone())
.await; .await;
break; break;
@ -152,7 +154,7 @@ impl RhoConnection {
pub async fn are_they_interested(&self, user: &crate::data::user::User) { pub async fn are_they_interested(&self, user: &crate::data::user::User) {
let connections = self.client_connections.read().await; let connections = self.client_connections.read().await;
for connection in connections.iter() { for connection in connections.iter() {
connection.are_you_interested(user).await; connection.clone().are_you_interested(user).await;
} }
} }