[WIP] Migration to TTP

This commit is contained in:
Alex Emmet 2026-03-09 18:45:52 +01:00
commit 6f3bf3692d
20 changed files with 1644 additions and 2240 deletions

1580
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,23 +4,18 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
actix = "0.13.5" epsilon-core = { git = "https://github.com/Tensamin/Epsilon.git", package = "epsilon-core" }
actix-rt = "2.11.0" epsilon-native = { git = "https://github.com/Tensamin/Epsilon.git", package = "epsilon-native" }
actix-web = { version = "4", features = ["rustls-0_23"] } actix-web = { version = "4", features = ["rustls-0_23"] }
actix-web-actors = "4" actix-web-actors = "4"
actix-files = "0.6"
aes-gcm = "*" aes-gcm = "*"
base64 = "0.22.1" base64 = "0.22.1"
bytes = "*"
cmake = "*"
color-eyre = "*"
crossterm = "*" crossterm = "*"
der = "*"
futures = "*" futures = "*"
futures-util = "*" futures-util = "*"
hex = "*" hex = "*"
hkdf = "*" hkdf = "*"
hmac = "*"
hyper-util = { version = "*" } hyper-util = { version = "*" }
hyper = { version = "1.8.1", features = [ hyper = { version = "1.8.1", features = [
"capi", "capi",
@ -31,45 +26,29 @@ hyper = { version = "1.8.1", features = [
"nightly", "nightly",
"server", "server",
] } ] }
http-body-util = "*"
json = "*" json = "*"
native-tls = { version = "*", default-features = false }
once_cell = "1.21.3" once_cell = "1.21.3"
pkcs8 = { version = "*", features = ["alloc"] }
rand = "0.8" rand = "0.8"
rand_core = { version = "0.6", features = ["getrandom", "std"] } rand_core = { version = "0.6", features = ["getrandom", "std"] }
reactive-rs = "*" reqwest = "0.13.2"
aws-lc-rs = "*" rustls = { version = "0.23.37", features = ["aws-lc-rs"] }
reqwest = "0.12.23"
rustls = { version = "*", features = ["aws-lc-rs"] }
serde = { version = "1.0.219", features = ["derive"] }
sha2 = "*" sha2 = "*"
sys-info = "*" sysinfo = "0.38.3"
sysinfo = "0.30" tokio = { version = "1.50.0", features = ["full"] }
tokio = { version = "1.48.0", features = ["full"] }
tokio-util = { version = "*", features = ["full"] }
tokio-tungstenite = { version = "*", features = ["native-tls"] } tokio-tungstenite = { version = "*", features = ["native-tls"] }
tower = "*"
tungstenite = "*" tungstenite = "*"
uuid = { version = "*", features = ["v4"] } uuid = { version = "*", features = ["v4"] }
walkdir = "2.5.0" walkdir = "2.5.0"
warp = "*" warp = "*"
x448 = { version = "*" } x448 = { version = "*" }
x509 = "*"
tokio-rustls = "0.26.4"
rustls-pemfile = "2.2.0" rustls-pemfile = "2.2.0"
async-trait = "0.1.89" async-trait = "0.1.89"
sha1 = "0.10.6"
async-tungstenite = "0.32.0"
zip = "6.0.0" zip = "6.0.0"
tui-textarea = "0.7.0"
tui-input = "0.14.0"
pnet = "0.35.0" pnet = "0.35.0"
dashmap = "6.1.0" dashmap = "6.1.0"
strum = "0.27.2" strum = "0.27.2"
strum_macros = "0.27.2" strum_macros = "0.27.2"
ratatui = "0.30.0" ratatui = "0.30.0"
ratatui_input = "0.1.3"
open = "5.3.3" open = "5.3.3"
chrono = "0.4.43" chrono = "0.4.43"
serde_json = "1.0.149" serde_json = "1.0.149"

View file

@ -4,7 +4,6 @@ use crate::communities::perms::permission::Permission;
use crate::communities::{ use crate::communities::{
community_connection::CommunityConnection, interactables::interactable::Interactable, community_connection::CommunityConnection, interactables::interactable::Interactable,
}; };
use crate::data::communication::{CommunicationType, CommunicationValue};
use crate::util::file_util; use crate::util::file_util;
use base64::{Engine as _, engine::general_purpose::STANDARD}; use base64::{Engine as _, engine::general_purpose::STANDARD};
use json::JsonValue; use json::JsonValue;

View file

@ -1,7 +1,6 @@
use crate::auth::auth_user::AuthUser; use crate::auth::auth_user::AuthUser;
use crate::communities::community::Community; use crate::communities::community::Community;
use crate::communities::interactables::interactable::Interactable; use crate::communities::interactables::interactable::Interactable;
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
use crate::users::user_manager::get_user; use crate::users::user_manager::get_user;
use aes_gcm::{Aes256Gcm, KeyInit, Nonce, aead::Aead}; use aes_gcm::{Aes256Gcm, KeyInit, Nonce, aead::Aead};
use base64::{Engine as _, engine::general_purpose::STANDARD}; use base64::{Engine as _, engine::general_purpose::STANDARD};

View file

@ -1,8 +1,6 @@
use crate::{ use crate::communities::{community::Community, interactables::interactable::Interactable};
communities::{community::Community, interactables::interactable::Interactable},
data::communication::{CommunicationType, CommunicationValue},
};
use async_trait::async_trait; use async_trait::async_trait;
use epsilon_core::CommunicationValue;
use json::JsonValue; use json::JsonValue;
use std::any::Any; use std::any::Any;
use std::sync::Arc; use std::sync::Arc;

View file

@ -1,5 +1,6 @@
use crate::{communities::community::Community, data::communication::CommunicationValue}; use crate::communities::community::Community;
use async_trait::async_trait; use async_trait::async_trait;
use epsilon_core::CommunicationValue;
use json::JsonValue; use json::JsonValue;
use std::any::Any; use std::any::Any;
use std::sync::Arc; use std::sync::Arc;

View file

@ -3,11 +3,11 @@ use crate::{
community::Community, community_connection::CommunityConnection, community::Community, community_connection::CommunityConnection,
interactables::interactable::Interactable, interactables::interactable::Interactable,
}, },
data::communication::{CommunicationType, CommunicationValue, DataTypes},
log, log,
util::file_util::{get_children, load_file, save_file}, util::file_util::{get_children, load_file, save_file},
}; };
use async_trait::async_trait; use async_trait::async_trait;
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes};
use json::{JsonValue, array, object}; use json::{JsonValue, array, object};
use std::fs; use std::fs;
use std::sync::Arc; use std::sync::Arc;
@ -190,9 +190,9 @@ impl Interactable for TextChat {
JsonValue::new_object() JsonValue::new_object()
} }
async fn run_function(&self, cv: CommunicationValue) -> CommunicationValue { async fn run_function(&self, cv: CommunicationValue) -> CommunicationValue {
let payload = cv.get_data(DataTypes::payload).unwrap(); let payload = cv.get_data(DataTypes::payload).as_container().unwrap();
if cv.get_data(DataTypes::function).unwrap().as_str().unwrap() == "get_messages" { if cv.get_data(DataTypes::function).as_str().unwrap() == "get_messages" {
let amount = payload["amount"].as_i64().unwrap(); let amount = payload.get(DataTypes::amount).as_i64().unwrap();
let loaded_messages = payload["loaded_messages"].as_i64().unwrap(); let loaded_messages = payload["loaded_messages"].as_i64().unwrap();
let messages = self.get_messages(loaded_messages, amount).clone(); let messages = self.get_messages(loaded_messages, amount).clone();
let mut payload = JsonValue::new_object(); let mut payload = JsonValue::new_object();

View file

@ -1,7 +1,4 @@
use crate::{ use crate::communities::{community::Community, interactables::interactable::Interactable};
communities::{community::Community, interactables::interactable::Interactable},
data::communication::{CommunicationType, CommunicationValue, DataTypes},
};
use async_trait::async_trait; use async_trait::async_trait;
use json::JsonValue; use json::JsonValue;
use std::sync::Arc; use std::sync::Arc;

View file

@ -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()),
)
}
}

View file

@ -1 +0,0 @@
pub mod communication;

2
src/gui/app_state.rs Normal file → Executable file
View file

@ -143,7 +143,7 @@ impl AppState {
pub fn setup() { pub fn setup() {
ACTIVE_TASKS.insert("System info loader".to_string()); ACTIVE_TASKS.insert("System info loader".to_string());
tokio::spawn(async move { tokio::spawn(async move {
let mut sys = System::new_with_specifics(RefreshKind::new()); let mut sys = System::new_with_specifics(RefreshKind::everything());
let mut last_total_received = 0u64; let mut last_total_received = 0u64;
let mut last_total_transmitted = 0u64; let mut last_total_transmitted = 0u64;
let mut counter = 0.0; let mut counter = 0.0;

View file

@ -1,4 +1,5 @@
use crossterm::event::{KeyCode, KeyEvent}; use crossterm::event::{KeyCode, KeyEvent};
use epsilon_core::{CommunicationType, CommunicationValue};
use ratatui::{ use ratatui::{
Frame, Frame,
layout::Rect, layout::Rect,
@ -10,7 +11,6 @@ use uuid::Uuid;
use crate::{ use crate::{
ACTIVE_TASKS, RELOAD, SHUTDOWN, ACTIVE_TASKS, RELOAD, SHUTDOWN,
data::communication::{CommunicationType, CommunicationValue},
gui::{ gui::{
elements::elements::{Element, InteractableElement, JoinableElement}, elements::elements::{Element, InteractableElement, JoinableElement},
interaction_result::InteractionResult, interaction_result::InteractionResult,
@ -260,15 +260,7 @@ pub async fn run_command(command: &str) {
pub async fn ping(time: u64) { pub async fn ping(time: u64) {
let time = time; let time = time;
let conn = { let conn = OMIKRON_CONNECTION.clone();
let guard = OMIKRON_CONNECTION.read().await;
guard.as_ref().cloned()
};
let conn = match conn {
Some(c) => c,
None => return,
};
let response_cv = conn let response_cv = conn
.await_response( .await_response(

View file

@ -8,25 +8,19 @@ use tokio::sync::RwLock;
use tokio::time::{Duration, sleep}; use tokio::time::{Duration, sleep};
mod auth; mod auth;
mod communities;
mod data;
mod gui; mod gui;
mod langu; mod langu;
mod omikron; mod omikron;
mod server;
mod terms; mod terms;
mod users; mod users;
mod util; mod util;
use crate::communities::community_manager;
use crate::communities::interactables::registry;
use crate::gui::app_state; use crate::gui::app_state;
use crate::gui::app_state::AppState; use crate::gui::app_state::AppState;
use crate::gui::screens::main_screen::MainScreen; use crate::gui::screens::main_screen::MainScreen;
use crate::gui::ui::start_tui; use crate::gui::ui::start_tui;
use crate::langu::language_creator; use crate::langu::language_creator;
use crate::omikron::omikron_connection::{OMIKRON_CONNECTION, OmikronConnection}; use crate::omikron::omikron_connection::{OMIKRON_CONNECTION, OmikronConnection};
use crate::server::server::start;
use crate::terms::consent_state; use crate::terms::consent_state;
use crate::users::user_manager; use crate::users::user_manager;
use crate::util::config_util::CONFIG; use crate::util::config_util::CONFIG;
@ -119,7 +113,7 @@ async fn main() {
log!("User IDS: {}", sb); log!("User IDS: {}", sb);
// COMMUNITY MANAGEMENT // COMMUNITY MANAGEMENT
registry::load_interactables().await; /* registry::load_interactables().await;
community_manager::load_communities().await; community_manager::load_communities().await;
community_manager::save_communities().await; community_manager::save_communities().await;
let mut sb1 = "".to_string(); let mut sb1 = "".to_string();
@ -131,7 +125,7 @@ async fn main() {
sb1.remove(0); sb1.remove(0);
sb1 = sb1 + ","; sb1 = sb1 + ",";
} }
log!("Community IDS: {}", sb1); log!("Community IDS: {}", sb1); */
let port = CONFIG.read().await.get_port(); let port = CONFIG.read().await.get_port();
let mut ip = "0.0.0.0".to_string(); let mut ip = "0.0.0.0".to_string();
for iface in pnet::datalink::interfaces() { for iface in pnet::datalink::interfaces() {
@ -144,6 +138,7 @@ async fn main() {
} }
} }
} }
/*
if start(port).await { if start(port).await {
log_t!("community_active", ip, port.to_string()); log_t!("community_active", ip, port.to_string());
} else { } else {
@ -152,7 +147,7 @@ async fn main() {
} else { } else {
log_t!("community_start_error", port.to_string()); log_t!("community_start_error", port.to_string());
} }
} } */
if !has_dir("web") { if !has_dir("web") {
download_and_extract_zip( download_and_extract_zip(
"https://omega.tensamin.net/api/download/iota_frontend", "https://omega.tensamin.net/api/download/iota_frontend",
@ -160,27 +155,17 @@ async fn main() {
) )
.await; .await;
} }
loop {
if *SHUTDOWN.read().await {
break;
}
let omikron: Arc<OmikronConnection> = Arc::new(OmikronConnection::new()); let omikron: Arc<OmikronConnection> = Arc::new(OmikronConnection::new());
omikron.connect().await; omikron.connect().await;
{
let mut omikron_connection = OMIKRON_CONNECTION.write().await;
*omikron_connection = Some(omikron.clone());
}
log_t!("setup_completed"); log_t!("setup_completed");
loop { loop {
if *SHUTDOWN.read().await { if *SHUTDOWN.read().await {
break; break;
} }
if !omikron.is_connected().await {
break;
}
sleep(Duration::from_millis(100)).await; sleep(Duration::from_millis(100)).await;
} }
}
if *RELOAD.read().await { if *RELOAD.read().await {
loop { loop {
if ACTIVE_TASKS.is_empty() { if ACTIVE_TASKS.is_empty() {
@ -190,7 +175,7 @@ async fn main() {
} }
&CONFIG.write().await.clear(); &CONFIG.write().await.clear();
user_manager::clear(); user_manager::clear();
community_manager::clear(); /*community_manager::clear();*/
*APP_STATE.lock().unwrap() = AppState::new(); *APP_STATE.lock().unwrap() = AppState::new();
} }
ui.terminal.lock().unwrap().clear(); ui.terminal.lock().unwrap().clear();

1021
src/omikron/omikron_connection.rs Normal file → Executable file

File diff suppressed because it is too large Load diff

View file

@ -1,47 +1,40 @@
use crate::APP_STATE; use crate::APP_STATE;
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
use crate::omikron::omikron_connection::OmikronConnection; use crate::omikron::omikron_connection::OmikronConnection;
use json::number::Number; use dashmap::DashMap;
use tokio::time::Instant; use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue, rand_u32};
use uuid::Uuid; use std::sync::LazyLock;
use std::time::Instant;
use tokio::time::Duration;
// Dedicated lightweight ping tracking
static PING_TIMES: LazyLock<DashMap<u32, Instant>> = LazyLock::new(|| DashMap::new());
impl OmikronConnection { impl OmikronConnection {
pub async fn send_ping(&self) { pub async fn send_ping(&self) {
let uuid = Uuid::new_v4(); let id = rand_u32();
let send_time = Instant::now();
self.message_send_times.lock().await.insert(uuid, send_time); PING_TIMES.insert(id, Instant::now());
self.send_ping_message(uuid).await;
} // Auto-cleanup old pings (optional)
PING_TIMES.retain(|_, v| v.elapsed() < Duration::from_secs(30));
pub async fn send_ping_message(&self, uuid: Uuid) {
let ping_message = CommunicationValue::new(CommunicationType::ping) let ping_message = CommunicationValue::new(CommunicationType::ping)
.with_id(uuid) .with_id(id)
.add_data_num( .add_data(
DataTypes::last_ping, DataTypes::last_ping,
Number::from(*self.last_ping.lock().await), DataValue::Number(*self.last_ping.lock().await),
); );
self.send_message(&ping_message).await; self.send_message(&ping_message).await;
} }
/// Handles incoming pong and calculates latency pub async fn handle_pong(&self, cv: &CommunicationValue) {
pub async fn handle_pong(&self, cv: &CommunicationValue, log: bool) {
let id = cv.get_id(); let id = cv.get_id();
let send_time_opt = {
let queue = self.message_send_times.lock().await;
queue.get(&id).cloned()
};
if let Some(send_time) = send_time_opt { if let Some((_, send_time)) = PING_TIMES.remove(&id) {
let ping = Instant::now().duration_since(send_time).as_millis() as i64; let ping_ms = Instant::now().duration_since(send_time).as_millis() as i64;
self.message_send_times.lock().await.remove(&id); *self.last_ping.lock().await = ping_ms;
APP_STATE.lock().unwrap().push_ping_val(ping_ms as f64);
*self.last_ping.lock().await = ping as i64;
if log {
APP_STATE.lock().unwrap().push_ping_val(ping as f64);
}
} }
} }
} }

View file

@ -1,4 +1,3 @@
pub mod api; pub mod api;
pub mod server; pub mod server;
pub mod socket;
pub mod web_path_parser; pub mod web_path_parser;

View file

@ -1,6 +1,5 @@
use crate::log; use crate::log;
use crate::server::api::api_config; use crate::server::api::api_config;
use crate::server::socket::WsSession;
use crate::server::web_path_parser; use crate::server::web_path_parser;
use crate::util::file_util::load_file_buf; use crate::util::file_util::load_file_buf;
use crate::{ACTIVE_TASKS, SHUTDOWN}; use crate::{ACTIVE_TASKS, SHUTDOWN};

View file

@ -1,97 +0,0 @@
use crate::{
data::communication::{CommunicationType, CommunicationValue},
log,
};
use actix::{Actor, ActorContext, AsyncContext, StreamHandler};
use actix_web_actors::ws;
use std::time::{Duration, Instant};
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
use actix::Message;
#[derive(Message)]
#[rtype(result = "()")]
pub struct WsSendMessage(pub String);
impl actix::Handler<WsSendMessage> for WsSession {
type Result = ();
fn handle(&mut self, msg: WsSendMessage, ctx: &mut Self::Context) {
ctx.text(msg.0);
}
}
pub struct WsSession {
path: String,
last_heartbeat: Instant,
}
impl WsSession {
pub fn new(path: String) -> Self {
Self {
path,
last_heartbeat: Instant::now(),
}
}
fn start_heartbeat(&self, ctx: &mut ws::WebsocketContext<Self>) {
ctx.run_interval(Duration::from_secs(5), |act, ctx| {
if Instant::now().duration_since(act.last_heartbeat) > IDLE_TIMEOUT {
ctx.close(None);
ctx.stop();
return;
}
let ping = CommunicationValue::new(CommunicationType::ping)
.to_json()
.to_string();
ctx.text(ping);
});
}
}
impl Actor for WsSession {
type Context = ws::WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.start_heartbeat(ctx);
log!("WebSocket session started for path: {}", self.path);
if self.path.starts_with("/ws/users/") {
log!("UserConnection handling is not yet implemented.");
} else if self.path.starts_with("/ws/community/") {
let community_id = self.path.split('/').nth(3).unwrap_or_default();
log!(
"CommunityConnection handling for {} is not yet implemented.",
community_id
);
}
}
fn stopped(&mut self, _ctx: &mut Self::Context) {
log!("WebSocket session stopped for path: {}", self.path);
}
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsSession {
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
match msg {
Ok(ws::Message::Ping(msg)) => {
self.last_heartbeat = Instant::now();
ctx.pong(&msg);
}
Ok(ws::Message::Pong(_)) => self.last_heartbeat = Instant::now(),
Ok(ws::Message::Text(_)) => self.last_heartbeat = Instant::now(),
Ok(ws::Message::Close(reason)) => {
ctx.close(reason);
ctx.stop();
}
Err(_) => {
ctx.stop();
}
_ => ctx.stop(),
}
}
}

View file

@ -1,5 +1,4 @@
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes}; use crate::omikron::omikron_connection::OMIKRON_CONNECTION;
use crate::omikron::omikron_connection::{OMIKRON_CONNECTION, OmikronConnection};
use crate::users::user_profile::UserProfile; use crate::users::user_profile::UserProfile;
use crate::util::crypto_helper::{self, public_key_to_base64}; use crate::util::crypto_helper::{self, public_key_to_base64};
use crate::util::file_util::{load_file, save_file}; use crate::util::file_util::{load_file, save_file};
@ -7,16 +6,16 @@ use crate::util::logger::PrintType;
use crate::{RELOAD, SHUTDOWN}; use crate::{RELOAD, SHUTDOWN};
use crate::{log, log_cv}; use crate::{log, log_cv};
use base64::{Engine as _, engine::general_purpose::STANDARD}; use base64::{Engine as _, engine::general_purpose::STANDARD};
use epsilon_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
use hex::{self}; use hex::{self};
use json::JsonValue; use json::JsonValue;
use json::number::Number;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rand::Rng; use rand::Rng;
use rand_core::OsRng; use rand_core::OsRng;
use rand_core::RngCore; use rand_core::RngCore;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::io::{self}; use std::io::{self};
use std::sync::{Arc, Mutex}; use std::sync::Mutex;
use std::time::Duration; use std::time::Duration;
use x448::{PublicKey, Secret}; use x448::{PublicKey, Secret};
@ -52,15 +51,7 @@ pub async fn load_from_tu(username: &str) -> Result<(), ()> {
pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>) { pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>) {
let register_cv = CommunicationValue::new(CommunicationType::get_register); let register_cv = CommunicationValue::new(CommunicationType::get_register);
let conn = { let conn = OMIKRON_CONNECTION.clone();
let guard = OMIKRON_CONNECTION.read().await;
guard.as_ref().cloned()
};
let conn = match conn {
Some(c) => c,
None => return (None, None),
};
let response_cv = match conn let response_cv = match conn
.await_response(&register_cv, Some(Duration::from_secs(20))) .await_response(&register_cv, Some(Duration::from_secs(20)))
@ -71,11 +62,7 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
}; };
log_cv!(PrintType::Omega, response_cv); log_cv!(PrintType::Omega, response_cv);
let user_id = match response_cv let user_id = match response_cv.get_data(DataTypes::user_id).as_number() {
.get_data(DataTypes::user_id)
.unwrap_or(&JsonValue::Null)
.as_i64()
{
Some(id) => id, Some(id) => id,
None => return (None, None), None => return (None, None),
}; };
@ -104,24 +91,14 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
); );
let cv = CommunicationValue::new(CommunicationType::complete_register_user) let cv = CommunicationValue::new(CommunicationType::complete_register_user)
.add_data(DataTypes::user_id, JsonValue::Number(Number::from(user_id))) .add_data(DataTypes::user_id, DataValue::Number(user_id))
.add_data(DataTypes::username, JsonValue::String(username.to_string())) .add_data(DataTypes::username, DataValue::Str(username.to_string()))
.add_data( .add_data(
DataTypes::public_key, DataTypes::public_key,
JsonValue::String(public_key_to_base64(&public_key)), DataValue::Str(public_key_to_base64(&public_key)),
) )
.add_data(DataTypes::iota_id, JsonValue::Number(Number::from(user_id))) .add_data(DataTypes::iota_id, DataValue::Number(user_id))
.add_data(DataTypes::reset_token, JsonValue::String(reset_token)); .add_data(DataTypes::reset_token, DataValue::Str(reset_token));
let conn = {
let guard = OMIKRON_CONNECTION.read().await;
guard.as_ref().cloned()
};
let conn = match conn {
Some(c) => c,
None => return (None, None),
};
let response_cv = conn let response_cv = conn
.await_response(&cv, Some(Duration::from_secs(20))) .await_response(&cv, Some(Duration::from_secs(20)))

214
src/util/logger.rs Normal file → Executable file
View file

@ -1,4 +1,5 @@
use std::{ use std::{
collections::BTreeMap,
fs::{self, OpenOptions}, fs::{self, OpenOptions},
io::Write, io::Write,
path::Path, path::Path,
@ -7,6 +8,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use epsilon_core::{CommunicationValue, DataTypes, DataValue};
use ratatui::style::Color; use ratatui::style::Color;
use crate::{ use crate::{
@ -156,82 +158,6 @@ pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: St
} }
} }
use crate::data::communication::CommunicationValue;
use json::JsonValue;
pub fn log_cv_internal(prefix: String, cv: &CommunicationValue, print_type: Option<PrintType>) {
let formatted = format_cv(cv);
log_internal(
print_type.unwrap_or(PrintType::General),
prefix,
false,
formatted,
);
}
pub fn format_cv(cv: &CommunicationValue) -> String {
let mut parts = Vec::new();
let sender = cv.get_sender();
let receiver = cv.get_receiver();
if sender > 0 && receiver > 0 {
parts.push(format!("{} > {}", sender, receiver));
} else if sender > 0 {
parts.push(format!("{}", sender));
} else if receiver > 0 {
parts.push(format!("> {}", receiver));
}
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(),
};
data_parts.push(format!("{} {}", key, val_string));
}
}
if !data_parts.is_empty() {
parts.push(format!("{}", data_parts.join(", ")));
}
parts.join(": ")
}
#[macro_export]
macro_rules! log_cv {
($kind:expr, $cv:expr) => {
$crate::util::logger::log_cv_internal("".to_string(), &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("".to_string(), &$cv, None)
};
}
#[macro_export]
macro_rules! log_cv_in {
($kind:expr, $cv:expr) => {
$crate::util::logger::log_cv_internal("> ".to_string(), &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("> ".to_string(), &$cv, None)
};
}
#[macro_export]
macro_rules! log_cv_out {
($kind:expr, $cv:expr) => {
$crate::util::logger::log_cv_internal("< ".to_string(), &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("< ".to_string(), &$cv, None)
};
}
#[macro_export] #[macro_export]
macro_rules! log_t { macro_rules! log_t {
($key:expr) => { ($key:expr) => {
@ -320,3 +246,139 @@ macro_rules! log_err {
) )
}; };
} }
// ******** COMMUNICATION VALUES ********
pub fn log_cv_internal(
prefix: &'static str,
cv: &CommunicationValue,
print_type: Option<PrintType>,
) {
let formatted = format_cv(cv);
log_internal(
print_type.unwrap_or(PrintType::General),
prefix.to_string(),
false,
formatted,
);
}
pub fn format_cv(cv: &CommunicationValue) -> String {
let mut parts = Vec::new();
let sender = cv.get_sender();
let receiver = cv.get_receiver();
if sender > 0 && receiver > 0 {
parts.push(format!("{} > {}", sender, receiver));
} else if sender > 0 {
parts.push(format!("{}", sender));
} else if receiver > 0 {
parts.push(format!("> {}", receiver));
}
let comm_type = cv.get_type().to_string();
parts.push(format!("{}", comm_type));
let data: &BTreeMap<DataTypes, DataValue> = cv.get_data_container();
let formated_data =
format_data_container(data.iter().map(|(k, v)| (k.clone(), v.clone())).collect());
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) => {
$crate::util::logger::log_cv_internal("", &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("", &$cv, None)
};
}
#[macro_export]
macro_rules! log_cv_in {
($kind:expr, $cv:expr) => {
$crate::util::logger::log_cv_internal("> ", &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("> ", &$cv, None)
};
}
#[macro_export]
macro_rules! log_cv_out {
($kind:expr, $cv:expr) => {
$crate::util::logger::log_cv_internal("< ", &$cv, Some($kind))
};
($cv:expr) => {
$crate::util::logger::log_cv_internal("< ", &$cv, None)
};
}