[WIP] MTP migration

This commit is contained in:
Alex Emmet 2026-07-03 20:17:20 +02:00
commit 0d24154af0
11 changed files with 379 additions and 286 deletions

View file

@ -5,7 +5,7 @@ use crate::rho::{rho_connection::RhoConnection, rho_manager};
use crate::util::logger::PrintType;
use crate::{log_cv_in, log_cv_out, log_err, log_in, log_out};
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataValue};
use mtp::transport::{Receiver, Sender};
use mtp::host::{Receiver, Sender};
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::sync::RwLock;
@ -129,7 +129,10 @@ impl AppConnection {
DataType::Avatar,
DataValue::Str(anonymous.get_avatar().await),
)
.add_typed_default(DataType::UserState, DataValue::Str("online".to_string()));
.add_typed_default(
DataType::UserState,
DataValue::Str("online".to_string()),
);
self.send_message(&response).await;
@ -183,7 +186,10 @@ impl AppConnection {
// Send pong response
let response = CommunicationValue::new(CommunicationType::Pong)
.with_id(cv.get_id())
.add_typed_default(DataType::PingIota, DataValue::SignedNumber(iota_ping.into()));
.add_typed_default(
DataType::PingIota,
DataValue::SignedNumber(iota_ping.into()),
);
self.send_message(&response).await;
}

View file

@ -7,7 +7,7 @@ use crate::util::logger::PrintType;
use crate::{data::user::UserStatus, omega::omega_connection::OmegaConnection};
use crate::{log_cv_in, log_cv_out, log_err, log_in, log_out};
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataValue};
use mtp::transport::{Receiver, Sender};
use mtp::host::{Receiver, Sender};
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
@ -158,11 +158,26 @@ impl ClientConnection {
} {
let response = CommunicationValue::new(CommunicationType::GetUserData)
.with_id(cv.get_id())
.add_typed_default(DataType::Username, DataValue::Str(anonymous.get_user_name().await))
.add_typed_default(DataType::UserId, DataValue::SignedNumber(anonymous.get_user_id().into()))
.add_typed_default(DataType::Display, DataValue::Str(anonymous.get_display_name().await))
.add_typed_default(DataType::Avatar, DataValue::Str(anonymous.get_avatar().await))
.add_typed_default(DataType::UserState, DataValue::Str("online".to_string()));
.add_typed_default(
DataType::Username,
DataValue::Str(anonymous.get_user_name().await),
)
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber(anonymous.get_user_id().into()),
)
.add_typed_default(
DataType::Display,
DataValue::Str(anonymous.get_display_name().await),
)
.add_typed_default(
DataType::Avatar,
DataValue::Str(anonymous.get_avatar().await),
)
.add_typed_default(
DataType::UserState,
DataValue::Str("online".to_string()),
);
self.send_message(&response).await;
@ -198,8 +213,14 @@ impl ClientConnection {
let response = CommunicationValue::new(CommunicationType::ErrorInvalidData)
.with_id(cv.get_id())
.with_receiver(self.user_id)
.add_typed_default(DataType::Message, DataValue::Str("Missing session_id".to_string()))
.add_typed_default(DataType::SessionId, DataValue::SignedNumber(expected_session_id));
.add_typed_default(
DataType::Message,
DataValue::Str("Missing session_id".to_string()),
)
.add_typed_default(
DataType::SessionId,
DataValue::SignedNumber(expected_session_id),
);
self.send_message(&response).await;
return;
};
@ -208,8 +229,14 @@ impl ClientConnection {
let response = CommunicationValue::new(CommunicationType::ErrorInvalidData)
.with_id(cv.get_id())
.with_receiver(self.user_id)
.add_typed_default(DataType::Message, DataValue::Str("session_id mismatch".to_string()))
.add_typed_default(DataType::SessionId, DataValue::SignedNumber(expected_session_id));
.add_typed_default(
DataType::Message,
DataValue::Str("session_id mismatch".to_string()),
)
.add_typed_default(
DataType::SessionId,
DataValue::SignedNumber(expected_session_id),
);
self.send_message(&response).await;
return;
}
@ -218,13 +245,22 @@ impl ClientConnection {
let response = CommunicationValue::new(CommunicationType::ErrorInvalidData)
.with_id(cv.get_id())
.with_receiver(self.user_id)
.add_typed_default(DataType::Message, DataValue::Str("session_id mismatch".to_string()))
.add_typed_default(DataType::SessionId, DataValue::SignedNumber(expected_session_id));
.add_typed_default(
DataType::Message,
DataValue::Str("session_id mismatch".to_string()),
)
.add_typed_default(
DataType::SessionId,
DataValue::SignedNumber(expected_session_id),
);
self.send_message(&response).await;
return;
}
} else {
cv = cv.add_typed_default(DataType::SessionId, DataValue::SignedNumber(expected_session_id));
cv = cv.add_typed_default(
DataType::SessionId,
DataValue::SignedNumber(expected_session_id),
);
}
}
@ -266,7 +302,10 @@ impl ClientConnection {
// Send pong response
let response = CommunicationValue::new(CommunicationType::Pong)
.with_id(cv.get_id())
.add_typed_default(DataType::PingIota, DataValue::SignedNumber(iota_ping.into()));
.add_typed_default(
DataType::PingIota,
DataValue::SignedNumber(iota_ping.into()),
);
self.send_message(&response).await;
}
@ -289,7 +328,10 @@ impl ClientConnection {
/// Handle call invite
async fn handle_call_invite(self: Arc<Self>, cv: CommunicationValue) {
let receiver_id: i128 = cv.get_data(DataType::ReceiverId).as_signed_number().unwrap_or(0);
let receiver_id: i128 = cv
.get_data(DataType::ReceiverId)
.as_signed_number()
.unwrap_or(0);
if receiver_id == 0 {
self.send_error_response(cv.get_id(), CommunicationType::ErrorNoUserId)
.await;
@ -334,9 +376,15 @@ impl ClientConnection {
// User is offline - send push notification for call invite
let push_cv = CommunicationValue::new(CommunicationType::PushNotification)
.with_receiver(receiver_id as u64)
.add_typed_default(DataType::SenderId, DataValue::SignedNumber(sender_id.into()))
.add_typed_default(
DataType::SenderId,
DataValue::SignedNumber(sender_id.into()),
)
.add_typed_default(DataType::CallId, DataValue::Str(call_id.to_string()))
.add_typed_default(DataType::Notifications, DataValue::Str("call_invite".to_string()));
.add_typed_default(
DataType::Notifications,
DataValue::Str("call_invite".to_string()),
);
let omega_conn = get_omega_connection();
// Send fire-and-forget, don't await to avoid blocking
@ -346,7 +394,10 @@ impl ClientConnection {
let error_cv = CommunicationValue::new(CommunicationType::ErrorNotFound)
.with_id(cv.get_id())
.add_typed_default(DataType::ReceiverId, DataValue::SignedNumber(receiver_id.into()));
.add_typed_default(
DataType::ReceiverId,
DataValue::SignedNumber(receiver_id.into()),
);
self.send_message(&error_cv).await;
return;
}
@ -359,10 +410,19 @@ impl ClientConnection {
let forward = CommunicationValue::new(CommunicationType::CallInvite)
.with_receiver(receiver_id as u64)
.with_sender(sender_id as u64)
.add_typed_default(DataType::CallSecret, cv.get_data(DataType::CallSecret).clone())
.add_typed_default(
DataType::CallSecret,
cv.get_data(DataType::CallSecret).clone(),
)
.add_typed_default(DataType::CallId, DataValue::Str(call_id.to_string()))
.add_typed_default(DataType::ReceiverId, DataValue::SignedNumber(receiver_id.into()))
.add_typed_default(DataType::SenderId, DataValue::SignedNumber(sender_id.into()));
.add_typed_default(
DataType::ReceiverId,
DataValue::SignedNumber(receiver_id.into()),
)
.add_typed_default(
DataType::SenderId,
DataValue::SignedNumber(sender_id.into()),
);
target_rho.message_to_client(forward).await;
@ -461,8 +521,14 @@ impl ClientConnection {
.await;
return;
};
let user_id = cv.get_data(DataType::UserId).as_signed_number().unwrap_or(0);
let untill = cv.get_data(DataType::Untill).as_signed_number().unwrap_or(0);
let user_id = cv
.get_data(DataType::UserId)
.as_signed_number()
.unwrap_or(0);
let untill = cv
.get_data(DataType::Untill)
.as_signed_number()
.unwrap_or(0);
let Some(call) = call_manager::get_call(call_id).await else {
self.send_error_response(cv.get_id(), CommunicationType::ErrorNotFound)
@ -489,7 +555,10 @@ impl ClientConnection {
.await;
return;
};
let user_id = cv.get_data(DataType::UserId).as_signed_number().unwrap_or(0);
let user_id = cv
.get_data(DataType::UserId)
.as_signed_number()
.unwrap_or(0);
let Some(call) = call_manager::get_call(call_id).await else {
self.send_error_response(cv.get_id(), CommunicationType::ErrorNotFound)
@ -546,7 +615,10 @@ impl ClientConnection {
let response =
CommunicationValue::new(CommunicationType::LoadTxtRecord)
.with_id(cv.get_id())
.add_typed_default(DataType::Content, DataValue::Str(s.to_string()));
.add_typed_default(
DataType::Content,
DataValue::Str(s.to_string()),
);
self.send_message(&response).await;
return;
}
@ -579,7 +651,10 @@ impl ClientConnection {
);
if cv.is_type(CommunicationType::AddConversation)
&& cv.get_data(DataType::ChatPartnerId).as_signed_number().is_none()
&& cv
.get_data(DataType::ChatPartnerId)
.as_signed_number()
.is_none()
{
let chat_partner_name = cv
.get_data(DataType::ChatPartnerName)
@ -600,7 +675,10 @@ impl ClientConnection {
.await_response(
&CommunicationValue::new(CommunicationType::GetUserData)
.with_id(cv.clone().get_id())
.add_typed_default(DataType::Username, DataValue::Str(chat_partner_name.clone())),
.add_typed_default(
DataType::Username,
DataValue::Str(chat_partner_name.clone()),
),
Some(Duration::from_secs(20)),
)
.await;
@ -665,7 +743,10 @@ impl ClientConnection {
);
let error_cv = CommunicationValue::new(CommunicationType::ErrorNoIota)
.with_id(msg_id)
.add_typed_default(DataType::UserId, DataValue::SignedNumber(sender_user_id.into()));
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber(sender_user_id.into()),
);
self.send_message(&error_cv).await;
}
}

View file

@ -1,15 +1,15 @@
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue};
use mtp::transport::{Receiver, Sender};
use mtp::host::{Receiver, Sender};
use rand::{Rng, distributions::Alphanumeric};
use std::{collections::BTreeMap, collections::HashMap, sync::Arc, time::Duration};
use tokio::sync::RwLock;
use uuid::Uuid;
use base64::engine::general_purpose::STANDARD as BASE64_STD;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD as BASE64_STD;
use mtp::crypto::{
encrypt_for, EncryptionType, KemPublicKey, PublicKeyBundle, SignaturePqPublicKey,
SignaturePublicKey,
EncryptionType, KemPublicKey, PublicKeyBundle, SignaturePqPublicKey, SignaturePublicKey,
encrypt_for,
};
use crate::{
@ -179,15 +179,11 @@ impl GeneralConnection {
.unwrap(),
);
let our_pk = BASE64_STD.encode(
get_keyring().public_key_bundle().kem_public_key.as_bytes(),
);
let our_pk =
BASE64_STD.encode(get_keyring().public_key_bundle().kem_public_key.as_bytes());
let response = CommunicationValue::new(CommunicationType::AppChallenge)
.with_id(cv.get_id())
.add_typed_default(
DataType::PublicKey,
DataValue::Str(our_pk),
)
.add_typed_default(DataType::PublicKey, DataValue::Str(our_pk))
.add_typed_default(DataType::Challenge, DataValue::Str(encrypted_challenge));
log_cv_out!(response);
@ -267,15 +263,11 @@ impl GeneralConnection {
.unwrap(),
);
let our_pk = BASE64_STD.encode(
get_keyring().public_key_bundle().kem_public_key.as_bytes(),
);
let our_pk =
BASE64_STD.encode(get_keyring().public_key_bundle().kem_public_key.as_bytes());
let response = CommunicationValue::new(CommunicationType::Challenge)
.with_id(cv.get_id())
.add_typed_default(
DataType::PublicKey,
DataValue::Str(our_pk),
)
.add_typed_default(DataType::PublicKey, DataValue::Str(our_pk))
.add_typed_default(DataType::Challenge, DataValue::Str(encrypted_challenge));
log_cv_out!(response);
@ -370,16 +362,12 @@ impl GeneralConnection {
CommunicationType::Challenge
};
let our_pk = BASE64_STD.encode(
get_keyring().public_key_bundle().kem_public_key.as_bytes(),
);
let our_pk =
BASE64_STD.encode(get_keyring().public_key_bundle().kem_public_key.as_bytes());
let response = CommunicationValue::new(challenge_type)
.with_id(cv.get_id())
.with_receiver(*self.session_id.read().await)
.add_typed_default(
DataType::PublicKey,
DataValue::Str(our_pk),
)
.add_typed_default(DataType::PublicKey, DataValue::Str(our_pk))
.add_typed_default(DataType::Challenge, DataValue::Str(encrypted_challenge));
log_cv_out!(response);
@ -440,7 +428,10 @@ impl GeneralConnection {
match kind {
ConnectionKind::Client => {
let notify = CommunicationValue::new(CommunicationType::UserConnected)
.add_typed_default(DataType::UserId, DataValue::SignedNumber((id as i64).into()));
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber((id as i64).into()),
);
get_omega_connection().send_message(&notify).await;
let user_id = id as i64;
@ -451,7 +442,10 @@ impl GeneralConnection {
if rho.is_none() {
let get_user_msg = CommunicationValue::new(CommunicationType::GetUserData)
.add_typed_default(DataType::UserId, DataValue::SignedNumber(user_id.into()));
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber(user_id.into()),
);
if let Ok(user_data_cv) = get_omega_connection()
.await_response(&get_user_msg, Some(Duration::from_secs(20)))
@ -475,8 +469,14 @@ impl GeneralConnection {
if let Some(rho_conn) = rho {
let session_id = *self.session_id.read().await as i64;
let iota_msg = CommunicationValue::new(CommunicationType::ClientConnected)
.add_typed_default(DataType::UserId, DataValue::SignedNumber(user_id.into()))
.add_typed_default(DataType::SessionId, DataValue::SignedNumber(session_id.into()));
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber(user_id.into()),
)
.add_typed_default(
DataType::SessionId,
DataValue::SignedNumber(session_id.into()),
);
if let Ok(resp) = rho_conn
.get_iota_connection()
@ -526,7 +526,9 @@ impl GeneralConnection {
if timeout > 0 {
base_call_map.insert(
DataType::Timeout.to_id(&tm),
DataValue::SignedNumber((timeout as i64).into()),
DataValue::SignedNumber(
(timeout as i64).into(),
),
);
}
@ -578,7 +580,8 @@ impl GeneralConnection {
if let Some(DataValue::SignedNumber(id)) =
contact_map.get(&DataType::UserId.to_id(&tm))
{
if let Some(call_list) = invites.get(&(*id as i64)) {
if let Some(call_list) = invites.get(&(*id as i64))
{
contact_map.insert(
DataType::Calls.to_id(&tm),
DataValue::Array(call_list.clone()),
@ -592,8 +595,10 @@ impl GeneralConnection {
}
}
ident_resp = ident_resp
.add_typed_default(DataType::Calls, DataValue::Array(global_calls));
ident_resp = ident_resp.add_typed_default(
DataType::Calls,
DataValue::Array(global_calls),
);
DataValue::Array(new_contacts)
} else {
v.clone()
@ -672,7 +677,10 @@ impl GeneralConnection {
if rho.is_none() {
let get_user_msg = CommunicationValue::new(CommunicationType::GetUserData)
.add_typed_default(DataType::UserId, DataValue::SignedNumber(user_id.into()));
.add_typed_default(
DataType::UserId,
DataValue::SignedNumber(user_id.into()),
);
if let Ok(user_data_cv) = get_omega_connection()
.await_response(&get_user_msg, Some(Duration::from_secs(20)))

View file

@ -14,13 +14,13 @@ use mtp::codec::DataType;
use mtp::codec::DataTypeId;
use mtp::codec::DataValue;
use mtp::codec::TypeMap;
use mtp::transport::Receiver;
use mtp::transport::Sender;
use mtp::crypto::KemPublicKey;
use mtp::host::Receiver;
use mtp::host::Sender;
use std::collections::BTreeMap;
use std::{collections::HashMap, sync::Arc, time::Duration};
use tokio::sync::RwLock;
use tokio::sync::mpsc;
use mtp::crypto::KemPublicKey;
use super::{rho_connection::RhoConnection, rho_manager};
use crate::omega::omega_connection::OmegaConnection;
@ -265,7 +265,10 @@ impl IotaConnection {
if let Ok(uid) = k.parse::<i128>() {
map.insert(DataType::UserId.to_id(&tm), DataValue::SignedNumber(uid));
}
map.insert(DataType::LastPing.to_id(&tm), DataValue::SignedNumber(v.into()));
map.insert(
DataType::LastPing.to_id(&tm),
DataValue::SignedNumber(v.into()),
);
DataValue::container_from_map(&map)
})
.collect();
@ -368,12 +371,20 @@ impl IotaConnection {
// Build base call container
let mut base_call_map: BTreeMap<DataTypeId, DataValue> = BTreeMap::new();
base_call_map.insert(DataType::CallId.to_id(&tm), DataValue::Str(call.call_id.to_string()));
base_call_map.insert(DataType::CallMembers.to_id(&tm), DataValue::Array(member_ids));
base_call_map.insert(
DataType::CallId.to_id(&tm),
DataValue::Str(call.call_id.to_string()),
);
base_call_map.insert(
DataType::CallMembers.to_id(&tm),
DataValue::Array(member_ids),
);
if timeout > 0 {
base_call_map
.insert(DataType::Timeout.to_id(&tm), DataValue::SignedNumber(timeout.into()));
base_call_map.insert(
DataType::Timeout.to_id(&tm),
DataValue::SignedNumber(timeout.into()),
);
}
if admin {
@ -394,8 +405,10 @@ impl IotaConnection {
// Add secret if it exists for this pairing
if let Some(secret) = call.secrets.read().await.get(&(member_id, user_id)) {
contact_call_map
.insert(DataType::CallSecret.to_id(&tm), DataValue::Str(secret.clone()));
contact_call_map.insert(
DataType::CallSecret.to_id(&tm),
DataValue::Str(secret.clone()),
);
}
invites
@ -423,14 +436,18 @@ impl IotaConnection {
let mut user_map: BTreeMap<DataTypeId, DataValue> =
entries.iter().cloned().collect();
if let Some(DataValue::SignedNumber(id)) = user_map.get(&DataType::UserId.to_id(&tm)) {
if let Some(DataValue::SignedNumber(id)) =
user_map.get(&DataType::UserId.to_id(&tm))
{
interested_ids.push(*id as i64);
if let Some(call_list) = invites.get(&(*id as i64))
&& !call_list.is_empty()
{
user_map
.insert(DataType::Calls.to_id(&tm), DataValue::Array(call_list.clone()));
user_map.insert(
DataType::Calls.to_id(&tm),
DataValue::Array(call_list.clone()),
);
}
}

View file

@ -1,46 +1,81 @@
use std::net::{IpAddr, Ipv4Addr};
use std::time::Duration;
use crate::load_keyring;
use crate::{
log,
rho::connection::GeneralConnection,
util::{file_util::load_file_vec, logger::PrintType},
};
use mtp::transport::{Host, Policy, SendMode, host};
use mtp::crypto::PublicKeyBundle;
use mtp::host::{AuthenticationPolicy, Host, HostConfig, Policy, SendMode};
pub async fn get_by_connector_id(
_client_id: u64,
description: Option<String>,
) -> Option<PublicKeyBundle> {
if let Some(description) = description {
if description == "iota" {
todo!()
} else if description == "client" {
todo!()
} else if description == "anonymous" {
todo!()
} else if description == "app" {
todo!()
}
}
None
}
pub async fn complete_register(_pub_key: PublicKeyBundle, description: Option<String>) -> u64 {
if let Some(description) = description {
if description == "iota" {
todo!()
}
}
0
}
pub async fn start(port: u16) -> Result<(), Box<dyn std::error::Error>> {
let cert_pem = load_file_vec("certs", "cert.pem").expect("Error loading Pemfile");
let key_pem = load_file_vec("certs", "key.pem").expect("Error loading Keyfile");
let mut host: Host = host(
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
let host_config = HostConfig::new(
IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)),
port,
cert_pem,
key_pem,
Policy {
send_mode: SendMode::SingleStreamPerMessage,
max_message_size: 1_000_000_000,
close_frame_len: u32::MAX,
application_close_code: 0,
open_stream_timeout: Duration::from_millis(2_000),
write_timeout: Duration::from_millis(2_000),
accept_stream_timeout: Duration::from_millis(10_000),
read_timeout: Duration::from_millis(30_000),
keep_alive_interval: Some(Duration::from_secs(6)),
max_idle_timeout: Some(Duration::from_secs(30)),
force_close_delay: Duration::from_millis(300),
max_transient_recv_errors: 20,
transient_recv_backoff: Duration::from_millis(100),
receiver_queue_capacity: 1000,
},
)
.await?;
.with_policy(Policy {
send_mode: SendMode::SingleStreamPerMessage,
max_message_size: 1_000_000_000,
close_frame_len: u32::MAX,
application_close_code: 0,
open_stream_timeout: Duration::from_millis(2_000),
write_timeout: Duration::from_millis(2_000),
accept_stream_timeout: Duration::from_millis(10_000),
read_timeout: Duration::from_millis(30_000),
keep_alive_interval: Some(Duration::from_secs(6)),
max_idle_timeout: Some(Duration::from_secs(30)),
force_close_delay: Duration::from_millis(300),
max_transient_recv_errors: 20,
transient_recv_backoff: Duration::from_millis(100),
receiver_queue_capacity: 1000,
})
.with_authentication(
load_keyring(),
Box::new(|user_id, description| Box::pin(get_by_connector_id(user_id, description))),
Box::new(|pub_key, description| Box::pin(complete_register(pub_key, description))),
)
.with_authentication_policy(AuthenticationPolicy::AllowAuthentication);
let mut host: Host = Host::new(host_config).await?;
log!(0, PrintType::General, "Server listening on port {}", port);
while let Some((sender, receiver)) = host.next().await {
while let Ok(Some(conn)) = host.accept().await {
tokio::spawn(async move {
let conn = GeneralConnection::new(sender, receiver);
let conn = GeneralConnection::new(conn.sender, conn.receiver);
conn.handle().await;
});
}