diff --git a/Cargo.lock b/Cargo.lock index 6b3df76..aa15ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" dependencies = [ "cc", "cmake", @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.57" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ "find-msvc-tools", "jobserver", @@ -1882,10 +1882,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1955,9 +1957,9 @@ dependencies = [ [[package]] name = "line-clipping" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" dependencies = [ "bitflags 2.11.0", ] @@ -2102,9 +2104,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "log", @@ -3040,9 +3042,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -3348,9 +3350,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "siphasher" @@ -3877,7 +3879,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttp-core" version = "0.1.0" -source = "git+https://github.com/Tensamin/TTP.git#9c0ed7a5b6c8735e4b674d4503bd7b936ee3656b" +source = "git+https://github.com/Tensamin/TTP.git#23c9e68da6622a0cb3a773881f353ae4489c9743" dependencies = [ "base64", "byteorder", @@ -3889,7 +3891,7 @@ dependencies = [ [[package]] name = "ttp-native" version = "0.1.0" -source = "git+https://github.com/Tensamin/TTP.git#9c0ed7a5b6c8735e4b674d4503bd7b936ee3656b" +source = "git+https://github.com/Tensamin/TTP.git#23c9e68da6622a0cb3a773881f353ae4489c9743" dependencies = [ "quinn", "rustls", @@ -4018,9 +4020,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ "atomic", "getrandom 0.4.2", @@ -4121,9 +4123,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" dependencies = [ "cfg-if", "once_cell", @@ -4134,23 +4136,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4158,9 +4156,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" dependencies = [ "bumpalo", "proc-macro2", @@ -4171,9 +4169,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" dependencies = [ "unicode-ident", ] @@ -4214,9 +4212,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/src/omikron/omikron_connection.rs b/src/omikron/omikron_connection.rs index 83b9dcf..3d60510 100755 --- a/src/omikron/omikron_connection.rs +++ b/src/omikron/omikron_connection.rs @@ -434,8 +434,22 @@ impl OmikronConnection { let sender_id = &cv.get_sender(); let receiver_id = &cv.get_receiver(); + // Parse send_time robustly: accept numeric or string, fallback to current time + let send_time_val = cv.get_data(DataTypes::send_time); + let now_i64 = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as i64; + let timestamp_i64 = if let Some(n) = send_time_val.as_number() { + n as i64 + } else if let Some(s) = send_time_val.as_str() { + s.parse::().unwrap_or(now_i64) + } else { + now_i64 + }; + let _ = chat_files::change_message_state( - cv.get_data(DataTypes::send_time).as_number().unwrap_or(0) as i64, + timestamp_i64, *receiver_id as i64, *sender_id as i64, MessageState::from_str( @@ -447,19 +461,34 @@ impl OmikronConnection { if cv.is_type(CommunicationType::message_other_iota) { let sender_id = &cv.get_sender(); let receiver_id = &cv.get_receiver(); - let timestamp = cv.get_data(DataTypes::send_time).as_number().unwrap_or( - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() as i64, - ); + + // parse send_time safely (number or string), fallback to now + let send_time_val = cv.get_data(DataTypes::send_time); + let now_i64 = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as i64; + let timestamp = if let Some(n) = send_time_val.as_number() { + n as i64 + } else if let Some(s) = send_time_val.as_str() { + s.parse::().unwrap_or(now_i64) + } else { + now_i64 + }; + + // content may be missing or non-string; default to empty string + let content = cv + .get_data(DataTypes::content) + .as_str() + .unwrap_or("") + .to_string(); chat_files::add_message( timestamp as u128, false, *receiver_id as i64, *sender_id as i64, - cv.get_data(DataTypes::content).as_str().unwrap(), + &content, ); let user_forward = CommunicationValue::new(CommunicationType::message_live) @@ -481,13 +510,12 @@ impl OmikronConnection { .await; if let Ok(user_resp) = user_resp { - let ms = MessageState::from_str( - &user_resp - .get_data(DataTypes::message_state) - .as_string() - .unwrap_or("".to_string()), - ) - .upgrade(MessageState::Received); + let ms_raw = user_resp + .get_data(DataTypes::message_state) + .as_string() + .unwrap_or_else(|| "".to_string()); + let ms = MessageState::from_str(&ms_raw).upgrade(MessageState::Received); + let _ = change_message_state( timestamp, *receiver_id as i64, @@ -532,19 +560,37 @@ impl OmikronConnection { if cv.is_type(CommunicationType::message_send) { let my_id = cv.get_sender(); - let other_id = cv.get_data(DataTypes::receiver_id).as_number().unwrap_or(0); - let now_ms = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() as u128; - chat_files::add_message( - now_ms, - true, - my_id as i64, - other_id, - &*cv.get_data(DataTypes::content).as_str().unwrap(), - ); + // parse other id robustly (number or string) + let other_id = if let Some(n) = cv.get_data(DataTypes::receiver_id).as_number() { + n as i64 + } else if let Some(s) = cv.get_data(DataTypes::receiver_id).as_str() { + s.parse::().unwrap_or(0) + } else { + 0 + }; + + let now_ms_u128 = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as u128; + // derive an i64 timestamp for protocol fields; fall back to current time if out of range + let now_ms_i64: i64 = match i64::try_from(now_ms_u128) { + Ok(v) => v, + Err(_) => SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as i64, + }; + + // safe content extraction + let content = cv + .get_data(DataTypes::content) + .as_str() + .unwrap_or("") + .to_string(); + + chat_files::add_message(now_ms_u128, true, my_id as i64, other_id, &content); let ack = CommunicationValue::new(CommunicationType::success) .with_id(cv.get_id()) @@ -556,18 +602,21 @@ impl OmikronConnection { .with_receiver(other_id as u64) .add_data(DataTypes::receiver_id, DataValue::Number(other_id)) .with_sender(my_id) - .add_data(DataTypes::send_time, DataValue::Str(now_ms.to_string())) + .add_data(DataTypes::send_time, DataValue::Number(now_ms_i64)) .add_data(DataTypes::sender_id, DataValue::Number(my_id as i64)) - .add_data( - DataTypes::content, - DataValue::Str( - cv.get_data(DataTypes::content) - .as_str() - .unwrap() - .to_string(), - ), + .add_data(DataTypes::content, DataValue::Str(content)); + if let Err(err) = self.send_message_result(&forward).await { + // sending failed - record via existing logging path + log_t!("send_message_failed", err); + } else { + // forwarding succeeded -> update stored message state to Sent + let _ = chat_files::change_message_state( + now_ms_i64, + my_id as i64, + other_id, + MessageState::Sent, ); - self.send_message(&forward).await; + } return; } @@ -576,11 +625,45 @@ impl OmikronConnection { let partner_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0); let offset = cv.get_data(DataTypes::offset).as_number().unwrap_or(0); let amount = cv.get_data(DataTypes::amount).as_number().unwrap_or(0); + // retrieve raw JSON messages let messages = chat_files::get_messages(my_id as i64, partner_id, offset, amount); + // convert JSON array -> protocol Array of Containers (send_time, content, sender_id, message_state) + let mut msg_array: Vec = Vec::new(); + for m in messages.members() { + // extract fields defensively + let message_time: i64 = m["message_time"].as_i64().unwrap_or(0); + let content: String = m["content"].as_str().unwrap_or("").to_string(); + let sent_by_self: bool = m["sent_by_self"].as_bool().unwrap_or(false); + // determine sender id: + // - if sent_by_self => sender is the requester (my_id) + // - otherwise prefer an explicit chat_partner_id if present on the request, + // fallback to the partner_id parameter + let sender_id: i64 = if sent_by_self { + my_id as i64 + } else { + // check for chat_partner_id in the incoming request (accept number or string) + if let Some(n) = cv.get_data(DataTypes::chat_partner_id).as_number() { + n as i64 + } else if let Some(s) = cv.get_data(DataTypes::chat_partner_id).as_str() { + s.parse::().unwrap_or(partner_id as i64) + } else { + partner_id as i64 + } + }; + let message_state: String = m["message_state"].as_str().unwrap_or("").to_string(); + + let mut container = Vec::new(); + container.push((DataTypes::send_time, DataValue::Number(message_time))); + container.push((DataTypes::message, DataValue::Str(content))); + container.push((DataTypes::sender_id, DataValue::Number(sender_id))); + container.push((DataTypes::message_state, DataValue::Str(message_state))); + msg_array.push(DataValue::Container(container)); + } + let resp = CommunicationValue::new(CommunicationType::messages_get) .with_id(cv.get_id()) .with_receiver(my_id) - .add_data(DataTypes::messages, DataValue::Str(messages.dump())); + .add_data(DataTypes::messages, DataValue::Array(msg_array)); self.send_message(&resp).await; return; diff --git a/src/util/chat_files.rs b/src/util/chat_files.rs index de6013b..bfdc184 100644 --- a/src/util/chat_files.rs +++ b/src/util/chat_files.rs @@ -3,6 +3,7 @@ use crate::util::file_util::get_directory; use json::{JsonValue, array, object}; use rusqlite::{Connection, params}; use std::io; +use std::sync::{LazyLock, Mutex}; #[derive(PartialEq, Debug, Clone)] pub enum MessageState { @@ -44,12 +45,9 @@ impl MessageState { } } -fn db_path() -> String { - format!("{}/messages.sqlite3", get_directory()) -} - -fn open_db() -> rusqlite::Result { - let conn = Connection::open(db_path())?; +static DB_CONN: LazyLock> = LazyLock::new(|| { + let conn = Connection::open(format!("{}/messages.sqlite3", get_directory())) + .expect("Failed to open messages sqlite DB"); conn.execute_batch( r#" PRAGMA journal_mode = WAL; @@ -68,9 +66,10 @@ fn open_db() -> rusqlite::Result { CREATE INDEX IF NOT EXISTS idx_messages_lookup ON messages (storage_owner, external_user, message_time DESC); "#, - )?; - Ok(conn) -} + ) + .expect("Failed to initialize messages DB"); + Mutex::new(conn) +}); pub fn add_message( send_time: u128, @@ -87,10 +86,10 @@ pub fn add_message( } }; - let conn = match open_db() { - Ok(c) => c, + let conn = match DB_CONN.lock() { + Ok(g) => g, Err(e) => { - log!("Failed to open sqlite db for add_message: {}", e); + log!("Failed to lock messages DB mutex for add_message: {:?}", e); return; } }; @@ -129,7 +128,9 @@ pub fn change_message_state( external_user: i64, new_state: MessageState, ) -> io::Result<()> { - let conn = open_db().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + let conn = DB_CONN + .lock() + .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Mutex lock error: {:?}", e)))?; let current: Option = match conn.query_row( r#" @@ -191,10 +192,10 @@ pub fn get_messages( return messages; } - let conn = match open_db() { - Ok(c) => c, + let conn = match DB_CONN.lock() { + Ok(g) => g, Err(e) => { - log!("Failed to open sqlite db for get_messages: {}", e); + log!("Failed to lock messages DB mutex for get_messages: {:?}", e); return messages; } };