UI Utility
This commit is contained in:
parent
a5ade7dd03
commit
cbd357ce14
14 changed files with 962 additions and 622 deletions
126
Cargo.lock
generated
126
Cargo.lock
generated
|
|
@ -334,6 +334,31 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm"
|
name = "crossterm"
|
||||||
version = "0.28.1"
|
version = "0.28.1"
|
||||||
|
|
@ -913,7 +938,7 @@ dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-core",
|
"windows-core 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1281,25 +1306,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-core-foundation"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-io-kit"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"objc2-core-foundation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.7"
|
version = "0.36.7"
|
||||||
|
|
@ -1534,6 +1540,26 @@ dependencies = [
|
||||||
"unicode-width 0.2.0",
|
"unicode-width 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.17"
|
version = "0.5.17"
|
||||||
|
|
@ -1964,15 +1990,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.37.0"
|
version = "0.30.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753"
|
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
|
||||||
"ntapi",
|
"ntapi",
|
||||||
"objc2-core-foundation",
|
"once_cell",
|
||||||
"objc2-io-kit",
|
"rayon",
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2531,24 +2558,21 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.61.3"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-collections",
|
"windows-core 0.52.0",
|
||||||
"windows-core",
|
"windows-targets 0.52.6",
|
||||||
"windows-future",
|
|
||||||
"windows-link 0.1.3",
|
|
||||||
"windows-numerics",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-collections"
|
name = "windows-core"
|
||||||
version = "0.2.0"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2564,17 +2588,6 @@ dependencies = [
|
||||||
"windows-strings",
|
"windows-strings",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-future"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core",
|
|
||||||
"windows-link 0.1.3",
|
|
||||||
"windows-threading",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-implement"
|
name = "windows-implement"
|
||||||
version = "0.60.0"
|
version = "0.60.0"
|
||||||
|
|
@ -2609,16 +2622,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-numerics"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core",
|
|
||||||
"windows-link 0.1.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-registry"
|
name = "windows-registry"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
|
@ -2717,15 +2720,6 @@ dependencies = [
|
||||||
"windows_x86_64_msvc 0.53.0",
|
"windows_x86_64_msvc 0.53.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-threading"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.1.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ cmake = "*"
|
||||||
tokio = { version = "*", features = ["full"] }
|
tokio = { version = "*", features = ["full"] }
|
||||||
uuid = { version = "*", features = ["v4"] }
|
uuid = { version = "*", features = ["v4"] }
|
||||||
walkdir = "2.5.0"
|
walkdir = "2.5.0"
|
||||||
sysinfo = "*"
|
sysinfo = "0.30"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
ratatui = { version = "*", features = ["all-widgets"]}
|
ratatui = { version = "*", features = ["all-widgets"]}
|
||||||
bytes = "*"
|
bytes = "*"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
use crate::CONFIG;
|
||||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
|
use crate::gui::log_panel::log_message;
|
||||||
use crate::users::user_profile::UserProfile;
|
use crate::users::user_profile::UserProfile;
|
||||||
use hex;
|
use hex;
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
|
|
@ -48,7 +50,7 @@ impl AuthConnector {
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let json = res.text().await.ok()?;
|
let json = res.text().await.ok()?;
|
||||||
let cv = CommunicationValue::from_json(&json);
|
let cv = CommunicationValue::from_json(&json);
|
||||||
Option::from(cv.is_type(CommunicationType::Success))
|
Option::from(cv.is_type(CommunicationType::success))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_uuid(username: &str) -> Option<Uuid> {
|
pub async fn get_uuid(username: &str) -> Option<Uuid> {
|
||||||
|
|
@ -60,10 +62,10 @@ impl AuthConnector {
|
||||||
let res = client.get(&url).send().await.ok()?;
|
let res = client.get(&url).send().await.ok()?;
|
||||||
let json = res.text().await.ok()?;
|
let json = res.text().await.ok()?;
|
||||||
let mut cv = CommunicationValue::from_json(&json);
|
let mut cv = CommunicationValue::from_json(&json);
|
||||||
if !cv.is_type(CommunicationType::Success) {
|
if !cv.is_type(CommunicationType::success) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Uuid::parse_str(&*cv.get_data(DataTypes::UserId).unwrap().to_string()).ok()
|
Uuid::parse_str(&*cv.get_data(DataTypes::user_id).unwrap().to_string()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user(user_id: Uuid) -> Option<AuthUser> {
|
pub async fn get_user(user_id: Uuid) -> Option<AuthUser> {
|
||||||
|
|
@ -73,31 +75,31 @@ impl AuthConnector {
|
||||||
let json = res.text().await.ok()?;
|
let json = res.text().await.ok()?;
|
||||||
|
|
||||||
let mut cv = CommunicationValue::from_json(&json);
|
let mut cv = CommunicationValue::from_json(&json);
|
||||||
if cv.comm_type != CommunicationType::Success {
|
if cv.comm_type != CommunicationType::success {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(AuthUser {
|
Some(AuthUser {
|
||||||
created_at: cv
|
created_at: cv
|
||||||
.get_data(DataTypes::CreatedAt)
|
.get_data(DataTypes::created_at)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<i64>()
|
.parse::<i64>()
|
||||||
.unwrap_or(-1),
|
.unwrap_or(-1),
|
||||||
username: cv.get_data(DataTypes::Username).unwrap().to_string(),
|
username: cv.get_data(DataTypes::username).unwrap().to_string(),
|
||||||
display: cv.get_data(DataTypes::Display).unwrap().to_string(),
|
display: cv.get_data(DataTypes::display).unwrap().to_string(),
|
||||||
avatar: cv.get_data(DataTypes::Avatar).unwrap().to_string(),
|
avatar: cv.get_data(DataTypes::avatar).unwrap().to_string(),
|
||||||
about: cv.get_data(DataTypes::About).unwrap().to_string(),
|
about: cv.get_data(DataTypes::about).unwrap().to_string(),
|
||||||
status: cv.get_data(DataTypes::Status).unwrap().to_string(),
|
status: cv.get_data(DataTypes::status).unwrap().to_string(),
|
||||||
public_key: cv.get_data(DataTypes::PublicKey).unwrap().to_string(),
|
public_key: cv.get_data(DataTypes::public_key).unwrap().to_string(),
|
||||||
sub_level: cv
|
sub_level: cv
|
||||||
.get_data(DataTypes::SubLevel)
|
.get_data(DataTypes::sub_level)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<i32>()
|
.parse::<i32>()
|
||||||
.unwrap_or(-1),
|
.unwrap_or(-1),
|
||||||
sub_end: cv
|
sub_end: cv
|
||||||
.get_data(DataTypes::SubEnd)
|
.get_data(DataTypes::sub_end)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<i32>()
|
.parse::<i32>()
|
||||||
|
|
@ -112,7 +114,7 @@ impl AuthConnector {
|
||||||
let json = res.text().await.ok()?;
|
let json = res.text().await.ok()?;
|
||||||
|
|
||||||
let mut cv = CommunicationValue::from_json(&json);
|
let mut cv = CommunicationValue::from_json(&json);
|
||||||
Uuid::parse_str(&*cv.get_data(DataTypes::UserId).unwrap().to_string()).ok()
|
Uuid::parse_str(&*cv.get_data(DataTypes::user_id).unwrap().to_string()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn complete_register(user_profile: &UserProfile, iota_id: &str) -> bool {
|
pub async fn complete_register(user_profile: &UserProfile, iota_id: &str) -> bool {
|
||||||
|
|
@ -139,10 +141,10 @@ impl AuthConnector {
|
||||||
let body = res.text().await.unwrap();
|
let body = res.text().await.unwrap();
|
||||||
println!("Response body:\n{}", body);
|
println!("Response body:\n{}", body);
|
||||||
|
|
||||||
CommunicationValue::from_json(&body).is_type(CommunicationType::Success)
|
CommunicationValue::from_json(&body).is_type(CommunicationType::success)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn migrate_user(user_profile: &mut UserProfile, iota_id: &str) -> bool {
|
pub async fn migrate_user(user_profile: &mut UserProfile) -> bool {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"https://auth.tensamin.methanium.net/api/change/iota-id/{}",
|
"https://auth.tensamin.methanium.net/api/change/iota-id/{}",
|
||||||
user_profile.user_id
|
user_profile.user_id
|
||||||
|
|
@ -150,7 +152,7 @@ impl AuthConnector {
|
||||||
let client = Self::client();
|
let client = Self::client();
|
||||||
|
|
||||||
let mut payload = JsonValue::new_object();
|
let mut payload = JsonValue::new_object();
|
||||||
payload["iota_id"] = iota_id.into();
|
payload["iota_id"] = JsonValue::String(CONFIG.lock().unwrap().get_iota_id().to_string());
|
||||||
payload["reset_token"] = user_profile.reset_token.clone().into();
|
payload["reset_token"] = user_profile.reset_token.clone().into();
|
||||||
payload["new_token"] = user_profile.randomize_reset_token().into();
|
payload["new_token"] = user_profile.randomize_reset_token().into();
|
||||||
|
|
||||||
|
|
@ -171,7 +173,7 @@ impl AuthConnector {
|
||||||
match resp.text().await {
|
match resp.text().await {
|
||||||
Ok(text) => {
|
Ok(text) => {
|
||||||
let cv = CommunicationValue::from_json(&text);
|
let cv = CommunicationValue::from_json(&text);
|
||||||
cv.comm_type == CommunicationType::Success
|
cv.comm_type == CommunicationType::success
|
||||||
}
|
}
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use json::number::Number;
|
use json::number::Number;
|
||||||
use json::{JsonValue, object, parse, stringify};
|
use json::{Array, JsonValue, object, parse, stringify};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env::VarsOs;
|
use std::env::VarsOs;
|
||||||
|
|
@ -8,73 +8,73 @@ use std::str::FromStr;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq, Debug)]
|
#[derive(Eq, Hash, PartialEq, Clone, Debug)]
|
||||||
pub enum DataTypes {
|
pub enum DataTypes {
|
||||||
ErrorType,
|
error_type,
|
||||||
ChatPartnerId,
|
chat_partner_id,
|
||||||
IotaId,
|
iota_id,
|
||||||
UserId,
|
user_id,
|
||||||
UserIds,
|
user_ids,
|
||||||
UserState,
|
user_state,
|
||||||
UserStates,
|
user_states,
|
||||||
UserPings,
|
user_pings,
|
||||||
CallState,
|
call_state,
|
||||||
ScreenShare,
|
screen_share,
|
||||||
PrivateKeyHash,
|
private_key_hash,
|
||||||
Accepted,
|
accepted,
|
||||||
AcceptedProfiles,
|
accepted_profiles,
|
||||||
DeniedProfiles,
|
denied_profiles,
|
||||||
MessageContent,
|
message_content,
|
||||||
MessageChunk,
|
message_chunk,
|
||||||
SendTime,
|
send_time,
|
||||||
GetTime,
|
get_time,
|
||||||
GetVariant,
|
get_variant,
|
||||||
SharedSecretOwn,
|
shared_secret_own,
|
||||||
SharedSecretOther,
|
shared_secret_other,
|
||||||
SharedSecretSign,
|
shared_secret_sign,
|
||||||
SharedSecret,
|
shared_secret,
|
||||||
CallId,
|
call_id,
|
||||||
CallName,
|
call_name,
|
||||||
CallSecretSha,
|
call_secret_sha,
|
||||||
CallSecret,
|
call_secret,
|
||||||
SharedCallSecret,
|
shared_call_secret,
|
||||||
StartDate,
|
start_date,
|
||||||
EndDate,
|
end_date,
|
||||||
ReceiverId,
|
receiver_id,
|
||||||
SenderId,
|
sender_id,
|
||||||
Signature,
|
signature,
|
||||||
Signed,
|
signed,
|
||||||
Message,
|
message,
|
||||||
LastPing,
|
last_ping,
|
||||||
PingIota,
|
ping_iota,
|
||||||
PingClients,
|
ping_clients,
|
||||||
Matches,
|
matches,
|
||||||
Omikron,
|
omikron,
|
||||||
LoadedMessages,
|
loaded_messages,
|
||||||
MessageAmount,
|
message_amount,
|
||||||
Position,
|
position,
|
||||||
Name,
|
name,
|
||||||
Path,
|
path,
|
||||||
Codec,
|
codec,
|
||||||
Function,
|
function,
|
||||||
Payload,
|
payload,
|
||||||
Result,
|
result,
|
||||||
Interactables,
|
interactables,
|
||||||
WantToWatch,
|
want_to_watch,
|
||||||
Watcher,
|
watcher,
|
||||||
CreatedAt,
|
created_at,
|
||||||
Username,
|
username,
|
||||||
Display,
|
display,
|
||||||
Avatar,
|
avatar,
|
||||||
About,
|
about,
|
||||||
Status,
|
status,
|
||||||
PublicKey,
|
public_key,
|
||||||
SubLevel,
|
sub_level,
|
||||||
SubEnd,
|
sub_end,
|
||||||
CommunityAddress,
|
community_address,
|
||||||
Challenge,
|
challenge,
|
||||||
CommunityTitle,
|
community_title,
|
||||||
Communities,
|
communities,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataTypes {
|
impl DataTypes {
|
||||||
|
|
@ -83,209 +83,179 @@ impl DataTypes {
|
||||||
let normalized = p0.to_lowercase().replace('_', "");
|
let normalized = p0.to_lowercase().replace('_', "");
|
||||||
|
|
||||||
match normalized.as_str() {
|
match normalized.as_str() {
|
||||||
"errortype" => DataTypes::ErrorType,
|
"errortype" => DataTypes::error_type,
|
||||||
"chatpartnerid" => DataTypes::ChatPartnerId,
|
"chatpartnerid" => DataTypes::chat_partner_id,
|
||||||
"iotaid" => DataTypes::IotaId,
|
"iotaid" => DataTypes::iota_id,
|
||||||
"userid" => DataTypes::UserId,
|
"userid" => DataTypes::user_id,
|
||||||
"userids" => DataTypes::UserIds,
|
"userids" => DataTypes::user_ids,
|
||||||
"userstate" => DataTypes::UserState,
|
"userstate" => DataTypes::user_state,
|
||||||
"userstates" => DataTypes::UserStates,
|
"userstates" => DataTypes::user_states,
|
||||||
"userpings" => DataTypes::UserPings,
|
"userpings" => DataTypes::user_pings,
|
||||||
"callstate" => DataTypes::CallState,
|
"callstate" => DataTypes::call_state,
|
||||||
"screenshare" => DataTypes::ScreenShare,
|
"screenshare" => DataTypes::screen_share,
|
||||||
"privatekeyhash" => DataTypes::PrivateKeyHash,
|
"privatekeyhash" => DataTypes::private_key_hash,
|
||||||
"accepted" => DataTypes::Accepted,
|
"accepted" => DataTypes::accepted,
|
||||||
"acceptedprofiles" => DataTypes::AcceptedProfiles,
|
"acceptedprofiles" => DataTypes::accepted_profiles,
|
||||||
"deniedprofiles" => DataTypes::DeniedProfiles,
|
"deniedprofiles" => DataTypes::denied_profiles,
|
||||||
"messagecontent" => DataTypes::MessageContent,
|
"messagecontent" => DataTypes::message_content,
|
||||||
"messagechunk" => DataTypes::MessageChunk,
|
"messagechunk" => DataTypes::message_chunk,
|
||||||
"sendtime" => DataTypes::SendTime,
|
"sendtime" => DataTypes::send_time,
|
||||||
"gettime" => DataTypes::GetTime,
|
"gettime" => DataTypes::get_time,
|
||||||
"getvariant" => DataTypes::GetVariant,
|
"getvariant" => DataTypes::get_variant,
|
||||||
"sharedsecretown" => DataTypes::SharedSecretOwn,
|
"sharedsecretown" => DataTypes::shared_secret_own,
|
||||||
"sharedsecretother" => DataTypes::SharedSecretOther,
|
"sharedsecretother" => DataTypes::shared_secret_other,
|
||||||
"sharedsecretsign" => DataTypes::SharedSecretSign,
|
"sharedsecretsign" => DataTypes::shared_secret_sign,
|
||||||
"sharedsecret" => DataTypes::SharedSecret,
|
"sharedsecret" => DataTypes::shared_secret,
|
||||||
"callid" => DataTypes::CallId,
|
"callid" => DataTypes::call_id,
|
||||||
"callname" => DataTypes::CallName,
|
"callname" => DataTypes::call_name,
|
||||||
"callsecretsha" => DataTypes::CallSecretSha,
|
"callsecretsha" => DataTypes::call_secret_sha,
|
||||||
"callsecret" => DataTypes::CallSecret,
|
"callsecret" => DataTypes::call_secret,
|
||||||
"sharedcallsecret" => DataTypes::SharedCallSecret,
|
"sharedcallsecret" => DataTypes::shared_call_secret,
|
||||||
"startdate" => DataTypes::StartDate,
|
"startdate" => DataTypes::start_date,
|
||||||
"enddate" => DataTypes::EndDate,
|
"enddate" => DataTypes::end_date,
|
||||||
"receiverid" => DataTypes::ReceiverId,
|
"receiverid" => DataTypes::receiver_id,
|
||||||
"senderid" => DataTypes::SenderId,
|
"senderid" => DataTypes::sender_id,
|
||||||
"signature" => DataTypes::Signature,
|
"signature" => DataTypes::signature,
|
||||||
"signed" => DataTypes::Signed,
|
"signed" => DataTypes::signed,
|
||||||
"message" => DataTypes::Message,
|
"message" => DataTypes::message,
|
||||||
"lastping" => DataTypes::LastPing,
|
"lastping" => DataTypes::last_ping,
|
||||||
"pingiota" => DataTypes::PingIota,
|
"pingiota" => DataTypes::ping_iota,
|
||||||
"pingclients" => DataTypes::PingClients,
|
"pingclients" => DataTypes::ping_clients,
|
||||||
"matches" => DataTypes::Matches,
|
"matches" => DataTypes::matches,
|
||||||
"omikron" => DataTypes::Omikron,
|
"omikron" => DataTypes::omikron,
|
||||||
"loadedmessages" => DataTypes::LoadedMessages,
|
"loadedmessages" => DataTypes::loaded_messages,
|
||||||
"messageamount" => DataTypes::MessageAmount,
|
"messageamount" => DataTypes::message_amount,
|
||||||
"position" => DataTypes::Position,
|
"position" => DataTypes::position,
|
||||||
"name" => DataTypes::Name,
|
"name" => DataTypes::name,
|
||||||
"path" => DataTypes::Path,
|
"path" => DataTypes::path,
|
||||||
"codec" => DataTypes::Codec,
|
"codec" => DataTypes::codec,
|
||||||
"function" => DataTypes::Function,
|
"function" => DataTypes::function,
|
||||||
"payload" => DataTypes::Payload,
|
"payload" => DataTypes::payload,
|
||||||
"result" => DataTypes::Result,
|
"result" => DataTypes::result,
|
||||||
"interactables" => DataTypes::Interactables,
|
"interactables" => DataTypes::interactables,
|
||||||
"wanttowatch" => DataTypes::WantToWatch,
|
"wanttowatch" => DataTypes::want_to_watch,
|
||||||
"watcher" => DataTypes::Watcher,
|
"watcher" => DataTypes::watcher,
|
||||||
"createdat" => DataTypes::CreatedAt,
|
"createdat" => DataTypes::created_at,
|
||||||
"username" => DataTypes::Username,
|
"username" => DataTypes::username,
|
||||||
"display" => DataTypes::Display,
|
"display" => DataTypes::display,
|
||||||
"avatar" => DataTypes::Avatar,
|
"avatar" => DataTypes::avatar,
|
||||||
"about" => DataTypes::About,
|
"about" => DataTypes::about,
|
||||||
"status" => DataTypes::Status,
|
"status" => DataTypes::status,
|
||||||
"publickey" => DataTypes::PublicKey,
|
"publickey" => DataTypes::public_key,
|
||||||
"sublevel" => DataTypes::SubLevel,
|
"sublevel" => DataTypes::sub_level,
|
||||||
"subend" => DataTypes::SubEnd,
|
"subend" => DataTypes::sub_end,
|
||||||
"communityaddress" => DataTypes::CommunityAddress,
|
"communityaddress" => DataTypes::community_address,
|
||||||
"challenge" => DataTypes::Challenge,
|
"challenge" => DataTypes::challenge,
|
||||||
"communitytitle" => DataTypes::CommunityTitle,
|
"communitytitle" => DataTypes::community_title,
|
||||||
"communities" => DataTypes::Communities,
|
"communities" => DataTypes::communities,
|
||||||
_ => DataTypes::ErrorType, // fallback if unknown
|
_ => DataTypes::error_type, // fallback if unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub enum CommunicationType {
|
pub enum CommunicationType {
|
||||||
Error,
|
error,
|
||||||
Success,
|
success,
|
||||||
Message,
|
message,
|
||||||
MessageLive,
|
message_live,
|
||||||
MessageOtherIota,
|
message_other_iota,
|
||||||
MessageChunk,
|
message_chunk,
|
||||||
MessageGet,
|
message_get,
|
||||||
ChangeConfirm,
|
change_confirm,
|
||||||
ConfirmReceive,
|
confirm_receive,
|
||||||
ConfirmRead,
|
confirm_read,
|
||||||
GetChats,
|
get_chats,
|
||||||
GetStates,
|
get_states,
|
||||||
AddCommunity,
|
add_community,
|
||||||
RemoveCommunity,
|
remove_community,
|
||||||
GetCommunities,
|
get_communities,
|
||||||
Challenge,
|
challenge,
|
||||||
ChallengeResponse,
|
challenge_response,
|
||||||
Register,
|
register,
|
||||||
RegisterResponse,
|
register_response,
|
||||||
Identification,
|
identification,
|
||||||
IdentificationResponse,
|
identification_response,
|
||||||
Ping,
|
ping,
|
||||||
Pong,
|
pong,
|
||||||
AddChat,
|
add_chat,
|
||||||
SendChat,
|
send_chat,
|
||||||
IotaConnected,
|
iota_connected,
|
||||||
IotaClosed,
|
iota_closed,
|
||||||
ClientChanged,
|
client_changed,
|
||||||
ClientConnected,
|
client_connected,
|
||||||
ClientClosed,
|
client_closed,
|
||||||
PublicKey,
|
public_key,
|
||||||
PrivateKey,
|
private_key,
|
||||||
WebrtcSdp,
|
webrtc_sdp,
|
||||||
WebrtcIce,
|
webrtc_ice,
|
||||||
StartStream,
|
start_stream,
|
||||||
EndStream,
|
end_stream,
|
||||||
WatchStream,
|
watch_stream,
|
||||||
GetCall,
|
get_call,
|
||||||
NewCall,
|
new_call,
|
||||||
CallInvite,
|
call_invite,
|
||||||
EndCall,
|
end_call,
|
||||||
Function,
|
function,
|
||||||
Update,
|
update,
|
||||||
}
|
}
|
||||||
impl CommunicationType {
|
impl CommunicationType {
|
||||||
pub fn parse(p0: String) -> CommunicationType {
|
pub fn parse(p0: String) -> CommunicationType {
|
||||||
let normalized = p0.to_lowercase().replace('_', "");
|
let normalized = p0.to_lowercase().replace('_', "");
|
||||||
|
|
||||||
match normalized.as_str() {
|
match normalized.as_str() {
|
||||||
"error" => CommunicationType::Error,
|
"error" => CommunicationType::error,
|
||||||
"success" => CommunicationType::Success,
|
"success" => CommunicationType::success,
|
||||||
"message" => CommunicationType::Message,
|
"message" => CommunicationType::message,
|
||||||
"messagelive" => CommunicationType::MessageLive,
|
"messagelive" => CommunicationType::message_live,
|
||||||
"messageotheriota" => CommunicationType::MessageOtherIota,
|
"messageotheriota" => CommunicationType::message_other_iota,
|
||||||
"messagechunk" => CommunicationType::MessageChunk,
|
"messagechunk" => CommunicationType::message_chunk,
|
||||||
"messageget" => CommunicationType::MessageGet,
|
"messageget" => CommunicationType::message_get,
|
||||||
"changeconfirm" => CommunicationType::ChangeConfirm,
|
"changeconfirm" => CommunicationType::change_confirm,
|
||||||
"confirmreceive" => CommunicationType::ConfirmReceive,
|
"confirmreceive" => CommunicationType::confirm_receive,
|
||||||
"confirmread" => CommunicationType::ConfirmRead,
|
"confirmread" => CommunicationType::confirm_read,
|
||||||
"getchats" => CommunicationType::GetChats,
|
"getchats" => CommunicationType::get_chats,
|
||||||
"getstates" => CommunicationType::GetStates,
|
"getstates" => CommunicationType::get_states,
|
||||||
"addcommunity" => CommunicationType::AddCommunity,
|
"addcommunity" => CommunicationType::add_community,
|
||||||
"removecommunity" => CommunicationType::RemoveCommunity,
|
"removecommunity" => CommunicationType::remove_community,
|
||||||
"getcommunities" => CommunicationType::GetCommunities,
|
"getcommunities" => CommunicationType::get_communities,
|
||||||
"challenge" => CommunicationType::Challenge,
|
"challenge" => CommunicationType::challenge,
|
||||||
"challengeresponse" => CommunicationType::ChallengeResponse,
|
"challengeresponse" => CommunicationType::challenge_response,
|
||||||
"register" => CommunicationType::Register,
|
"register" => CommunicationType::register,
|
||||||
"registerresponse" => CommunicationType::RegisterResponse,
|
"registerresponse" => CommunicationType::register_response,
|
||||||
"identification" => CommunicationType::Identification,
|
"identification" => CommunicationType::identification,
|
||||||
"identificationresponse" => CommunicationType::IdentificationResponse,
|
"identificationresponse" => CommunicationType::identification_response,
|
||||||
"ping" => CommunicationType::Ping,
|
"ping" => CommunicationType::ping,
|
||||||
"pong" => CommunicationType::Pong,
|
"pong" => CommunicationType::pong,
|
||||||
"addchat" => CommunicationType::AddChat,
|
"addchat" => CommunicationType::add_chat,
|
||||||
"sendchat" => CommunicationType::SendChat,
|
"sendchat" => CommunicationType::send_chat,
|
||||||
"iotaconnected" => CommunicationType::IotaConnected,
|
"iotaconnected" => CommunicationType::iota_connected,
|
||||||
"iotaclosed" => CommunicationType::IotaClosed,
|
"iotaclosed" => CommunicationType::iota_closed,
|
||||||
"clientchanged" => CommunicationType::ClientChanged,
|
"clientchanged" => CommunicationType::client_changed,
|
||||||
"clientconnected" => CommunicationType::ClientConnected,
|
"clientconnected" => CommunicationType::client_connected,
|
||||||
"clientclosed" => CommunicationType::ClientClosed,
|
"clientclosed" => CommunicationType::client_closed,
|
||||||
"publickey" => CommunicationType::PublicKey,
|
"publickey" => CommunicationType::public_key,
|
||||||
"privatekey" => CommunicationType::PrivateKey,
|
"privatekey" => CommunicationType::private_key,
|
||||||
"webrtcsdp" => CommunicationType::WebrtcSdp,
|
"webrtcsdp" => CommunicationType::webrtc_sdp,
|
||||||
"webrtcice" => CommunicationType::WebrtcIce,
|
"webrtcice" => CommunicationType::webrtc_ice,
|
||||||
"startstream" => CommunicationType::StartStream,
|
"startstream" => CommunicationType::start_stream,
|
||||||
"endstream" => CommunicationType::EndStream,
|
"endstream" => CommunicationType::end_stream,
|
||||||
"watchstream" => CommunicationType::WatchStream,
|
"watchstream" => CommunicationType::watch_stream,
|
||||||
"getcall" => CommunicationType::GetCall,
|
"getcall" => CommunicationType::get_call,
|
||||||
"newcall" => CommunicationType::NewCall,
|
"newcall" => CommunicationType::new_call,
|
||||||
"callinvite" => CommunicationType::CallInvite,
|
"callinvite" => CommunicationType::call_invite,
|
||||||
"endcall" => CommunicationType::EndCall,
|
"endcall" => CommunicationType::end_call,
|
||||||
"function" => CommunicationType::Function,
|
"function" => CommunicationType::function,
|
||||||
"update" => CommunicationType::Update,
|
"update" => CommunicationType::update,
|
||||||
_ => CommunicationType::Error, // fallback
|
_ => CommunicationType::error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum LogLevel {
|
|
||||||
Important = 2,
|
|
||||||
Normal = 1,
|
|
||||||
Debug = 0,
|
|
||||||
None = -1,
|
|
||||||
DebugOnly = -2,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LogValue {
|
|
||||||
pub message: String,
|
|
||||||
pub log_level: LogLevel,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogValue {
|
|
||||||
pub fn new(message: impl Into<String>, log_level: LogLevel) -> Self {
|
|
||||||
Self {
|
|
||||||
message: message.into(),
|
|
||||||
log_level,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_json(self) -> JsonValue {
|
|
||||||
object! {
|
|
||||||
message: self.message.clone(),
|
|
||||||
log_level: self.log_level as i32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CommunicationValue {
|
pub struct CommunicationValue {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub comm_type: CommunicationType,
|
pub comm_type: CommunicationType,
|
||||||
pub log_value: Option<LogValue>,
|
|
||||||
pub sender: Uuid,
|
pub sender: Uuid,
|
||||||
pub receiver: Uuid,
|
pub receiver: Uuid,
|
||||||
pub data: HashMap<DataTypes, JsonValue>,
|
pub data: HashMap<DataTypes, JsonValue>,
|
||||||
|
|
@ -296,7 +266,6 @@ impl CommunicationValue {
|
||||||
Self {
|
Self {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
comm_type,
|
comm_type,
|
||||||
log_value: None,
|
|
||||||
sender: Uuid::new_v4(),
|
sender: Uuid::new_v4(),
|
||||||
receiver: Uuid::new_v4(),
|
receiver: Uuid::new_v4(),
|
||||||
data: HashMap::new(),
|
data: HashMap::new(),
|
||||||
|
|
@ -309,13 +278,6 @@ impl CommunicationValue {
|
||||||
pub fn get_id(&self) -> Uuid {
|
pub fn get_id(&self) -> Uuid {
|
||||||
self.id.clone()
|
self.id.clone()
|
||||||
}
|
}
|
||||||
pub fn with_log(mut self, log: LogValue) -> Self {
|
|
||||||
self.log_value = Some(log);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn get_log(&self) -> &Option<LogValue> {
|
|
||||||
&self.log_value
|
|
||||||
}
|
|
||||||
pub fn with_sender(mut self, sender: Uuid) -> Self {
|
pub fn with_sender(mut self, sender: Uuid) -> Self {
|
||||||
self.sender = sender;
|
self.sender = sender;
|
||||||
self
|
self
|
||||||
|
|
@ -342,6 +304,10 @@ impl CommunicationValue {
|
||||||
self.data.insert(key, value);
|
self.data.insert(key, value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
pub fn add_array(mut self, key: DataTypes, value: Array) -> Self {
|
||||||
|
self.data.insert(key, JsonValue::Array(value));
|
||||||
|
self
|
||||||
|
}
|
||||||
pub fn get_data(&mut self, key: DataTypes) -> Option<&JsonValue> {
|
pub fn get_data(&mut self, key: DataTypes) -> Option<&JsonValue> {
|
||||||
self.data.get(&key)
|
self.data.get(&key)
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +326,6 @@ impl CommunicationValue {
|
||||||
type: format!("{:?}", self.comm_type),
|
type: format!("{:?}", self.comm_type),
|
||||||
sender: self.sender.to_string(),
|
sender: self.sender.to_string(),
|
||||||
receiver: self.receiver.to_string(),
|
receiver: self.receiver.to_string(),
|
||||||
log: self.log_value.as_ref().map(|l| l.clone().to_json()).unwrap_or(JsonValue::Null),
|
|
||||||
data: jdata
|
data: jdata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -379,14 +344,6 @@ impl CommunicationValue {
|
||||||
.and_then(|s| Uuid::parse_str(s).ok())
|
.and_then(|s| Uuid::parse_str(s).ok())
|
||||||
.unwrap_or(Uuid::new_v4());
|
.unwrap_or(Uuid::new_v4());
|
||||||
|
|
||||||
let log_value = if parsed["log"].is_object() {
|
|
||||||
Some(LogValue::new(
|
|
||||||
parsed["log"]["message"].as_str().unwrap_or("").to_string(),
|
|
||||||
LogLevel::Normal,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let uuid = Uuid::parse_str(parsed["id"].as_str().unwrap_or("")).unwrap_or(Uuid::new_v4());
|
let uuid = Uuid::parse_str(parsed["id"].as_str().unwrap_or("")).unwrap_or(Uuid::new_v4());
|
||||||
let mut data = HashMap::new();
|
let mut data = HashMap::new();
|
||||||
if parsed["data"].is_object() {
|
if parsed["data"].is_object() {
|
||||||
|
|
@ -399,24 +356,23 @@ impl CommunicationValue {
|
||||||
Self {
|
Self {
|
||||||
id: uuid,
|
id: uuid,
|
||||||
comm_type,
|
comm_type,
|
||||||
log_value,
|
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
data,
|
data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn ack_message(message_id: Uuid, sender: Uuid) -> CommunicationValue {
|
pub fn ack_message(message_id: Uuid, sender: Uuid) -> CommunicationValue {
|
||||||
let mut cv = CommunicationValue::new(CommunicationType::Message).with_id(message_id);
|
let mut cv = CommunicationValue::new(CommunicationType::message).with_id(message_id);
|
||||||
|
|
||||||
if let s = sender {
|
if let s = sender {
|
||||||
cv = cv.add_data(DataTypes::SenderId, JsonValue::String(s.to_string()));
|
cv = cv.add_data(DataTypes::send_time, JsonValue::String(s.to_string()));
|
||||||
}
|
}
|
||||||
cv
|
cv
|
||||||
}
|
}
|
||||||
pub fn forward_to_other_iota(original: &mut CommunicationValue) -> CommunicationValue {
|
pub fn forward_to_other_iota(original: &mut CommunicationValue) -> CommunicationValue {
|
||||||
let receiver = Uuid::from_str(
|
let receiver = Uuid::from_str(
|
||||||
&*original
|
&*original
|
||||||
.get_data(DataTypes::ReceiverId)
|
.get_data(DataTypes::receiver_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
|
|
@ -428,15 +384,15 @@ impl CommunicationValue {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_millis() as i64;
|
.as_millis() as i64;
|
||||||
|
|
||||||
let cv = CommunicationValue::new(CommunicationType::MessageOtherIota)
|
let cv = CommunicationValue::new(CommunicationType::message_other_iota)
|
||||||
.with_id(original.get_id())
|
.with_id(original.get_id())
|
||||||
.with_receiver(receiver.unwrap())
|
.with_receiver(receiver.unwrap())
|
||||||
.add_data(DataTypes::SendTime, JsonValue::String(now_ms.to_string()))
|
.add_data(DataTypes::send_time, JsonValue::String(now_ms.to_string()))
|
||||||
.add_data(
|
.add_data(
|
||||||
DataTypes::MessageContent,
|
DataTypes::message_content,
|
||||||
JsonValue::String(
|
JsonValue::String(
|
||||||
original
|
original
|
||||||
.get_data(DataTypes::MessageContent)
|
.get_data(DataTypes::message_content)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
|
|
@ -444,6 +400,6 @@ impl CommunicationValue {
|
||||||
|
|
||||||
// include sender_id if the original had one
|
// include sender_id if the original had one
|
||||||
let sender = original.get_sender();
|
let sender = original.get_sender();
|
||||||
cv.add_data(DataTypes::SenderId, JsonValue::String(sender.to_string()))
|
cv.add_data(DataTypes::sender_id, JsonValue::String(sender.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,405 @@
|
||||||
|
use crate::langu::language_manager::from_key;
|
||||||
|
use crate::{APP_STATE, omikron::ping_pong_task::PingPongTask};
|
||||||
|
use crossterm::{
|
||||||
|
ExecutableCommand,
|
||||||
|
terminal::{LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
|
||||||
|
};
|
||||||
|
use ratatui::widgets::canvas::{Canvas, Line};
|
||||||
|
use ratatui::{
|
||||||
|
Terminal,
|
||||||
|
backend::CrosstermBackend,
|
||||||
|
layout::{Constraint, Direction, Layout},
|
||||||
|
style::Color,
|
||||||
|
widgets::{Block, Borders, List, ListItem, Paragraph},
|
||||||
|
};
|
||||||
|
use std::{collections::VecDeque, io::stdout, process::Command, thread, time::Duration};
|
||||||
|
use sysinfo::{RefreshKind, System};
|
||||||
|
|
||||||
|
const MAX_POINTS: usize = 1000;
|
||||||
|
const MAX_LOGS: usize = 100;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
logs: VecDeque<String>,
|
||||||
|
cpu: Vec<(f64, f64)>,
|
||||||
|
ram: Vec<(f64, f64)>,
|
||||||
|
ping: Vec<(f64, f64)>,
|
||||||
|
net_up: Vec<(f64, f64)>,
|
||||||
|
net_down: Vec<(f64, f64)>,
|
||||||
|
sys_info: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
logs: VecDeque::new(),
|
||||||
|
cpu: Vec::new(),
|
||||||
|
ram: Vec::new(),
|
||||||
|
ping: Vec::new(),
|
||||||
|
net_up: Vec::new(),
|
||||||
|
net_down: Vec::new(),
|
||||||
|
sys_info: String::from("Loading..."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_log(&mut self, msg: String) {
|
||||||
|
if self.logs.len() >= MAX_LOGS {
|
||||||
|
self.logs.pop_front();
|
||||||
|
}
|
||||||
|
self.logs.push_back(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_cpu(&mut self, pt: (f64, f64)) {
|
||||||
|
self.cpu.push(pt);
|
||||||
|
if self.cpu.len() > MAX_POINTS {
|
||||||
|
self.cpu.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_ram(&mut self, pt: (f64, f64)) {
|
||||||
|
self.ram.push(pt);
|
||||||
|
if self.ram.len() > MAX_POINTS {
|
||||||
|
self.ram.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_ping_val(&mut self, pt: f64) {
|
||||||
|
self.ping.push((self.ping.len() as f64, pt));
|
||||||
|
if self.ping.len() > MAX_POINTS {
|
||||||
|
self.ping.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_net_up(&mut self, pt: (f64, f64)) {
|
||||||
|
self.net_up.push(pt);
|
||||||
|
if self.net_up.len() > MAX_POINTS {
|
||||||
|
self.net_up.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_net_down(&mut self, pt: (f64, f64)) {
|
||||||
|
self.net_down.push(pt);
|
||||||
|
if self.net_down.len() > MAX_POINTS {
|
||||||
|
self.net_down.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_message_trans(key: impl Into<String>) {
|
||||||
|
APP_STATE.lock().unwrap().push_log(from_key(&key.into()));
|
||||||
|
}
|
||||||
|
pub fn log_message(msg: impl Into<String>) {
|
||||||
|
APP_STATE.lock().unwrap().push_log(msg.into());
|
||||||
|
}
|
||||||
|
fn smooth_data(data: &[(f64, f64)], window_size: usize) -> Vec<(f64, f64)> {
|
||||||
|
if data.len() < window_size {
|
||||||
|
return data.to_vec();
|
||||||
|
}
|
||||||
|
let mut smoothed = Vec::with_capacity(data.len());
|
||||||
|
for i in 0..data.len() {
|
||||||
|
let start = if i + 1 >= window_size {
|
||||||
|
i + 1 - window_size
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let window = &data[start..=i];
|
||||||
|
let avg = window.iter().map(|(_, y)| y).sum::<f64>() / window.len() as f64;
|
||||||
|
smoothed.push((data[i].0, avg));
|
||||||
|
}
|
||||||
|
smoothed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downsample_to_fit_width(data: &[(f64, f64)], width: u16) -> Vec<(f64, f64)> {
|
||||||
|
let width_usize = (width as usize) * 2;
|
||||||
|
let len = data.len();
|
||||||
|
if len == 0 {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let slice = if len <= width_usize {
|
||||||
|
data.to_vec()
|
||||||
|
} else {
|
||||||
|
data[len - width_usize..].to_vec()
|
||||||
|
};
|
||||||
|
slice
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_ping_ms(host: &str) -> Option<f64> {
|
||||||
|
// adapt for Windows
|
||||||
|
let output = Command::new("ping")
|
||||||
|
.arg("-c")
|
||||||
|
.arg("1")
|
||||||
|
.arg("-W")
|
||||||
|
.arg("1")
|
||||||
|
.arg(host)
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
let out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
for line in out.lines() {
|
||||||
|
if line.contains("time=") {
|
||||||
|
if let Some(idx) = line.find("time=") {
|
||||||
|
let substr = &line[idx + 5..];
|
||||||
|
if let Some(end) = substr.find(" ms") {
|
||||||
|
let num = &substr[..end];
|
||||||
|
if let Ok(f) = num.parse::<f64>() {
|
||||||
|
return Some(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup() {
|
||||||
|
enable_raw_mode().unwrap();
|
||||||
|
|
||||||
|
// Start a background thread to sample metrics
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut sys = System::new_with_specifics(RefreshKind::new());
|
||||||
|
let mut last_total_received = 0u64;
|
||||||
|
let mut last_total_transmitted = 0u64;
|
||||||
|
let mut counter = 0.0;
|
||||||
|
loop {
|
||||||
|
sys.refresh_all();
|
||||||
|
|
||||||
|
let mut tcpu = 0;
|
||||||
|
for cpu in sys.cpus() {
|
||||||
|
tcpu += cpu.cpu_usage() as i64;
|
||||||
|
tcpu /= 2;
|
||||||
|
}
|
||||||
|
let ram = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.0;
|
||||||
|
|
||||||
|
let mut total_received = 0u64;
|
||||||
|
let mut total_transmitted = 0u64;
|
||||||
|
|
||||||
|
let delta_received = if last_total_received == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
total_received.saturating_sub(last_total_received)
|
||||||
|
};
|
||||||
|
let delta_transmitted = if last_total_transmitted == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
total_transmitted.saturating_sub(last_total_transmitted)
|
||||||
|
};
|
||||||
|
last_total_received = total_received;
|
||||||
|
last_total_transmitted = total_transmitted;
|
||||||
|
|
||||||
|
let net_down = delta_received as f64;
|
||||||
|
let net_up = delta_transmitted as f64;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut st = APP_STATE.lock().unwrap();
|
||||||
|
st.push_cpu((counter, tcpu as f64));
|
||||||
|
st.push_ram((counter, ram));
|
||||||
|
st.push_net_down((counter, net_down));
|
||||||
|
st.push_net_up((counter, net_up));
|
||||||
|
|
||||||
|
st.sys_info = format!(
|
||||||
|
"CPU: {:.1}% RAM: {:.1}%\nNetDown: {} NetUp: {}",
|
||||||
|
tcpu, ram, delta_received, delta_transmitted
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
counter += 1.0;
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// UI rendering loop in a separate thread
|
||||||
|
thread::spawn(move || {
|
||||||
|
let stdout = stdout();
|
||||||
|
let mut terminal = Terminal::new(CrosstermBackend::new(stdout)).unwrap();
|
||||||
|
|
||||||
|
enable_raw_mode().unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
terminal
|
||||||
|
.draw(|f| {
|
||||||
|
let size = f.size();
|
||||||
|
let chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([Constraint::Percentage(40), Constraint::Percentage(60)])
|
||||||
|
.split(size);
|
||||||
|
|
||||||
|
let left = chunks[0];
|
||||||
|
let right = chunks[1];
|
||||||
|
|
||||||
|
{
|
||||||
|
let st = APP_STATE.lock().unwrap();
|
||||||
|
let items: Vec<ListItem> = st
|
||||||
|
.logs
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|s| ListItem::new(s.clone()))
|
||||||
|
.collect();
|
||||||
|
let list = List::new(items)
|
||||||
|
.block(Block::default().title("Logs").borders(Borders::ALL));
|
||||||
|
f.render_widget(list, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
let right_chunks = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([Constraint::Length(5), Constraint::Min(0)])
|
||||||
|
.split(right);
|
||||||
|
|
||||||
|
{
|
||||||
|
let st = APP_STATE.lock().unwrap();
|
||||||
|
let header = Paragraph::new(st.sys_info.clone())
|
||||||
|
.block(Block::default().title("System Info").borders(Borders::ALL));
|
||||||
|
f.render_widget(header, right_chunks[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let grid_chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.split(right_chunks[1]);
|
||||||
|
|
||||||
|
let left_column = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.split(grid_chunks[0]);
|
||||||
|
|
||||||
|
let right_column = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.split(grid_chunks[1]);
|
||||||
|
|
||||||
|
let st = APP_STATE.lock().unwrap();
|
||||||
|
let w = grid_chunks[0].width.saturating_sub(2);
|
||||||
|
|
||||||
|
let ping_ds = downsample_to_fit_width(&smooth_data(&st.ping, 3), w);
|
||||||
|
let cpu_ds = downsample_to_fit_width(&smooth_data(&st.cpu, 3), w);
|
||||||
|
let ram_ds = downsample_to_fit_width(&smooth_data(&st.ram, 3), w);
|
||||||
|
let down_ds = downsample_to_fit_width(&st.net_down, w);
|
||||||
|
let up_ds = downsample_to_fit_width(&st.net_up, w);
|
||||||
|
|
||||||
|
// ---- Render CPU ----
|
||||||
|
{
|
||||||
|
let min_x = cpu_ds.first().map(|(x, _)| *x).unwrap_or(0.0);
|
||||||
|
let max_x = cpu_ds.last().map(|(x, _)| *x).unwrap_or(100.0);
|
||||||
|
|
||||||
|
let canvas = Canvas::default()
|
||||||
|
.block(Block::default().title("CPU %").borders(Borders::ALL))
|
||||||
|
.x_bounds([min_x, max_x])
|
||||||
|
.y_bounds([0.0, 100.0])
|
||||||
|
.paint(|ctx| {
|
||||||
|
for (x, y) in &cpu_ds {
|
||||||
|
ctx.draw(&Line {
|
||||||
|
x1: *x,
|
||||||
|
y1: 0.0,
|
||||||
|
x2: *x,
|
||||||
|
y2: *y,
|
||||||
|
color: Color::Cyan,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.render_widget(canvas, left_column[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Render RAM ----
|
||||||
|
{
|
||||||
|
let min_x = ram_ds.first().map(|(x, _)| *x).unwrap_or(0.0);
|
||||||
|
let max_x = ram_ds.last().map(|(x, _)| *x).unwrap_or(100.0);
|
||||||
|
let canvas = Canvas::default()
|
||||||
|
.block(Block::default().title("RAM %").borders(Borders::ALL))
|
||||||
|
.x_bounds([min_x, max_x])
|
||||||
|
.y_bounds([0.0, 100.0])
|
||||||
|
.paint(|ctx| {
|
||||||
|
for (x, y) in &ram_ds {
|
||||||
|
ctx.draw(&Line {
|
||||||
|
x1: *x,
|
||||||
|
y1: 0.0,
|
||||||
|
x2: *x,
|
||||||
|
y2: *y,
|
||||||
|
color: Color::Magenta,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.render_widget(canvas, left_column[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Render Ping ----
|
||||||
|
{
|
||||||
|
let min_x = ping_ds.first().map(|(x, _)| *x).unwrap_or(0.0);
|
||||||
|
let max_x = ping_ds.last().map(|(x, _)| *x).unwrap_or(100.0);
|
||||||
|
let max_y = ping_ds.iter().map(|(_, y)| *y).fold(1.0, f64::max);
|
||||||
|
|
||||||
|
let canvas = Canvas::default()
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.title(format!("Ping {}(ms)", max_y))
|
||||||
|
.borders(Borders::ALL),
|
||||||
|
)
|
||||||
|
.x_bounds([min_x, max_x])
|
||||||
|
.y_bounds([0.0, max_y])
|
||||||
|
.paint(|ctx| {
|
||||||
|
for (x, y) in &ping_ds {
|
||||||
|
ctx.draw(&Line {
|
||||||
|
x1: *x,
|
||||||
|
y1: 0.0,
|
||||||
|
x2: *x,
|
||||||
|
y2: *y,
|
||||||
|
color: Color::Yellow,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.render_widget(canvas, right_column[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Render Network ----
|
||||||
|
{
|
||||||
|
let min_x = up_ds.first().map(|(x, _)| *x).unwrap_or(0.0);
|
||||||
|
let max_x = up_ds.last().map(|(x, _)| *x).unwrap_or(100.0);
|
||||||
|
let mut max_sum: f64 = 1.0;
|
||||||
|
for ((_, up), (_, down)) in up_ds.iter().zip(down_ds.iter()) {
|
||||||
|
max_sum = max_sum.max(up + down);
|
||||||
|
}
|
||||||
|
|
||||||
|
let canvas = Canvas::default()
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.title("Network Up/Down")
|
||||||
|
.borders(Borders::ALL),
|
||||||
|
)
|
||||||
|
.x_bounds([min_x, max_x])
|
||||||
|
.y_bounds([0.0, max_sum])
|
||||||
|
.paint(|ctx| {
|
||||||
|
for (x, dval) in &down_ds {
|
||||||
|
ctx.draw(&Line {
|
||||||
|
x1: *x,
|
||||||
|
y1: 0.0,
|
||||||
|
x2: *x,
|
||||||
|
y2: *dval,
|
||||||
|
color: Color::Red,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (x, uval) in &up_ds {
|
||||||
|
let dval = down_ds
|
||||||
|
.iter()
|
||||||
|
.find(|(xx, _)| (*xx - *x).abs() < f64::EPSILON)
|
||||||
|
.map(|(_, y)| *y)
|
||||||
|
.unwrap_or(0.0);
|
||||||
|
|
||||||
|
ctx.draw(&Line {
|
||||||
|
x1: *x,
|
||||||
|
y1: dval,
|
||||||
|
x2: *x,
|
||||||
|
y2: dval + *uval,
|
||||||
|
color: Color::Green,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
f.render_widget(canvas, right_column[1]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Clean up terminal before exit
|
||||||
|
disable_raw_mode().unwrap();
|
||||||
|
stdout().execute(LeaveAlternateScreen).unwrap();
|
||||||
|
}
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod log_panel;
|
||||||
pub mod ratatui_interface;
|
pub mod ratatui_interface;
|
||||||
|
|
@ -9,19 +9,15 @@ pub fn create_languages() {
|
||||||
let mut debug_messages = JsonValue::new_object();
|
let mut debug_messages = JsonValue::new_object();
|
||||||
|
|
||||||
// FRONTEND
|
// FRONTEND
|
||||||
frontend_messages.insert(
|
frontend_messages.insert("GET_CHATS", "User {} is loading conversations");
|
||||||
"USER_CONTEXT_GET_CONVERSATIONS",
|
frontend_messages.insert("MESSAGE_GET", "User {} is loading messages");
|
||||||
"User {} is loading conversations",
|
frontend_messages.insert("get_communities", "User {} is loading communities");
|
||||||
);
|
frontend_messages.insert("client_connected", "Client {} connected");
|
||||||
frontend_messages.insert(
|
frontend_messages.insert("add_conversation", "User {} added {}");
|
||||||
"USER_CONTEXT_GET_COMMUNITIES",
|
|
||||||
"User {} is loading communities",
|
|
||||||
);
|
|
||||||
frontend_messages.insert("ADD_CONVERSATION", "User {} added {}");
|
|
||||||
|
|
||||||
// OMIKRON
|
// OMIKRON
|
||||||
omikron_messages.insert(
|
omikron_messages.insert(
|
||||||
"IdentificationResponse",
|
"identification_response",
|
||||||
"IOTA identified on Omikron, {} users!",
|
"IOTA identified on Omikron, {} users!",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -32,6 +28,7 @@ pub fn create_languages() {
|
||||||
general_texts.insert("IOTA_ID", "IOTA ID: {}-####-####-####-############");
|
general_texts.insert("IOTA_ID", "IOTA ID: {}-####-####-####-############");
|
||||||
general_texts.insert("USER_ID", "USER ID: {}");
|
general_texts.insert("USER_ID", "USER ID: {}");
|
||||||
general_texts.insert("USER_IDS", "USER IDS: {}");
|
general_texts.insert("USER_IDS", "USER IDS: {}");
|
||||||
|
general_texts.insert("SETUP_COMPLETED", "Launched");
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
debug_messages.insert("", "");
|
debug_messages.insert("", "");
|
||||||
|
|
@ -55,4 +52,9 @@ pub fn create_languages() {
|
||||||
"debug.json",
|
"debug.json",
|
||||||
&debug_messages.to_string(),
|
&debug_messages.to_string(),
|
||||||
);
|
);
|
||||||
|
save_file(
|
||||||
|
"languages/en_INT",
|
||||||
|
"general.json",
|
||||||
|
&general_texts.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,7 @@ pub fn from_key(key: &str) -> String {
|
||||||
LANGUAGE_PACK
|
LANGUAGE_PACK
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.language
|
.get_translation(key)
|
||||||
.get(key)
|
|
||||||
.unwrap_or(&String::new())
|
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,9 +88,18 @@ impl LanguagePack {
|
||||||
self.language
|
self.language
|
||||||
.insert(key.to_string(), value.as_str().unwrap().to_string());
|
.insert(key.to_string(), value.as_str().unwrap().to_string());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_translation(&self, key: &str) -> &String {
|
let general_messages = file_util::load_file(&path, "general.json");
|
||||||
self.language.get(key).unwrap()
|
let general_messages = parse(&general_messages).unwrap();
|
||||||
|
for (key, value) in general_messages.entries() {
|
||||||
|
self.language
|
||||||
|
.insert(key.to_string(), value.as_str().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_translation(&self, key: &str) -> String {
|
||||||
|
match self.language.get(key) {
|
||||||
|
Some(v) if !v.is_empty() => v.clone(),
|
||||||
|
_ => key.to_uppercase(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
src/main.rs
51
src/main.rs
|
|
@ -1,41 +1,30 @@
|
||||||
use base64::Engine;
|
|
||||||
use base64::engine::general_purpose;
|
|
||||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
|
||||||
use futures_util::SinkExt;
|
|
||||||
use json::JsonValue::String;
|
use json::JsonValue::String;
|
||||||
use json::{self, JsonValue};
|
use json::{self};
|
||||||
use rand::Rng;
|
|
||||||
use rand_core::OsRng;
|
|
||||||
use rand_core::RngCore;
|
|
||||||
use reqwest::header::PUBLIC_KEY_PINS_REPORT_ONLY;
|
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
use std::sync::Mutex;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use x448::{PublicKey, Secret};
|
|
||||||
|
|
||||||
|
mod auth;
|
||||||
mod data;
|
mod data;
|
||||||
mod eula;
|
mod eula;
|
||||||
|
mod gui;
|
||||||
|
mod langu;
|
||||||
mod omikron;
|
mod omikron;
|
||||||
mod users;
|
mod users;
|
||||||
mod util;
|
mod util;
|
||||||
mod gui {
|
|
||||||
pub mod ratatui_interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod auth;
|
|
||||||
mod langu;
|
|
||||||
use crate::auth::auth_connector::AuthConnector;
|
|
||||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
use crate::eula::*;
|
use crate::gui::log_panel;
|
||||||
|
use crate::gui::log_panel::{AppState, log_message, log_message_trans};
|
||||||
use crate::langu::language_creator;
|
use crate::langu::language_creator;
|
||||||
use crate::langu::language_manager;
|
|
||||||
use crate::omikron::omikron_connection::OmikronConnection;
|
use crate::omikron::omikron_connection::OmikronConnection;
|
||||||
use crate::omikron::ping_pong_task::PingPongTask;
|
use crate::omikron::ping_pong_task::PingPongTask;
|
||||||
use crate::users::user_manager::UserManager;
|
use crate::users::user_manager::UserManager;
|
||||||
use crate::users::user_profile::UserProfile;
|
use crate::util::config_util::CONFIG;
|
||||||
use crate::users::user_profile_full::UserProfileFull;
|
|
||||||
use crate::util::config_util::{self, CONFIG, ConfigUtil};
|
pub static APP_STATE: LazyLock<Arc<Mutex<AppState>>> =
|
||||||
use crate::util::file_util;
|
LazyLock::new(|| Arc::new(Mutex::new(AppState::new())));
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
@ -46,8 +35,8 @@ async fn main() {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
gui::ratatui_interface::launch(false);
|
|
||||||
|
|
||||||
|
log_panel::setup();
|
||||||
// LANGUAGE PACK
|
// LANGUAGE PACK
|
||||||
language_creator::create_languages();
|
language_creator::create_languages();
|
||||||
|
|
||||||
|
|
@ -68,8 +57,9 @@ async fn main() {
|
||||||
|
|
||||||
if !sb.is_empty() {
|
if !sb.is_empty() {
|
||||||
sb.remove(0);
|
sb.remove(0);
|
||||||
|
sb = sb + ",";
|
||||||
}
|
}
|
||||||
println!(
|
log_message(format!(
|
||||||
"IOTA ID: {}-####-####-####-############",
|
"IOTA ID: {}-####-####-####-############",
|
||||||
CONFIG
|
CONFIG
|
||||||
.lock()
|
.lock()
|
||||||
|
|
@ -79,8 +69,8 @@ async fn main() {
|
||||||
.split("-")
|
.split("-")
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
));
|
||||||
println!("User ID: {}", sb);
|
log_message(format!("User IDS: {}", sb));
|
||||||
|
|
||||||
// IDENTIFICATION ON OMIKRON
|
// IDENTIFICATION ON OMIKRON
|
||||||
let omikron: OmikronConnection = OmikronConnection::new();
|
let omikron: OmikronConnection = OmikronConnection::new();
|
||||||
|
|
@ -88,10 +78,10 @@ async fn main() {
|
||||||
let _ping_pong_task = PingPongTask::new(Arc::new(OmikronConnection::new()));
|
let _ping_pong_task = PingPongTask::new(Arc::new(OmikronConnection::new()));
|
||||||
omikron
|
omikron
|
||||||
.send_message(
|
.send_message(
|
||||||
CommunicationValue::new(CommunicationType::Identification)
|
CommunicationValue::new(CommunicationType::identification)
|
||||||
.add_data(DataTypes::UserIds, String(sb.to_string()))
|
.add_data(DataTypes::user_ids, String(sb.to_string()))
|
||||||
.add_data(
|
.add_data(
|
||||||
DataTypes::IotaId,
|
DataTypes::iota_id,
|
||||||
String(CONFIG.lock().unwrap().get_iota_id().to_string()),
|
String(CONFIG.lock().unwrap().get_iota_id().to_string()),
|
||||||
)
|
)
|
||||||
.to_json()
|
.to_json()
|
||||||
|
|
@ -100,6 +90,7 @@ async fn main() {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
log_message_trans("SETUP_COMPLETED");
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
use crate::APP_STATE;
|
||||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
use crate::omikron::ping_pong_task::PingPongTask;
|
use crate::gui::log_panel::log_message;
|
||||||
|
use crate::gui::log_panel::log_message_trans;
|
||||||
|
use crate::omikron::ping_pong_task::{self, PingPongTask};
|
||||||
use crate::users::contact::Contact;
|
use crate::users::contact::Contact;
|
||||||
use crate::users::user_community_util::UserCommunityUtil;
|
use crate::users::user_community_util::UserCommunityUtil;
|
||||||
use crate::util::chat_files::ChatFiles;
|
use crate::util::chat_files::ChatFiles;
|
||||||
|
|
@ -8,6 +11,7 @@ use futures_util::{SinkExt, StreamExt};
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
use json::number::Number;
|
use json::number::Number;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::pin::Pin;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
@ -31,8 +35,9 @@ pub struct OmikronConnection {
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
waiting: Arc<Mutex<HashMap<Uuid, Box<dyn Fn(CommunicationValue) + Send>>>>, // waiting for responses
|
waiting: Arc<Mutex<HashMap<Uuid, Box<dyn Fn(CommunicationValue) + Send + Sync>>>>, // waiting for responses
|
||||||
pingpong: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>, // ping-pong handler
|
pingpong: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>, // ping-pong handler
|
||||||
|
ping_pong_task: Arc<Mutex<Option<Arc<PingPongTask>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OmikronConnection {
|
impl OmikronConnection {
|
||||||
|
|
@ -41,18 +46,27 @@ impl OmikronConnection {
|
||||||
writer: Arc::new(Mutex::new(None)),
|
writer: Arc::new(Mutex::new(None)),
|
||||||
waiting: Arc::new(Mutex::new(HashMap::new())),
|
waiting: Arc::new(Mutex::new(HashMap::new())),
|
||||||
pingpong: Arc::new(Mutex::new(None)),
|
pingpong: Arc::new(Mutex::new(None)),
|
||||||
|
ping_pong_task: Arc::new(Mutex::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect loop with retry
|
/// Connect loop with retry
|
||||||
pub async fn connect<'a>(&'a self) {
|
pub async fn connect(&self) {
|
||||||
loop {
|
loop {
|
||||||
match connect_async("wss://tensamin.methanium.net/ws/iota/").await {
|
match connect_async("wss://tensamin.methanium.net/ws/iota/").await {
|
||||||
Ok((ws_stream, _)) => {
|
Ok((ws_stream, _)) => {
|
||||||
let (write_half, read_half) = ws_stream.split();
|
let (write_half, read_half) = ws_stream.split();
|
||||||
*self.writer.lock().await = Some(write_half);
|
*self.writer.lock().await = Some(write_half);
|
||||||
self.spawn_listener(read_half);
|
self.spawn_listener(read_half).await;
|
||||||
self.start_ping_pong_task().await;
|
|
||||||
|
let ppt = PingPongTask::new(Arc::new(self.clone()));
|
||||||
|
*self.ping_pong_task.lock().await = Some(Arc::new(ppt.clone()));
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
ppt.send_ping();
|
||||||
|
sleep(Duration::from_secs(5)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -61,18 +75,6 @@ impl OmikronConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the PingPongTask
|
|
||||||
pub async fn start_ping_pong_task(&self) {
|
|
||||||
let ping_pong_task = PingPongTask::new(Arc::new(self.clone()));
|
|
||||||
|
|
||||||
// Store the task handle in `pingpong` so we can manage it
|
|
||||||
let mut pingpong_handle = self.pingpong.lock().await;
|
|
||||||
*pingpong_handle = Some(tokio::spawn(async move {
|
|
||||||
ping_pong_task.run_ping_loop();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_message(&self, msg: String) {
|
pub async fn send_message(&self, msg: String) {
|
||||||
Self::send_message_static(&self.writer, msg).await;
|
Self::send_message_static(&self.writer, msg).await;
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +89,7 @@ impl OmikronConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listener for all incoming messages
|
/// Listener for all incoming messages
|
||||||
fn spawn_listener(
|
async fn spawn_listener(
|
||||||
&self,
|
&self,
|
||||||
mut read_half: futures_util::stream::SplitStream<
|
mut read_half: futures_util::stream::SplitStream<
|
||||||
WebSocketStream<MaybeTlsStream<TcpStream>>,
|
WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||||
|
|
@ -95,57 +97,60 @@ impl OmikronConnection {
|
||||||
) {
|
) {
|
||||||
let waiting = self.waiting.clone();
|
let waiting = self.waiting.clone();
|
||||||
let writer = self.writer.clone();
|
let writer = self.writer.clone();
|
||||||
|
let sel = self.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(msg) = read_half.next().await {
|
while let Some(msg) = read_half.next().await {
|
||||||
match msg {
|
match msg {
|
||||||
Ok(Message::Close(Some(frame))) => {
|
Ok(Message::Close(Some(frame))) => {
|
||||||
println!("[Omikron] Closed: {:?}", frame);
|
log_message(format!("[Omikron] Closed: {:?}", frame));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(Message::Text(text)) => {
|
Ok(Message::Text(text)) => {
|
||||||
let mut cv = CommunicationValue::from_json(&text); // needs CommunicationValue parser
|
let mut cv = CommunicationValue::from_json(&text); // needs CommunicationValue parser
|
||||||
if cv.is_type(CommunicationType::Pong) {
|
if cv.is_type(CommunicationType::pong) {
|
||||||
// handle pingpong reset here
|
sel.ping_pong_task
|
||||||
continue;
|
.lock()
|
||||||
|
.await
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.handle_pong(&cv, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// ************************************************ //
|
// ************************************************ //
|
||||||
// Direct messages //
|
// Direct messages //
|
||||||
// ************************************************ //
|
// ************************************************ //
|
||||||
println!("[Omikron] Received message: {:?}", cv);
|
|
||||||
if cv.is_type(CommunicationType::MessageOtherIota) {
|
log_message_trans(format!("{:?}", &cv.comm_type));
|
||||||
|
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();
|
||||||
|
|
||||||
ChatFiles::add_message(
|
ChatFiles::add_message(
|
||||||
cv.get_data(DataTypes::SendTime)
|
cv.get_data(DataTypes::send_time)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_i64()
|
.as_i64()
|
||||||
.unwrap_or(-1),
|
.unwrap_or(-1),
|
||||||
false,
|
false,
|
||||||
*receiver_id,
|
*receiver_id,
|
||||||
*sender_id,
|
*sender_id,
|
||||||
cv.get_data(DataTypes::MessageContent)
|
cv.get_data(DataTypes::message_content)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
false,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
let response = CommunicationValue::new(CommunicationType::MessageLive)
|
let response = CommunicationValue::new(CommunicationType::message_live)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(cv.get_receiver())
|
.with_receiver(cv.get_receiver())
|
||||||
.add_data(
|
.add_data(
|
||||||
DataTypes::SendTime,
|
DataTypes::send_time,
|
||||||
cv.get_data(DataTypes::SendTime).unwrap().clone(),
|
cv.get_data(DataTypes::send_time).unwrap().clone(),
|
||||||
)
|
)
|
||||||
.add_data(
|
.add_data(
|
||||||
DataTypes::Message,
|
DataTypes::message,
|
||||||
cv.get_data(DataTypes::MessageContent).unwrap().clone(),
|
cv.get_data(DataTypes::message_content).unwrap().clone(),
|
||||||
)
|
)
|
||||||
.add_data(
|
.add_data(
|
||||||
DataTypes::SenderId,
|
DataTypes::sender_id,
|
||||||
JsonValue::String(cv.get_sender().clone().to_string()),
|
JsonValue::String(cv.get_sender().clone().to_string()),
|
||||||
);
|
);
|
||||||
Self::send_message_static(
|
Self::send_message_static(
|
||||||
|
|
@ -156,26 +161,24 @@ impl OmikronConnection {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::Message) {
|
if cv.is_type(CommunicationType::message) {
|
||||||
/*
|
/* DATA CONTAINER:
|
||||||
"user": {
|
"sent_by_self": true,
|
||||||
"avatar": true,
|
"timestamp": unixTimestamp,
|
||||||
"display": true,
|
"files": [ // wenn keine files dann weglassen
|
||||||
"timestamp": true
|
|
||||||
},
|
|
||||||
"body": {
|
|
||||||
"tint": "<hex color>",
|
|
||||||
"content": "<markdown (encrypted)>",
|
|
||||||
"files": [
|
|
||||||
{
|
{
|
||||||
"name": "<cool name>",
|
"name": "<name>",
|
||||||
"id": "<uuid>",
|
"id": "<uuid>",
|
||||||
"type": "[ image | image_top_right | file ]"
|
"type": "[ image | image_top_right | file ]"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
"content": "<enc markdown>"
|
||||||
*/
|
*/
|
||||||
let my_id = cv.get_sender();
|
let my_id = cv.get_sender();
|
||||||
|
let other_id = Uuid::from_str(
|
||||||
|
&*cv.get_data(DataTypes::receiver_id).unwrap().to_string(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
ChatFiles::add_message(
|
ChatFiles::add_message(
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|
@ -183,20 +186,12 @@ impl OmikronConnection {
|
||||||
.as_millis() as i64,
|
.as_millis() as i64,
|
||||||
true,
|
true,
|
||||||
my_id,
|
my_id,
|
||||||
Uuid::from_str(
|
other_id,
|
||||||
&*cv.get_data(DataTypes::ReceiverId).unwrap().to_string(),
|
&*cv.get_data(DataTypes::message_content).unwrap().to_string(),
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
&*cv.get_data(DataTypes::MessageContent).unwrap().to_string(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
// ack
|
|
||||||
let ack = CommunicationValue::ack_message(cv.get_id(), my_id);
|
let ack = CommunicationValue::ack_message(cv.get_id(), my_id);
|
||||||
Self::send_message_static(&writer.clone(), ack.to_json().to_string())
|
Self::send_message_static(&writer.clone(), ack.to_json().to_string())
|
||||||
.await;
|
.await;
|
||||||
// forward
|
|
||||||
let forward = CommunicationValue::forward_to_other_iota(&mut cv);
|
let forward = CommunicationValue::forward_to_other_iota(&mut cv);
|
||||||
Self::send_message_static(
|
Self::send_message_static(
|
||||||
&writer.clone(),
|
&writer.clone(),
|
||||||
|
|
@ -206,55 +201,52 @@ impl OmikronConnection {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::MessageGet) {
|
if cv.is_type(CommunicationType::message_get) {
|
||||||
let my_id = cv.get_sender();
|
let my_id = cv.get_sender();
|
||||||
let partner_id = Uuid::from_str(
|
let partner_id = Uuid::from_str(
|
||||||
&*cv.get_data(DataTypes::ChatPartnerId).unwrap().to_string(),
|
&*cv.get_data(DataTypes::user_id).unwrap().to_string(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let offset = cv
|
let offset = cv
|
||||||
.get_data(DataTypes::LoadedMessages)
|
.get_data(DataTypes::loaded_messages)
|
||||||
.unwrap_or(&JsonValue::Null)
|
.unwrap_or(&JsonValue::Null)
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<i64>()
|
.parse::<i64>()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let amount = cv
|
let amount = cv
|
||||||
.get_data(DataTypes::MessageAmount)
|
.get_data(DataTypes::message_amount)
|
||||||
.unwrap_or(&JsonValue::Null)
|
.unwrap_or(&JsonValue::Null)
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<i64>()
|
.parse::<i64>()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let messages =
|
let messages =
|
||||||
ChatFiles::get_messages(my_id, partner_id, offset, amount); // needs ChatFiles
|
ChatFiles::get_messages(my_id, partner_id, offset, amount);
|
||||||
let mut resp = CommunicationValue::new(CommunicationType::MessageChunk)
|
let resp = CommunicationValue::new(CommunicationType::message_chunk)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(my_id);
|
.with_receiver(my_id)
|
||||||
if !messages.is_empty() {
|
.add_data(DataTypes::message_chunk, messages);
|
||||||
resp = resp.add_data(DataTypes::MessageChunk, messages);
|
|
||||||
}
|
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
.await;
|
.await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::GetChats) {
|
if cv.is_type(CommunicationType::get_chats) {
|
||||||
let user_id = cv.get_sender();
|
let user_id = cv.get_sender();
|
||||||
let users = get_users(user_id); // needs ChatsUtil
|
let users = get_users(user_id);
|
||||||
let resp = CommunicationValue::new(CommunicationType::GetChats)
|
let resp = CommunicationValue::new(CommunicationType::get_chats)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(user_id)
|
.with_receiver(user_id)
|
||||||
.add_data(DataTypes::UserIds, users);
|
.add_data(DataTypes::user_ids, users);
|
||||||
println!("ALARM: {}", resp.to_json().to_string());
|
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
.await;
|
.await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::AddChat) {
|
if cv.is_type(CommunicationType::add_chat) {
|
||||||
let user_id = cv.get_sender();
|
let user_id = cv.get_sender();
|
||||||
let other_id = Uuid::from_str(
|
let other_id = Uuid::from_str(
|
||||||
&*cv.get_data(DataTypes::UserId).unwrap().to_string(),
|
&*cv.get_data(DataTypes::user_id).unwrap().to_string(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut contact =
|
let mut contact =
|
||||||
|
|
@ -266,7 +258,7 @@ impl OmikronConnection {
|
||||||
.as_millis() as i64,
|
.as_millis() as i64,
|
||||||
);
|
);
|
||||||
mod_user(user_id, &contact);
|
mod_user(user_id, &contact);
|
||||||
let resp = CommunicationValue::new(CommunicationType::AddChat)
|
let resp = CommunicationValue::new(CommunicationType::add_chat)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(user_id);
|
.with_receiver(user_id);
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
|
|
@ -274,16 +266,16 @@ impl OmikronConnection {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::AddCommunity) {
|
if cv.is_type(CommunicationType::add_community) {
|
||||||
UserCommunityUtil::add_community(
|
UserCommunityUtil::add_community(
|
||||||
cv.get_sender(),
|
cv.get_sender(),
|
||||||
cv.get_data(DataTypes::CommunityAddress)
|
cv.get_data(DataTypes::community_address)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
cv.get_data(DataTypes::CommunityTitle).unwrap().to_string(),
|
cv.get_data(DataTypes::community_title).unwrap().to_string(),
|
||||||
cv.get_data(DataTypes::Position).unwrap().to_string(),
|
cv.get_data(DataTypes::position).unwrap().to_string(),
|
||||||
);
|
);
|
||||||
let resp = CommunicationValue::new(CommunicationType::AddCommunity)
|
let resp = CommunicationValue::new(CommunicationType::add_community)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(cv.get_sender());
|
.with_receiver(cv.get_sender());
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
|
|
@ -291,12 +283,12 @@ impl OmikronConnection {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::GetCommunities) {
|
if cv.is_type(CommunicationType::get_communities) {
|
||||||
let resp = CommunicationValue::new(CommunicationType::GetCommunities)
|
let resp = CommunicationValue::new(CommunicationType::get_communities)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(cv.get_sender())
|
.with_receiver(cv.get_sender())
|
||||||
.add_data(
|
.add_array(
|
||||||
DataTypes::Communities,
|
DataTypes::communities,
|
||||||
UserCommunityUtil::get_communities(cv.get_sender()),
|
UserCommunityUtil::get_communities(cv.get_sender()),
|
||||||
); // needs UserCommunityUtil
|
); // needs UserCommunityUtil
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
|
|
@ -304,14 +296,14 @@ impl OmikronConnection {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cv.is_type(CommunicationType::RemoveCommunity) {
|
if cv.is_type(CommunicationType::remove_community) {
|
||||||
UserCommunityUtil::remove_community(
|
UserCommunityUtil::remove_community(
|
||||||
cv.get_sender(),
|
cv.get_sender(),
|
||||||
cv.get_data(DataTypes::CommunityAddress)
|
cv.get_data(DataTypes::community_address)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
); // needs UserCommunityUtil
|
); // needs UserCommunityUtil
|
||||||
let resp = CommunicationValue::new(CommunicationType::RemoveCommunity)
|
let resp = CommunicationValue::new(CommunicationType::remove_community)
|
||||||
.with_id(cv.get_id())
|
.with_id(cv.get_id())
|
||||||
.with_receiver(cv.get_sender());
|
.with_receiver(cv.get_sender());
|
||||||
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
Self::send_message_static(&writer.clone(), resp.to_json().to_string())
|
||||||
|
|
@ -320,7 +312,7 @@ impl OmikronConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[Omikron] Error: {}", e);
|
log_message(format!("[Omikron] Error: {}", e));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -351,23 +343,11 @@ impl OmikronConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_answer<F>(&self, message_id: Uuid, callback: F)
|
|
||||||
where
|
|
||||||
F: Fn(CommunicationValue) + Send + 'static,
|
|
||||||
{
|
|
||||||
tokio::spawn({
|
|
||||||
let waiting = self.waiting.clone();
|
|
||||||
async move {
|
|
||||||
waiting.lock().await.insert(message_id, Box::new(callback));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_ping_message(&self, uuid: Uuid) {
|
pub async fn send_ping_message(&self, uuid: Uuid) {
|
||||||
// Send the ping message over the connection
|
// Send the ping message over the connection
|
||||||
let ping_message = CommunicationValue::new(CommunicationType::Ping)
|
let ping_message = CommunicationValue::new(CommunicationType::ping)
|
||||||
.with_id(uuid)
|
.with_id(uuid)
|
||||||
.add_data_num(DataTypes::LastPing, Number::from(2))
|
.add_data_num(DataTypes::last_ping, Number::from(2))
|
||||||
.to_json()
|
.to_json()
|
||||||
.to_string();
|
.to_string();
|
||||||
self.send_message(ping_message).await;
|
self.send_message(ping_message).await;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
use crate::APP_STATE;
|
||||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
|
use crate::gui::log_panel::AppState;
|
||||||
use crate::omikron::omikron_connection::OmikronConnection;
|
use crate::omikron::omikron_connection::OmikronConnection;
|
||||||
use color_eyre::owo_colors::OwoColorize;
|
use color_eyre::owo_colors::OwoColorize;
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use std::arch::x86_64::_SIDD_MASKED_NEGATIVE_POLARITY;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
@ -10,12 +13,22 @@ use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PingPongTask {
|
pub struct PingPongTask {
|
||||||
pub parent: Arc<OmikronConnection>, // assuming OmikronConnection is your connection type
|
pub parent: Arc<OmikronConnection>,
|
||||||
pub message_send_times: Arc<Mutex<HashMap<Uuid, Instant>>>,
|
pub message_send_times: Arc<Mutex<HashMap<Uuid, Instant>>>,
|
||||||
pub no_ping_in: Arc<Mutex<i32>>,
|
pub no_ping_in: Arc<Mutex<i32>>,
|
||||||
pub last_ping: Arc<Mutex<Option<u64>>>,
|
pub last_ping: Arc<Mutex<Option<u64>>>,
|
||||||
}
|
}
|
||||||
|
fn assert_send_sync<T: Send + Sync>() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_omikron_connection_send_sync() {
|
||||||
|
assert_send_sync::<OmikronConnection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_pingpong_task_send_sync() {
|
||||||
|
assert_send_sync::<PingPongTask>();
|
||||||
|
}
|
||||||
impl PingPongTask {
|
impl PingPongTask {
|
||||||
pub fn new(parent: Arc<OmikronConnection>) -> Self {
|
pub fn new(parent: Arc<OmikronConnection>) -> Self {
|
||||||
let message_send_times = Arc::new(Mutex::new(HashMap::new()));
|
let message_send_times = Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
|
@ -29,50 +42,32 @@ impl PingPongTask {
|
||||||
last_ping: last_ping.clone(),
|
last_ping: last_ping.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Spawn the periodic ping task
|
|
||||||
tokio::spawn({
|
|
||||||
let task = task.clone(); // Clone the task (Arc) so that it lives long enough for the async task
|
|
||||||
async move {
|
|
||||||
task.run_ping_loop().await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
task
|
task
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_ping_loop(&self) {
|
pub fn send_ping(&self) {
|
||||||
loop {
|
let sel = self.clone();
|
||||||
sleep(Duration::from_secs(5)).await;
|
tokio::spawn(async move {
|
||||||
self.send_ping().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_ping(&self) {
|
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let send_time = Instant::now();
|
let send_time = Instant::now();
|
||||||
|
let mut message_send_times = sel.message_send_times.lock().await;
|
||||||
{
|
|
||||||
let mut message_send_times = self.message_send_times.lock().await;
|
|
||||||
message_send_times.insert(uuid, send_time);
|
message_send_times.insert(uuid, send_time);
|
||||||
}
|
|
||||||
|
|
||||||
let no_ping_in = {
|
let no_ping_in_val = {
|
||||||
let no_ping_in = self.no_ping_in.lock().await;
|
let no_ping_in = sel.no_ping_in.lock().await;
|
||||||
*no_ping_in
|
*no_ping_in
|
||||||
};
|
};
|
||||||
|
|
||||||
if no_ping_in != -1 {
|
if no_ping_in_val != -1 {
|
||||||
// Connection slow or disconnected
|
sel.handle_slow_connection(no_ping_in_val).await;
|
||||||
self.handle_slow_connection(no_ping_in).await;
|
|
||||||
} else {
|
} else {
|
||||||
// Connection is fine
|
sel.parent.send_ping_message(uuid).await;
|
||||||
self.parent.send_ping_message(uuid).await;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_slow_connection(&self, no_ping_in: i32) {
|
pub async fn handle_slow_connection(&self, no_ping_in: i32) {
|
||||||
if no_ping_in > 8 {
|
if no_ping_in > 8 {
|
||||||
// Attempt reconnection if ping times out
|
|
||||||
self.parent.reconnect().await;
|
self.parent.reconnect().await;
|
||||||
self.reconnect().await;
|
self.reconnect().await;
|
||||||
}
|
}
|
||||||
|
|
@ -80,12 +75,15 @@ impl PingPongTask {
|
||||||
|
|
||||||
pub async fn reconnect(&self) {
|
pub async fn reconnect(&self) {
|
||||||
let mut no_ping_in = self.no_ping_in.lock().await;
|
let mut no_ping_in = self.no_ping_in.lock().await;
|
||||||
*no_ping_in = -1; // Reset slow count
|
*no_ping_in = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_pong(&self, cv: &CommunicationValue) {
|
pub fn handle_pong(&self, cv: &CommunicationValue, log: bool) {
|
||||||
|
let sel = self.clone();
|
||||||
|
let cv = cv.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
let send_time = {
|
let send_time = {
|
||||||
let message_send_times = self.message_send_times.lock().await;
|
let message_send_times = sel.message_send_times.lock().await;
|
||||||
message_send_times.get(&cv.get_id()).cloned()
|
message_send_times.get(&cv.get_id()).cloned()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -93,24 +91,23 @@ impl PingPongTask {
|
||||||
let receive_time = Instant::now();
|
let receive_time = Instant::now();
|
||||||
let ping = receive_time.duration_since(send_time).as_millis() as u64;
|
let ping = receive_time.duration_since(send_time).as_millis() as u64;
|
||||||
|
|
||||||
{
|
let mut last_ping = sel.last_ping.lock().await;
|
||||||
let mut last_ping = self.last_ping.lock().await;
|
|
||||||
*last_ping = Some(ping);
|
*last_ping = Some(ping);
|
||||||
}
|
let mut no_ping_in = sel.no_ping_in.lock().await;
|
||||||
|
|
||||||
{
|
|
||||||
let mut no_ping_in = self.no_ping_in.lock().await;
|
|
||||||
*no_ping_in = -1;
|
*no_ping_in = -1;
|
||||||
|
let mut message_send_times = sel.message_send_times.lock().await;
|
||||||
|
message_send_times.remove(&cv.get_id());
|
||||||
|
|
||||||
|
if log {
|
||||||
|
APP_STATE.lock().unwrap().push_log("12.0".to_string());
|
||||||
|
APP_STATE.lock().unwrap().push_ping_val(12.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cancel(&self) {
|
pub async fn cancel(&self) {
|
||||||
// Cancel or stop the task
|
|
||||||
let mut no_ping_in = self.no_ping_in.lock().await;
|
let mut no_ping_in = self.no_ping_in.lock().await;
|
||||||
*no_ping_in = -1; // Reset the counter
|
*no_ping_in = -1;
|
||||||
|
|
||||||
// Example of stopping the ping task gracefully
|
|
||||||
// If using a task join handle or similar
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use json::{self, JsonValue};
|
use crate::util::file_util::save_file;
|
||||||
|
use json::{self, Array, JsonValue};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -7,8 +8,8 @@ pub struct UserCommunityUtil;
|
||||||
|
|
||||||
impl UserCommunityUtil {
|
impl UserCommunityUtil {
|
||||||
pub fn add_community(storage_owner: Uuid, address: String, title: String, position: String) {
|
pub fn add_community(storage_owner: Uuid, address: String, title: String, position: String) {
|
||||||
let path = format!("users/{}/communities.json", storage_owner);
|
let file_path = format!("users/{}/", storage_owner);
|
||||||
let mut communities: JsonValue = Self::load_array(&path);
|
let mut communities = Self::load_array(&file_path);
|
||||||
|
|
||||||
let mut community = JsonValue::new_object();
|
let mut community = JsonValue::new_object();
|
||||||
community["title"] = JsonValue::String(title);
|
community["title"] = JsonValue::String(title);
|
||||||
|
|
@ -16,44 +17,52 @@ impl UserCommunityUtil {
|
||||||
community["position"] = JsonValue::String(position);
|
community["position"] = JsonValue::String(position);
|
||||||
|
|
||||||
communities.push(community);
|
communities.push(community);
|
||||||
Self::save_array(&path, communities);
|
|
||||||
|
save_file(
|
||||||
|
&file_path,
|
||||||
|
"communities.json",
|
||||||
|
&JsonValue::Array(communities).to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_community(storage_owner: Uuid, community_address: String) {
|
pub fn remove_community(storage_owner: Uuid, community_address: String) {
|
||||||
let path = format!("users/{}/communities.json", storage_owner);
|
let file_path = format!("users/{}/", storage_owner);
|
||||||
let mut communities = Self::load_array(&path);
|
let communities = Self::load_array(&file_path);
|
||||||
|
|
||||||
let mut new_array = JsonValue::new_array();
|
let filtered: Array = communities
|
||||||
for entry in communities.members() {
|
.iter()
|
||||||
if entry["address"].as_str() != Some(&community_address) {
|
.filter(|entry| entry["address"].as_str() != Some(&community_address))
|
||||||
new_array.push(entry.clone()).unwrap();
|
.cloned()
|
||||||
}
|
.collect();
|
||||||
|
save_file(
|
||||||
|
&file_path,
|
||||||
|
"communities.json",
|
||||||
|
&JsonValue::Array(filtered).to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::save_array(&path, new_array);
|
pub fn get_communities(storage_owner: Uuid) -> Array {
|
||||||
|
let file_path = format!("users/{}/communities.json", storage_owner);
|
||||||
|
Self::load_array(&file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_communities(storage_owner: Uuid) -> JsonValue {
|
fn load_array(file_path: &str) -> Array {
|
||||||
let path = format!("users/{}/communities.json", storage_owner);
|
if !Path::new(file_path).exists() {
|
||||||
Self::load_array(&path)
|
return Array::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_array(path: &str) -> JsonValue {
|
match fs::read_to_string(file_path) {
|
||||||
if !Path::new(path).exists() {
|
Ok(content) => {
|
||||||
return JsonValue::new_object();
|
let parsed = json::parse(&content);
|
||||||
}
|
match parsed {
|
||||||
|
Ok(JsonValue::Array(arr)) => arr,
|
||||||
match fs::read_to_string(path) {
|
_ => Array::new(),
|
||||||
Ok(content) => json::parse(&content).unwrap_or_else(|_| JsonValue::new_object()),
|
|
||||||
Err(_) => JsonValue::new_object(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
fn save_array(path: &str, arr: JsonValue) {
|
eprintln!("Failed to read file {}: {}", file_path, err);
|
||||||
if let Some(parent) = Path::new(path).parent() {
|
Array::new()
|
||||||
let _ = fs::create_dir_all(parent);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = fs::write(path, arr.pretty(3));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::auth::auth_connector::AuthConnector;
|
use crate::auth::auth_connector::AuthConnector;
|
||||||
|
use crate::gui::log_panel::log_message;
|
||||||
use crate::users::user_manager::UserManager;
|
use crate::users::user_manager::UserManager;
|
||||||
use base64::{Engine as _, engine::general_purpose};
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
use json::{JsonValue, object, stringify};
|
use json::{JsonValue, object, stringify};
|
||||||
|
|
@ -72,15 +73,14 @@ impl UserProfile {
|
||||||
reset_token,
|
reset_token,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Migration hook (stubbed, since AuthConnector isn’t implemented here)
|
|
||||||
if j.has_key("migrate")
|
if j.has_key("migrate")
|
||||||
|| j.has_key("migrating")
|
|| j.has_key("migrating")
|
||||||
|| j.has_key("changing")
|
|| j.has_key("changing")
|
||||||
|| j.has_key("move")
|
|| j.has_key("move")
|
||||||
|| j.has_key("moving")
|
|| j.has_key("moving")
|
||||||
{
|
{
|
||||||
if AuthConnector::migrate_user(&mut up, stringify!("{}", Uuid::new_v4())).await {
|
if AuthConnector::migrate_user(&mut up).await {
|
||||||
println!("[INFO] Migration triggered for {}", up.username);
|
log_message(format!("[INFO] Migration triggered for {}", up.username));
|
||||||
UserManager::set_unique(true);
|
UserManager::set_unique(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,6 @@ impl UserProfile {
|
||||||
OsRng.fill(bytes.as_mut());
|
OsRng.fill(bytes.as_mut());
|
||||||
let new_token = general_purpose::STANDARD.encode(&bytes);
|
let new_token = general_purpose::STANDARD.encode(&bytes);
|
||||||
self.reset_token = new_token.clone();
|
self.reset_token = new_token.clone();
|
||||||
UserManager::save_users().ok();
|
|
||||||
new_token
|
new_token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ impl ChatFiles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_file(dir: &str, file_name: &str, content: &str) -> std::io::Result<()> {
|
fn save_file(dir: &str, file_name: &str, content: &str) {
|
||||||
fs::create_dir_all(dir)?;
|
fs::create_dir_all(dir);
|
||||||
let path = Path::new(dir).join(file_name);
|
let path = Path::new(dir).join(file_name);
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path).unwrap();
|
||||||
file.write_all(content.as_bytes())
|
file.write_all(content.as_bytes());
|
||||||
}
|
}
|
||||||
pub fn add_message(
|
pub fn add_message(
|
||||||
send_time: i64,
|
send_time: i64,
|
||||||
|
|
@ -49,10 +49,7 @@ impl ChatFiles {
|
||||||
storage_owner: Uuid,
|
storage_owner: Uuid,
|
||||||
external_user: Uuid,
|
external_user: Uuid,
|
||||||
message: &str,
|
message: &str,
|
||||||
avatar: bool,
|
) {
|
||||||
timestamp: bool,
|
|
||||||
tint: i64,
|
|
||||||
) -> std::io::Result<()> {
|
|
||||||
let user_dir = format!("users/{}/chats/{}", storage_owner, external_user);
|
let user_dir = format!("users/{}/chats/{}", storage_owner, external_user);
|
||||||
|
|
||||||
let mut chunk_index = 0;
|
let mut chunk_index = 0;
|
||||||
|
|
@ -88,7 +85,7 @@ impl ChatFiles {
|
||||||
&user_dir,
|
&user_dir,
|
||||||
&format!("msgs_{}.json", chunk_index),
|
&format!("msgs_{}.json", chunk_index),
|
||||||
&message_chunk.dump(),
|
&message_chunk.dump(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_message_state(
|
pub fn change_message_state(
|
||||||
|
|
@ -127,7 +124,7 @@ impl ChatFiles {
|
||||||
}
|
}
|
||||||
|
|
||||||
if modified {
|
if modified {
|
||||||
Self::save_file(&user_dir, &fname_str, &chunk.dump())?;
|
Self::save_file(&user_dir, &fname_str, &chunk.dump());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue