[Add] get chats now returns Array of Containers instead of String

This commit is contained in:
Alex Emmet 2026-03-28 23:02:45 +01:00
commit b53203f8a7
3 changed files with 168 additions and 86 deletions

66
Cargo.lock generated
View file

@ -426,9 +426,9 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-sys" name = "aws-lc-sys"
version = "0.39.0" version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399"
dependencies = [ dependencies = [
"cc", "cc",
"cmake", "cmake",
@ -552,9 +552,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.57" version = "1.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@ -1882,10 +1882,12 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.91" version = "0.3.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995"
dependencies = [ dependencies = [
"cfg-if",
"futures-util",
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1955,9 +1957,9 @@ dependencies = [
[[package]] [[package]]
name = "line-clipping" name = "line-clipping"
version = "0.3.5" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a" checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8"
dependencies = [ dependencies = [
"bitflags 2.11.0", "bitflags 2.11.0",
] ]
@ -2102,9 +2104,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@ -3040,9 +3042,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
@ -3348,9 +3350,9 @@ dependencies = [
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]] [[package]]
name = "siphasher" name = "siphasher"
@ -3877,7 +3879,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "ttp-core" name = "ttp-core"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/Tensamin/TTP.git#9c0ed7a5b6c8735e4b674d4503bd7b936ee3656b" source = "git+https://github.com/Tensamin/TTP.git#23c9e68da6622a0cb3a773881f353ae4489c9743"
dependencies = [ dependencies = [
"base64", "base64",
"byteorder", "byteorder",
@ -3889,7 +3891,7 @@ dependencies = [
[[package]] [[package]]
name = "ttp-native" name = "ttp-native"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/Tensamin/TTP.git#9c0ed7a5b6c8735e4b674d4503bd7b936ee3656b" source = "git+https://github.com/Tensamin/TTP.git#23c9e68da6622a0cb3a773881f353ae4489c9743"
dependencies = [ dependencies = [
"quinn", "quinn",
"rustls", "rustls",
@ -4018,9 +4020,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.22.0" version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
dependencies = [ dependencies = [
"atomic", "atomic",
"getrandom 0.4.2", "getrandom 0.4.2",
@ -4121,9 +4123,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.114" version = "0.2.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@ -4134,23 +4136,19 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.64" version = "0.4.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0"
dependencies = [ dependencies = [
"cfg-if",
"futures-util",
"js-sys", "js-sys",
"once_cell",
"wasm-bindgen", "wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.114" version = "0.2.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -4158,9 +4156,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.114" version = "0.2.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@ -4171,9 +4169,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.114" version = "0.2.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -4214,9 +4212,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.91" version = "0.3.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View file

@ -434,8 +434,22 @@ impl OmikronConnection {
let sender_id = &cv.get_sender(); let sender_id = &cv.get_sender();
let receiver_id = &cv.get_receiver(); 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::<i64>().unwrap_or(now_i64)
} else {
now_i64
};
let _ = chat_files::change_message_state( 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, *receiver_id as i64,
*sender_id as i64, *sender_id as i64,
MessageState::from_str( MessageState::from_str(
@ -447,19 +461,34 @@ impl OmikronConnection {
if cv.is_type(CommunicationType::message_other_iota) { if cv.is_type(CommunicationType::message_other_iota) {
let sender_id = &cv.get_sender(); let sender_id = &cv.get_sender();
let receiver_id = &cv.get_receiver(); let receiver_id = &cv.get_receiver();
let timestamp = cv.get_data(DataTypes::send_time).as_number().unwrap_or(
SystemTime::now() // 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) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap_or_default()
.as_millis() as i64, .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::<i64>().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( chat_files::add_message(
timestamp as u128, timestamp as u128,
false, false,
*receiver_id as i64, *receiver_id as i64,
*sender_id as i64, *sender_id as i64,
cv.get_data(DataTypes::content).as_str().unwrap(), &content,
); );
let user_forward = CommunicationValue::new(CommunicationType::message_live) let user_forward = CommunicationValue::new(CommunicationType::message_live)
@ -481,13 +510,12 @@ impl OmikronConnection {
.await; .await;
if let Ok(user_resp) = user_resp { if let Ok(user_resp) = user_resp {
let ms = MessageState::from_str( let ms_raw = user_resp
&user_resp
.get_data(DataTypes::message_state) .get_data(DataTypes::message_state)
.as_string() .as_string()
.unwrap_or("".to_string()), .unwrap_or_else(|| "".to_string());
) let ms = MessageState::from_str(&ms_raw).upgrade(MessageState::Received);
.upgrade(MessageState::Received);
let _ = change_message_state( let _ = change_message_state(
timestamp, timestamp,
*receiver_id as i64, *receiver_id as i64,
@ -532,19 +560,37 @@ impl OmikronConnection {
if cv.is_type(CommunicationType::message_send) { if cv.is_type(CommunicationType::message_send) {
let my_id = cv.get_sender(); 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( // parse other id robustly (number or string)
now_ms, let other_id = if let Some(n) = cv.get_data(DataTypes::receiver_id).as_number() {
true, n as i64
my_id as i64, } else if let Some(s) = cv.get_data(DataTypes::receiver_id).as_str() {
other_id, s.parse::<i64>().unwrap_or(0)
&*cv.get_data(DataTypes::content).as_str().unwrap(), } 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) let ack = CommunicationValue::new(CommunicationType::success)
.with_id(cv.get_id()) .with_id(cv.get_id())
@ -556,18 +602,21 @@ impl OmikronConnection {
.with_receiver(other_id as u64) .with_receiver(other_id as u64)
.add_data(DataTypes::receiver_id, DataValue::Number(other_id)) .add_data(DataTypes::receiver_id, DataValue::Number(other_id))
.with_sender(my_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::sender_id, DataValue::Number(my_id as i64))
.add_data( .add_data(DataTypes::content, DataValue::Str(content));
DataTypes::content, if let Err(err) = self.send_message_result(&forward).await {
DataValue::Str( // sending failed - record via existing logging path
cv.get_data(DataTypes::content) log_t!("send_message_failed", err);
.as_str() } else {
.unwrap() // forwarding succeeded -> update stored message state to Sent
.to_string(), let _ = chat_files::change_message_state(
), now_ms_i64,
my_id as i64,
other_id,
MessageState::Sent,
); );
self.send_message(&forward).await; }
return; return;
} }
@ -576,11 +625,45 @@ impl OmikronConnection {
let partner_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0); 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 offset = cv.get_data(DataTypes::offset).as_number().unwrap_or(0);
let amount = cv.get_data(DataTypes::amount).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); 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<DataValue> = 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::<i64>().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) let resp = CommunicationValue::new(CommunicationType::messages_get)
.with_id(cv.get_id()) .with_id(cv.get_id())
.with_receiver(my_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; self.send_message(&resp).await;
return; return;

View file

@ -3,6 +3,7 @@ use crate::util::file_util::get_directory;
use json::{JsonValue, array, object}; use json::{JsonValue, array, object};
use rusqlite::{Connection, params}; use rusqlite::{Connection, params};
use std::io; use std::io;
use std::sync::{LazyLock, Mutex};
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum MessageState { pub enum MessageState {
@ -44,12 +45,9 @@ impl MessageState {
} }
} }
fn db_path() -> String { static DB_CONN: LazyLock<Mutex<Connection>> = LazyLock::new(|| {
format!("{}/messages.sqlite3", get_directory()) let conn = Connection::open(format!("{}/messages.sqlite3", get_directory()))
} .expect("Failed to open messages sqlite DB");
fn open_db() -> rusqlite::Result<Connection> {
let conn = Connection::open(db_path())?;
conn.execute_batch( conn.execute_batch(
r#" r#"
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
@ -68,9 +66,10 @@ fn open_db() -> rusqlite::Result<Connection> {
CREATE INDEX IF NOT EXISTS idx_messages_lookup CREATE INDEX IF NOT EXISTS idx_messages_lookup
ON messages (storage_owner, external_user, message_time DESC); ON messages (storage_owner, external_user, message_time DESC);
"#, "#,
)?; )
Ok(conn) .expect("Failed to initialize messages DB");
} Mutex::new(conn)
});
pub fn add_message( pub fn add_message(
send_time: u128, send_time: u128,
@ -87,10 +86,10 @@ pub fn add_message(
} }
}; };
let conn = match open_db() { let conn = match DB_CONN.lock() {
Ok(c) => c, Ok(g) => g,
Err(e) => { Err(e) => {
log!("Failed to open sqlite db for add_message: {}", e); log!("Failed to lock messages DB mutex for add_message: {:?}", e);
return; return;
} }
}; };
@ -129,7 +128,9 @@ pub fn change_message_state(
external_user: i64, external_user: i64,
new_state: MessageState, new_state: MessageState,
) -> io::Result<()> { ) -> 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<String> = match conn.query_row( let current: Option<String> = match conn.query_row(
r#" r#"
@ -191,10 +192,10 @@ pub fn get_messages(
return messages; return messages;
} }
let conn = match open_db() { let conn = match DB_CONN.lock() {
Ok(c) => c, Ok(g) => g,
Err(e) => { 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; return messages;
} }
}; };