From 3cdf7c62d509fca970e30f35fb973c9d6b523e24 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:46:21 +0200 Subject: [PATCH 1/9] [Add] basic split --- Cargo.lock | 177 ++++++- Cargo.toml | 58 +-- decentralized/Cargo.toml | 56 ++ .../src}/communities/community.rs | 0 .../src}/communities/community_connection.rs | 0 .../src}/communities/community_manager.rs | 0 .../communities/interactables/category.rs | 0 .../communities/interactables/interactable.rs | 0 .../communities/interactables/registry.rs | 0 .../communities/interactables/text_chat.rs | 0 .../communities/interactables/voice_chat.rs | 0 {src => decentralized/src}/communities/mod.rs | 0 .../src}/communities/perms/permission.rs | 0 src/gui/tui.rs => decentralized/src/lib.rs | 0 .../src/local-auth}/auth_user.rs | 0 .../src/local-auth}/local_auth.rs | 0 .../src/local-auth}/mod.rs | 0 iota-cli/Cargo.toml | 57 ++ iota-cli/src/app_state.rs | 1 + .../src}/elements/console_card.rs | 0 .../gui => iota-cli/src}/elements/elements.rs | 0 .../src}/elements/graph_card.rs | 0 .../gui => iota-cli/src}/elements/log_card.rs | 0 {src/gui => iota-cli/src}/input_handler.rs | 2 +- .../src}/interaction_result.rs | 2 +- .../src}/langu/language_creator.rs | 0 .../src}/langu/language_manager.rs | 0 {src => iota-cli/src}/langu/mod.rs | 0 src/gui/mod.rs => iota-cli/src/lib.rs | 0 .../src}/screens/main_screen.rs | 2 +- .../gui => iota-cli/src}/screens/md_viewer.rs | 2 +- {src/gui => iota-cli/src}/screens/screens.rs | 2 +- .../src}/screens/terms_checker.rs | 14 +- .../src}/screens/terms_updater.rs | 13 +- iota-cli/src/tui.rs | 0 {src/gui => iota-cli/src}/ui.rs | 7 +- {src/gui => iota-cli/src}/util/borders.rs | 0 iota-core/Cargo.toml | 17 + {src => iota-core/src}/main.rs | 36 +- {src => iota-core/src}/terms/buttons.rs | 0 {src => iota-core/src}/terms/doc.rs | 0 {src => iota-core/src}/terms/focus.rs | 0 {src => iota-core/src}/terms/mod.rs | 1 - {src => iota-core/src}/terms/terms_getter.rs | 0 iota-logger/Cargo.toml | 6 + iota-logger/src/lib.rs | 14 + iota-state/Cargo.toml | 12 + src/gui/app_state.rs => iota-state/src/lib.rs | 77 +-- iota-storage/Cargo.toml | 27 + iota-storage/src/lib.rs | 2 + {src => iota-storage/src}/users/contact.rs | 0 {src => iota-storage/src}/users/mod.rs | 0 .../src}/users/user_community_util.rs | 0 .../src}/users/user_manager.rs | 0 .../src}/users/user_profile.rs | 0 {src => iota-storage/src}/util/chat_files.rs | 0 {src => iota-storage/src}/util/chats_util.rs | 0 .../src}/util/communities_util.rs | 0 {src => iota-storage/src}/util/config_util.rs | 0 .../src}/util/crypto_helper.rs | 0 {src => iota-storage/src}/util/crypto_util.rs | 0 {src => iota-storage/src}/util/db.rs | 0 {src => iota-storage/src}/util/file_util.rs | 0 {src => iota-storage/src}/util/logger.rs | 0 {src => iota-storage/src}/util/mod.rs | 0 omikron-connector/Cargo.toml | 13 + .../mod.rs => omikron-connector/src/lib.rs | 0 .../src}/omikron_connection.rs | 0 .../src}/ping_pong_task.rs | 0 src/terms/consent_state.rs | 491 ------------------ web-server/Cargo.toml | 9 + web-server/src/lib.rs | 0 web-ui/Cargo.toml | 56 ++ {src/server => web-ui/src}/api.rs | 0 src/server/mod.rs => web-ui/src/lib.rs | 0 {src/server => web-ui/src}/server.rs | 0 {src/server => web-ui/src}/web_path_parser.rs | 0 77 files changed, 506 insertions(+), 648 deletions(-) create mode 100644 decentralized/Cargo.toml rename {src => decentralized/src}/communities/community.rs (100%) rename {src => decentralized/src}/communities/community_connection.rs (100%) rename {src => decentralized/src}/communities/community_manager.rs (100%) rename {src => decentralized/src}/communities/interactables/category.rs (100%) rename {src => decentralized/src}/communities/interactables/interactable.rs (100%) rename {src => decentralized/src}/communities/interactables/registry.rs (100%) rename {src => decentralized/src}/communities/interactables/text_chat.rs (100%) rename {src => decentralized/src}/communities/interactables/voice_chat.rs (100%) rename {src => decentralized/src}/communities/mod.rs (100%) rename {src => decentralized/src}/communities/perms/permission.rs (100%) rename src/gui/tui.rs => decentralized/src/lib.rs (100%) rename {src/auth => decentralized/src/local-auth}/auth_user.rs (100%) rename {src/auth => decentralized/src/local-auth}/local_auth.rs (100%) rename {src/auth => decentralized/src/local-auth}/mod.rs (100%) create mode 100644 iota-cli/Cargo.toml create mode 100755 iota-cli/src/app_state.rs rename {src/gui => iota-cli/src}/elements/console_card.rs (100%) rename {src/gui => iota-cli/src}/elements/elements.rs (100%) rename {src/gui => iota-cli/src}/elements/graph_card.rs (100%) rename {src/gui => iota-cli/src}/elements/log_card.rs (100%) rename {src/gui => iota-cli/src}/input_handler.rs (98%) rename {src/gui => iota-cli/src}/interaction_result.rs (97%) rename {src => iota-cli/src}/langu/language_creator.rs (100%) rename {src => iota-cli/src}/langu/language_manager.rs (100%) rename {src => iota-cli/src}/langu/mod.rs (100%) rename src/gui/mod.rs => iota-cli/src/lib.rs (100%) rename {src/gui => iota-cli/src}/screens/main_screen.rs (99%) rename {src/gui => iota-cli/src}/screens/md_viewer.rs (99%) rename {src/gui => iota-cli/src}/screens/screens.rs (89%) rename {src/gui => iota-cli/src}/screens/terms_checker.rs (97%) rename {src/gui => iota-cli/src}/screens/terms_updater.rs (98%) create mode 100644 iota-cli/src/tui.rs rename {src/gui => iota-cli/src}/ui.rs (96%) rename {src/gui => iota-cli/src}/util/borders.rs (100%) create mode 100644 iota-core/Cargo.toml rename {src => iota-core/src}/main.rs (81%) rename {src => iota-core/src}/terms/buttons.rs (100%) rename {src => iota-core/src}/terms/doc.rs (100%) rename {src => iota-core/src}/terms/focus.rs (100%) rename {src => iota-core/src}/terms/mod.rs (74%) rename {src => iota-core/src}/terms/terms_getter.rs (100%) create mode 100644 iota-logger/Cargo.toml create mode 100644 iota-logger/src/lib.rs create mode 100644 iota-state/Cargo.toml rename src/gui/app_state.rs => iota-state/src/lib.rs (76%) mode change 100755 => 100644 create mode 100644 iota-storage/Cargo.toml create mode 100644 iota-storage/src/lib.rs rename {src => iota-storage/src}/users/contact.rs (100%) rename {src => iota-storage/src}/users/mod.rs (100%) rename {src => iota-storage/src}/users/user_community_util.rs (100%) rename {src => iota-storage/src}/users/user_manager.rs (100%) rename {src => iota-storage/src}/users/user_profile.rs (100%) rename {src => iota-storage/src}/util/chat_files.rs (100%) rename {src => iota-storage/src}/util/chats_util.rs (100%) rename {src => iota-storage/src}/util/communities_util.rs (100%) rename {src => iota-storage/src}/util/config_util.rs (100%) rename {src => iota-storage/src}/util/crypto_helper.rs (100%) rename {src => iota-storage/src}/util/crypto_util.rs (100%) rename {src => iota-storage/src}/util/db.rs (100%) rename {src => iota-storage/src}/util/file_util.rs (100%) rename {src => iota-storage/src}/util/logger.rs (100%) rename {src => iota-storage/src}/util/mod.rs (100%) create mode 100644 omikron-connector/Cargo.toml rename src/omikron/mod.rs => omikron-connector/src/lib.rs (100%) rename {src/omikron => omikron-connector/src}/omikron_connection.rs (100%) rename {src/omikron => omikron-connector/src}/ping_pong_task.rs (100%) delete mode 100644 src/terms/consent_state.rs create mode 100644 web-server/Cargo.toml create mode 100644 web-server/src/lib.rs create mode 100644 web-ui/Cargo.toml rename {src/server => web-ui/src}/api.rs (100%) rename src/server/mod.rs => web-ui/src/lib.rs (100%) rename {src/server => web-ui/src}/server.rs (100%) rename {src/server => web-ui/src}/web_path_parser.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index cd56dfb..334fe02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -847,6 +847,53 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "decentralized" +version = "0.1.0" +dependencies = [ + "actix-web", + "actix-web-actors", + "aes-gcm", + "async-trait", + "base64", + "chrono", + "crossterm", + "dashmap", + "futures", + "futures-util", + "hex", + "hkdf", + "hyper", + "hyper-util", + "json", + "lazy_static", + "once_cell", + "open", + "pnet", + "rand 0.8.5", + "rand_core 0.6.4", + "ratatui", + "reqwest", + "rusqlite", + "rustls", + "rustls-pemfile", + "serde_json", + "sha2", + "strum 0.27.2", + "strum_macros 0.27.2", + "sysinfo", + "tokio", + "tokio-tungstenite", + "ttp-core", + "ttp-native", + "tungstenite", + "uuid", + "walkdir", + "warp", + "x448", + "zip", +] + [[package]] name = "deflate64" version = "0.1.12" @@ -1028,9 +1075,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "a043dc74da1e37d6afe657061213aa6f425f855399a11d3463c6ecccc4dfda1f" [[package]] name = "fiat-crypto" @@ -1723,6 +1770,14 @@ dependencies = [ [[package]] name = "iota" version = "0.1.0" +dependencies = [ + "ttp-core", + "ttp-native", +] + +[[package]] +name = "iota-cli" +version = "0.1.0" dependencies = [ "actix-web", "actix-web-actors", @@ -1738,6 +1793,7 @@ dependencies = [ "hkdf", "hyper", "hyper-util", + "iota-state", "json", "lazy_static", "once_cell", @@ -1767,6 +1823,64 @@ dependencies = [ "zip", ] +[[package]] +name = "iota-core" +version = "0.1.0" +dependencies = [ + "dashmap", + "iota-state", + "json", + "once_cell", + "pnet", + "ratatui", + "reqwest", + "tokio", + "ttp-core", + "ttp-native", +] + +[[package]] +name = "iota-logger" +version = "0.1.0" + +[[package]] +name = "iota-state" +version = "0.1.0" +dependencies = [ + "dashmap", + "json", + "once_cell", + "sysinfo", + "tokio", + "ttp-core", +] + +[[package]] +name = "iota-storage" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "base64", + "hex", + "hkdf", + "json", + "once_cell", + "rand 0.8.5", + "rand_core 0.6.4", + "ratatui", + "reqwest", + "rusqlite", + "sha2", + "sysinfo", + "tokio", + "ttp-core", + "ttp-native", + "uuid", + "walkdir", + "x448", + "zip", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -2257,6 +2371,18 @@ dependencies = [ "asn1-rs", ] +[[package]] +name = "omikron-connector" +version = "0.1.0" +dependencies = [ + "dashmap", + "json", + "tokio", + "ttp-core", + "ttp-native", + "uuid", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -4224,6 +4350,53 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-ui" +version = "0.1.0" +dependencies = [ + "actix-web", + "actix-web-actors", + "aes-gcm", + "async-trait", + "base64", + "chrono", + "crossterm", + "dashmap", + "futures", + "futures-util", + "hex", + "hkdf", + "hyper", + "hyper-util", + "json", + "lazy_static", + "once_cell", + "open", + "pnet", + "rand 0.8.5", + "rand_core 0.6.4", + "ratatui", + "reqwest", + "rusqlite", + "rustls", + "rustls-pemfile", + "serde_json", + "sha2", + "strum 0.27.2", + "strum_macros 0.27.2", + "sysinfo", + "tokio", + "tokio-tungstenite", + "ttp-core", + "ttp-native", + "tungstenite", + "uuid", + "walkdir", + "warp", + "x448", + "zip", +] + [[package]] name = "webpki-root-certs" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index 8767b56..7d4ef81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,56 +1,2 @@ -[package] -name = "iota" -version = "0.1.0" -edition = "2024" - -[dependencies] -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } - -actix-web = { version = "4", features = ["rustls-0_23"] } -actix-web-actors = "4" -aes-gcm = "0.10.3" -base64 = "0.22.1" -crossterm = "*" -futures = "*" -futures-util = "*" -hex = "*" -hkdf = "0.12.4" -hyper-util = { version = "*" } -hyper = { version = "1.8.1", features = [ - "capi", - "client", - "full", - "http1", - "http2", - "nightly", - "server", -] } -json = "*" -once_cell = "1.21.3" -rand = "0.8" -rand_core = { version = "0.6", features = ["getrandom", "std"] } -reqwest = "0.13.2" -rustls = { version = "0.23.37", features = ["aws-lc-rs"] } -sha2 = "0.10.9" -sysinfo = "0.38.3" -tokio = { version = "1.50.0", features = ["full"] } -tokio-tungstenite = { version = "*", features = ["native-tls"] } -tungstenite = "*" -uuid = { version = "*", features = ["v4"] } -walkdir = "2.5.0" -warp = "*" -x448 = { version = "*" } -rustls-pemfile = "2.2.0" -async-trait = "0.1.89" -zip = "6.0.0" -pnet = "0.35.0" -dashmap = "6.1.0" -strum = "0.27.2" -strum_macros = "0.27.2" -ratatui = "0.30.0" -open = "5.3.3" -chrono = "0.4.43" -serde_json = "1.0.149" -rusqlite = "0.39.0" -lazy_static = "1.5.0" +[workspace] +members = ["iota-storage", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "decentralized", "iota-logger"] diff --git a/decentralized/Cargo.toml b/decentralized/Cargo.toml new file mode 100644 index 0000000..9c21cdf --- /dev/null +++ b/decentralized/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "decentralized" +version = "0.1.0" +edition = "2024" + +[dependencies] +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +actix-web = { version = "4", features = ["rustls-0_23"] } +actix-web-actors = "4" +aes-gcm = "0.10.3" +async-trait = "0.1.89" +base64 = "0.22.1" +chrono = "0.4.43" +crossterm = "*" +dashmap = "6.1.0" +futures = "*" +futures-util = "*" +hex = "*" +hkdf = "0.12.4" +hyper = { version = "1.8.1", features = [ + "capi", + "client", + "full", + "http1", + "http2", + "nightly", + "server", +] } +hyper-util = { version = "*" } +json = "*" +lazy_static = "1.5.0" +once_cell = "1.21.3" +open = "5.3.3" +pnet = "0.35.0" +rand = "0.8" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +ratatui = "0.30.0" +reqwest = "0.13.2" +rusqlite = "0.39.0" +rustls = { version = "0.23.37", features = ["aws-lc-rs"] } +rustls-pemfile = "2.2.0" +serde_json = "1.0.149" +sha2 = "0.10.9" +strum = "0.27.2" +strum_macros = "0.27.2" +sysinfo = "0.38.3" +tokio = { version = "1.50.0", features = ["full"] } +tokio-tungstenite = { version = "*", features = ["native-tls"] } +tungstenite = "*" +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +warp = "*" +x448 = { version = "*" } +zip = "6.0.0" diff --git a/src/communities/community.rs b/decentralized/src/communities/community.rs similarity index 100% rename from src/communities/community.rs rename to decentralized/src/communities/community.rs diff --git a/src/communities/community_connection.rs b/decentralized/src/communities/community_connection.rs similarity index 100% rename from src/communities/community_connection.rs rename to decentralized/src/communities/community_connection.rs diff --git a/src/communities/community_manager.rs b/decentralized/src/communities/community_manager.rs similarity index 100% rename from src/communities/community_manager.rs rename to decentralized/src/communities/community_manager.rs diff --git a/src/communities/interactables/category.rs b/decentralized/src/communities/interactables/category.rs similarity index 100% rename from src/communities/interactables/category.rs rename to decentralized/src/communities/interactables/category.rs diff --git a/src/communities/interactables/interactable.rs b/decentralized/src/communities/interactables/interactable.rs similarity index 100% rename from src/communities/interactables/interactable.rs rename to decentralized/src/communities/interactables/interactable.rs diff --git a/src/communities/interactables/registry.rs b/decentralized/src/communities/interactables/registry.rs similarity index 100% rename from src/communities/interactables/registry.rs rename to decentralized/src/communities/interactables/registry.rs diff --git a/src/communities/interactables/text_chat.rs b/decentralized/src/communities/interactables/text_chat.rs similarity index 100% rename from src/communities/interactables/text_chat.rs rename to decentralized/src/communities/interactables/text_chat.rs diff --git a/src/communities/interactables/voice_chat.rs b/decentralized/src/communities/interactables/voice_chat.rs similarity index 100% rename from src/communities/interactables/voice_chat.rs rename to decentralized/src/communities/interactables/voice_chat.rs diff --git a/src/communities/mod.rs b/decentralized/src/communities/mod.rs similarity index 100% rename from src/communities/mod.rs rename to decentralized/src/communities/mod.rs diff --git a/src/communities/perms/permission.rs b/decentralized/src/communities/perms/permission.rs similarity index 100% rename from src/communities/perms/permission.rs rename to decentralized/src/communities/perms/permission.rs diff --git a/src/gui/tui.rs b/decentralized/src/lib.rs similarity index 100% rename from src/gui/tui.rs rename to decentralized/src/lib.rs diff --git a/src/auth/auth_user.rs b/decentralized/src/local-auth/auth_user.rs similarity index 100% rename from src/auth/auth_user.rs rename to decentralized/src/local-auth/auth_user.rs diff --git a/src/auth/local_auth.rs b/decentralized/src/local-auth/local_auth.rs similarity index 100% rename from src/auth/local_auth.rs rename to decentralized/src/local-auth/local_auth.rs diff --git a/src/auth/mod.rs b/decentralized/src/local-auth/mod.rs similarity index 100% rename from src/auth/mod.rs rename to decentralized/src/local-auth/mod.rs diff --git a/iota-cli/Cargo.toml b/iota-cli/Cargo.toml new file mode 100644 index 0000000..029e7e0 --- /dev/null +++ b/iota-cli/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "iota-cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +iota-state = { path = "../iota-state" } +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +actix-web = { version = "4", features = ["rustls-0_23"] } +actix-web-actors = "4" +aes-gcm = "0.10.3" +async-trait = "0.1.89" +base64 = "0.22.1" +chrono = "0.4.43" +crossterm = "*" +dashmap = "6.1.0" +futures = "*" +futures-util = "*" +hex = "*" +hkdf = "0.12.4" +hyper = { version = "1.8.1", features = [ + "capi", + "client", + "full", + "http1", + "http2", + "nightly", + "server", +] } +hyper-util = { version = "*" } +json = "*" +lazy_static = "1.5.0" +once_cell = "1.21.3" +open = "5.3.3" +pnet = "0.35.0" +rand = "0.8" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +ratatui = "0.30.0" +reqwest = "0.13.2" +rusqlite = "0.39.0" +rustls = { version = "0.23.37", features = ["aws-lc-rs"] } +rustls-pemfile = "2.2.0" +serde_json = "1.0.149" +sha2 = "0.10.9" +strum = "0.27.2" +strum_macros = "0.27.2" +sysinfo = "0.38.3" +tokio = { version = "1.50.0", features = ["full"] } +tokio-tungstenite = { version = "*", features = ["native-tls"] } +tungstenite = "*" +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +warp = "*" +x448 = { version = "*" } +zip = "6.0.0" diff --git a/iota-cli/src/app_state.rs b/iota-cli/src/app_state.rs new file mode 100755 index 0000000..cfb4b3b --- /dev/null +++ b/iota-cli/src/app_state.rs @@ -0,0 +1 @@ +pub use iota_state::*; diff --git a/src/gui/elements/console_card.rs b/iota-cli/src/elements/console_card.rs similarity index 100% rename from src/gui/elements/console_card.rs rename to iota-cli/src/elements/console_card.rs diff --git a/src/gui/elements/elements.rs b/iota-cli/src/elements/elements.rs similarity index 100% rename from src/gui/elements/elements.rs rename to iota-cli/src/elements/elements.rs diff --git a/src/gui/elements/graph_card.rs b/iota-cli/src/elements/graph_card.rs similarity index 100% rename from src/gui/elements/graph_card.rs rename to iota-cli/src/elements/graph_card.rs diff --git a/src/gui/elements/log_card.rs b/iota-cli/src/elements/log_card.rs similarity index 100% rename from src/gui/elements/log_card.rs rename to iota-cli/src/elements/log_card.rs diff --git a/src/gui/input_handler.rs b/iota-cli/src/input_handler.rs similarity index 98% rename from src/gui/input_handler.rs rename to iota-cli/src/input_handler.rs index b2557c5..92b899c 100644 --- a/src/gui/input_handler.rs +++ b/iota-cli/src/input_handler.rs @@ -1,4 +1,4 @@ -use crate::gui::ui::{UI, UNIQUE}; +use crate::ui::{UI, UNIQUE}; use crate::{RELOAD, SHUTDOWN}; use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyModifiers, poll, read}; use std::sync::Arc; diff --git a/src/gui/interaction_result.rs b/iota-cli/src/interaction_result.rs similarity index 97% rename from src/gui/interaction_result.rs rename to iota-cli/src/interaction_result.rs index 462149a..f9ba7e0 100644 --- a/src/gui/interaction_result.rs +++ b/iota-cli/src/interaction_result.rs @@ -2,7 +2,7 @@ use std::fmt::{Debug, Formatter}; use std::future::Future; use std::pin::Pin; -use crate::gui::screens::screens::Screen; +use crate::screens::screens::Screen; #[allow(unused)] pub enum InteractionResult { diff --git a/src/langu/language_creator.rs b/iota-cli/src/langu/language_creator.rs similarity index 100% rename from src/langu/language_creator.rs rename to iota-cli/src/langu/language_creator.rs diff --git a/src/langu/language_manager.rs b/iota-cli/src/langu/language_manager.rs similarity index 100% rename from src/langu/language_manager.rs rename to iota-cli/src/langu/language_manager.rs diff --git a/src/langu/mod.rs b/iota-cli/src/langu/mod.rs similarity index 100% rename from src/langu/mod.rs rename to iota-cli/src/langu/mod.rs diff --git a/src/gui/mod.rs b/iota-cli/src/lib.rs similarity index 100% rename from src/gui/mod.rs rename to iota-cli/src/lib.rs diff --git a/src/gui/screens/main_screen.rs b/iota-cli/src/screens/main_screen.rs similarity index 99% rename from src/gui/screens/main_screen.rs rename to iota-cli/src/screens/main_screen.rs index 85dbbaa..e10947d 100644 --- a/src/gui/screens/main_screen.rs +++ b/iota-cli/src/screens/main_screen.rs @@ -1,4 +1,4 @@ -use crate::gui::{ +use crate::{ elements::{ console_card::ConsoleCard, elements::{InteractableElement, JoinableElement}, diff --git a/src/gui/screens/md_viewer.rs b/iota-cli/src/screens/md_viewer.rs similarity index 99% rename from src/gui/screens/md_viewer.rs rename to iota-cli/src/screens/md_viewer.rs index 10eabce..2faa2f1 100644 --- a/src/gui/screens/md_viewer.rs +++ b/iota-cli/src/screens/md_viewer.rs @@ -7,7 +7,7 @@ use ratatui::{ }; use std::{any::Any, time::Duration}; -use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen}; +use crate::{interaction_result::InteractionResult, screens::screens::Screen}; pub struct FileViewer { title: String, diff --git a/src/gui/screens/screens.rs b/iota-cli/src/screens/screens.rs similarity index 89% rename from src/gui/screens/screens.rs rename to iota-cli/src/screens/screens.rs index 9676fbb..7606521 100644 --- a/src/gui/screens/screens.rs +++ b/iota-cli/src/screens/screens.rs @@ -3,7 +3,7 @@ use std::any::Any; use crossterm::event::KeyEvent; use ratatui::{Frame, layout::Rect}; -use crate::gui::interaction_result::InteractionResult; +use crate::interaction_result::InteractionResult; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NavDirection { diff --git a/src/gui/screens/terms_checker.rs b/iota-cli/src/screens/terms_checker.rs similarity index 97% rename from src/gui/screens/terms_checker.rs rename to iota-cli/src/screens/terms_checker.rs index 26bb7c6..0808ac5 100644 --- a/src/gui/screens/terms_checker.rs +++ b/iota-cli/src/screens/terms_checker.rs @@ -1,15 +1,7 @@ use crate::{ - gui::{ - interaction_result::InteractionResult, - screens::{md_viewer::FileViewer, screens::Screen}, - ui::UI, - }, - terms::{ - buttons::{checkbox, draw_buttons}, - consent_state::UserChoice, - focus::Focus, - terms_getter::{Type, get_link, get_terms}, - }, + interaction_result::InteractionResult, + screens::{md_viewer::FileViewer, screens::Screen}, + ui::UI, }; use crossterm::event::{KeyCode, KeyEvent}; use ratatui::{ diff --git a/src/gui/screens/terms_updater.rs b/iota-cli/src/screens/terms_updater.rs similarity index 98% rename from src/gui/screens/terms_updater.rs rename to iota-cli/src/screens/terms_updater.rs index 35da364..909da8d 100644 --- a/src/gui/screens/terms_updater.rs +++ b/iota-cli/src/screens/terms_updater.rs @@ -1,15 +1,6 @@ use crate::{ - gui::{ - interaction_result::InteractionResult, - screens::{md_viewer::FileViewer, screens::Screen}, - }, - terms::{ - buttons::{checkbox, draw_buttons}, - consent_state::{UpdateDecision, UserChoice}, - doc::Doc, - focus::Focus, - terms_getter::{Type, get_newest_link, get_terms}, - }, + interaction_result::InteractionResult, + screens::{md_viewer::FileViewer, screens::Screen}, }; use chrono::{Local, TimeZone, Utc}; use crossterm::event::{KeyCode, KeyEvent}; diff --git a/iota-cli/src/tui.rs b/iota-cli/src/tui.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/gui/ui.rs b/iota-cli/src/ui.rs similarity index 96% rename from src/gui/ui.rs rename to iota-cli/src/ui.rs index 5903a4b..71e9847 100644 --- a/src/gui/ui.rs +++ b/iota-cli/src/ui.rs @@ -1,9 +1,6 @@ use crate::{ - ACTIVE_TASKS, SHUTDOWN, - gui::{ - input_handler::setup_input_handler, interaction_result::InteractionResult, - screens::screens::Screen, - }, + input_handler::setup_input_handler, interaction_result::InteractionResult, + screens::screens::Screen, }; use crossterm::event::KeyEvent; use once_cell::sync::Lazy; diff --git a/src/gui/util/borders.rs b/iota-cli/src/util/borders.rs similarity index 100% rename from src/gui/util/borders.rs rename to iota-cli/src/util/borders.rs diff --git a/iota-core/Cargo.toml b/iota-core/Cargo.toml new file mode 100644 index 0000000..7db34a2 --- /dev/null +++ b/iota-core/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "iota-core" +version = "0.1.0" +edition = "2024" + +[dependencies] +iota-state = { path = "../iota-state" } +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +dashmap = "6.1.0" +json = "*" +once_cell = "1.21.3" +pnet = "0.35.0" +ratatui = "0.30.0" +reqwest = "0.13.2" +tokio = { version = "1.50.0", features = ["full"] } diff --git a/src/main.rs b/iota-core/src/main.rs similarity index 81% rename from src/main.rs rename to iota-core/src/main.rs index 767106f..f8f4847 100644 --- a/src/main.rs +++ b/iota-core/src/main.rs @@ -1,39 +1,7 @@ -use dashmap::DashSet; -use once_cell::sync::Lazy; use pnet::datalink::NetworkInterface; -use std::sync::Arc; -use std::sync::LazyLock; -use std::sync::Mutex; -use tokio::sync::RwLock; use tokio::time::{Duration, sleep}; -mod auth; -mod gui; -mod langu; -mod omikron; -mod terms; -mod users; -mod util; - -use crate::gui::app_state; -use crate::gui::app_state::AppState; -use crate::gui::screens::main_screen::MainScreen; -use crate::gui::ui::start_tui; -use crate::langu::language_creator; -use crate::omikron::omikron_connection::OmikronConnection; -use crate::terms::consent_state; -use crate::users::user_manager; -use crate::util::config_util::CONFIG; -use crate::util::file_util::download_and_extract_zip; -use crate::util::file_util::has_dir; -use crate::util::logger; - -pub static APP_STATE: LazyLock>> = - LazyLock::new(|| Arc::new(Mutex::new(AppState::new()))); - -pub static SHUTDOWN: Lazy> = Lazy::new(|| RwLock::new(false)); -pub static RELOAD: Lazy> = Lazy::new(|| RwLock::new(true)); -pub static ACTIVE_TASKS: Lazy> = Lazy::new(|| DashSet::new()); +use iota_state::{ACTIVE_TASKS, APP_STATE, AppState, RELOAD, SHUTDOWN}; #[tokio::main(flavor = "multi_thread", worker_threads = 16)] #[allow(unused_must_use, dead_code)] @@ -73,7 +41,7 @@ async fn main() { println!("You can find this at 'agreements'!"); return; } - app_state::setup(); + iota_state::setup(); let main_screen = MainScreen::new(ui.clone()).await; ui.set_screen(Box::new(main_screen)).await; diff --git a/src/terms/buttons.rs b/iota-core/src/terms/buttons.rs similarity index 100% rename from src/terms/buttons.rs rename to iota-core/src/terms/buttons.rs diff --git a/src/terms/doc.rs b/iota-core/src/terms/doc.rs similarity index 100% rename from src/terms/doc.rs rename to iota-core/src/terms/doc.rs diff --git a/src/terms/focus.rs b/iota-core/src/terms/focus.rs similarity index 100% rename from src/terms/focus.rs rename to iota-core/src/terms/focus.rs diff --git a/src/terms/mod.rs b/iota-core/src/terms/mod.rs similarity index 74% rename from src/terms/mod.rs rename to iota-core/src/terms/mod.rs index 4a11008..947fc13 100644 --- a/src/terms/mod.rs +++ b/iota-core/src/terms/mod.rs @@ -1,5 +1,4 @@ pub mod buttons; -pub mod consent_state; pub mod doc; pub mod focus; pub mod terms_getter; diff --git a/src/terms/terms_getter.rs b/iota-core/src/terms/terms_getter.rs similarity index 100% rename from src/terms/terms_getter.rs rename to iota-core/src/terms/terms_getter.rs diff --git a/iota-logger/Cargo.toml b/iota-logger/Cargo.toml new file mode 100644 index 0000000..a07b745 --- /dev/null +++ b/iota-logger/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "iota-logger" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/iota-logger/src/lib.rs b/iota-logger/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/iota-logger/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/iota-state/Cargo.toml b/iota-state/Cargo.toml new file mode 100644 index 0000000..eff1cb7 --- /dev/null +++ b/iota-state/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "iota-state" +version = "0.1.0" +edition = "2024" + +[dependencies] +dashmap = "6.1.0" +once_cell = "1.21.3" +tokio = { version = "1.50.0", features = ["full"] } +json = "*" +sysinfo = "0.38.3" +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } diff --git a/src/gui/app_state.rs b/iota-state/src/lib.rs old mode 100755 new mode 100644 similarity index 76% rename from src/gui/app_state.rs rename to iota-state/src/lib.rs index a161226..5d8d351 --- a/src/gui/app_state.rs +++ b/iota-state/src/lib.rs @@ -1,7 +1,33 @@ -use crate::{ACTIVE_TASKS, APP_STATE, SHUTDOWN, gui::elements::log_card::UiLogEntry}; +use dashmap::DashSet; use json::{JsonValue, object}; -use std::{collections::VecDeque, thread, time::Duration}; +use once_cell::sync::Lazy; +use std::collections::VecDeque; +use std::sync::{Arc, LazyLock, Mutex}; +use std::thread; +use std::time::Duration; use sysinfo::{RefreshKind, System}; +use tokio::sync::RwLock; + +pub const MAX_POINTS: usize = 1000; +pub const MAX_LOGS: usize = 100; + +#[derive(Clone, Debug)] +pub struct UiLogEntry { + pub timestamp_ms: u128, + pub sender: String, + pub message: String, + pub is_error: bool, +} + +impl UiLogEntry { + pub fn format_timestamp(&self) -> String { + let secs = (self.timestamp_ms / 1000) as i64; + let hours = (secs / 3600) % 24; + let minutes = (secs / 60) % 60; + let seconds = secs % 60; + format!("{:02}:{:02}:{:02}", hours, minutes, seconds) + } +} #[derive(Clone)] pub struct AppState { @@ -13,8 +39,6 @@ pub struct AppState { pub net_down: Vec<(f64, f64)>, pub sys_info: String, } -const MAX_POINTS: usize = 1000; -const MAX_LOGS: usize = 100; impl AppState { pub fn new() -> Self { @@ -74,34 +98,17 @@ impl AppState { self.net_down.remove(0); } } + pub fn to_json(&self) -> JsonValue { - let json = object! { - "cpu" => self.cpu - .iter() - .map(|(_, y)| *y) - .collect::>(), - "ram" => self.ram - .iter() - .map(|(_, y)| *y) - .collect::>(), - "ping" => self - .ping - .iter() - .map(|(_, y)| *y) - .collect::>(), - "net_up" => self - .net_up - .iter() - .map(|(_, y)| *y) - .collect::>(), - "net_down" => self - .net_down - .iter() - .map(|(_, y)| *y) - .collect::>(), - }; - json + object! { + "cpu" => self.cpu.iter().map(|(_, y)| *y).collect::>(), + "ram" => self.ram.iter().map(|(_, y)| *y).collect::>(), + "ping" => self.ping.iter().map(|(_, y)| *y).collect::>(), + "net_up" => self.net_up.iter().map(|(_, y)| *y).collect::>(), + "net_down" => self.net_down.iter().map(|(_, y)| *y).collect::>(), + } } + pub fn with_width(&self, width: u16) -> Self { let mut new = self.clone(); new.cpu = Self::downsample_to_fit_width(&new.cpu, width); @@ -128,10 +135,9 @@ impl AppState { .first() .map(|(x, _)| x - (dx * pad_len as f64)) .unwrap_or(0.0); - let _ = data.first().map(|(_, y)| *y).unwrap_or(0.0); for i in 0..pad_len { - result.push((start_x + i as f64 * dx, -1 as f64)); + result.push((start_x + i as f64 * dx, -1.0)); } result.extend_from_slice(data); @@ -140,6 +146,13 @@ impl AppState { } } +pub static APP_STATE: LazyLock>> = + LazyLock::new(|| Arc::new(Mutex::new(AppState::new()))); + +pub static SHUTDOWN: Lazy> = Lazy::new(|| RwLock::new(false)); +pub static RELOAD: Lazy> = Lazy::new(|| RwLock::new(true)); +pub static ACTIVE_TASKS: Lazy> = Lazy::new(|| DashSet::new()); + pub fn setup() { ACTIVE_TASKS.insert("System info loader".to_string()); tokio::spawn(async move { diff --git a/iota-storage/Cargo.toml b/iota-storage/Cargo.toml new file mode 100644 index 0000000..b62ac11 --- /dev/null +++ b/iota-storage/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "iota-storage" +version = "0.1.0" +edition = "2024" + +[dependencies] +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +aes-gcm = "0.10.3" +base64 = "0.22.1" +hex = "*" +hkdf = "0.12.4" +json = "*" +once_cell = "1.21.3" +rand = "0.8" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +ratatui = "0.30.0" +reqwest = "0.13.2" +rusqlite = "0.39.0" +sha2 = "0.10.9" +sysinfo = "0.38.3" +tokio = { version = "1.50.0", features = ["full"] } +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +x448 = { version = "*" } +zip = "6.0.0" diff --git a/iota-storage/src/lib.rs b/iota-storage/src/lib.rs new file mode 100644 index 0000000..778de0f --- /dev/null +++ b/iota-storage/src/lib.rs @@ -0,0 +1,2 @@ +mod users; +mod util; diff --git a/src/users/contact.rs b/iota-storage/src/users/contact.rs similarity index 100% rename from src/users/contact.rs rename to iota-storage/src/users/contact.rs diff --git a/src/users/mod.rs b/iota-storage/src/users/mod.rs similarity index 100% rename from src/users/mod.rs rename to iota-storage/src/users/mod.rs diff --git a/src/users/user_community_util.rs b/iota-storage/src/users/user_community_util.rs similarity index 100% rename from src/users/user_community_util.rs rename to iota-storage/src/users/user_community_util.rs diff --git a/src/users/user_manager.rs b/iota-storage/src/users/user_manager.rs similarity index 100% rename from src/users/user_manager.rs rename to iota-storage/src/users/user_manager.rs diff --git a/src/users/user_profile.rs b/iota-storage/src/users/user_profile.rs similarity index 100% rename from src/users/user_profile.rs rename to iota-storage/src/users/user_profile.rs diff --git a/src/util/chat_files.rs b/iota-storage/src/util/chat_files.rs similarity index 100% rename from src/util/chat_files.rs rename to iota-storage/src/util/chat_files.rs diff --git a/src/util/chats_util.rs b/iota-storage/src/util/chats_util.rs similarity index 100% rename from src/util/chats_util.rs rename to iota-storage/src/util/chats_util.rs diff --git a/src/util/communities_util.rs b/iota-storage/src/util/communities_util.rs similarity index 100% rename from src/util/communities_util.rs rename to iota-storage/src/util/communities_util.rs diff --git a/src/util/config_util.rs b/iota-storage/src/util/config_util.rs similarity index 100% rename from src/util/config_util.rs rename to iota-storage/src/util/config_util.rs diff --git a/src/util/crypto_helper.rs b/iota-storage/src/util/crypto_helper.rs similarity index 100% rename from src/util/crypto_helper.rs rename to iota-storage/src/util/crypto_helper.rs diff --git a/src/util/crypto_util.rs b/iota-storage/src/util/crypto_util.rs similarity index 100% rename from src/util/crypto_util.rs rename to iota-storage/src/util/crypto_util.rs diff --git a/src/util/db.rs b/iota-storage/src/util/db.rs similarity index 100% rename from src/util/db.rs rename to iota-storage/src/util/db.rs diff --git a/src/util/file_util.rs b/iota-storage/src/util/file_util.rs similarity index 100% rename from src/util/file_util.rs rename to iota-storage/src/util/file_util.rs diff --git a/src/util/logger.rs b/iota-storage/src/util/logger.rs similarity index 100% rename from src/util/logger.rs rename to iota-storage/src/util/logger.rs diff --git a/src/util/mod.rs b/iota-storage/src/util/mod.rs similarity index 100% rename from src/util/mod.rs rename to iota-storage/src/util/mod.rs diff --git a/omikron-connector/Cargo.toml b/omikron-connector/Cargo.toml new file mode 100644 index 0000000..89aa2d4 --- /dev/null +++ b/omikron-connector/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "omikron-connector" +version = "0.1.0" +edition = "2024" + +[dependencies] +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +dashmap = "6.1.0" +json = "*" +tokio = { version = "1.50.0", features = ["full"] } +uuid = { version = "*", features = ["v4"] } diff --git a/src/omikron/mod.rs b/omikron-connector/src/lib.rs similarity index 100% rename from src/omikron/mod.rs rename to omikron-connector/src/lib.rs diff --git a/src/omikron/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs similarity index 100% rename from src/omikron/omikron_connection.rs rename to omikron-connector/src/omikron_connection.rs diff --git a/src/omikron/ping_pong_task.rs b/omikron-connector/src/ping_pong_task.rs similarity index 100% rename from src/omikron/ping_pong_task.rs rename to omikron-connector/src/ping_pong_task.rs diff --git a/src/terms/consent_state.rs b/src/terms/consent_state.rs deleted file mode 100644 index 1cc6e0a..0000000 --- a/src/terms/consent_state.rs +++ /dev/null @@ -1,491 +0,0 @@ -use tokio::sync::oneshot; - -use crate::{ - gui::{ - screens::{terms_checker::TermsCheckerScreen, terms_updater::TermsUpdaterScreen}, - ui::UI, - }, - terms::{ - doc::Doc, - terms_getter::{Type, get_current_docs, get_newest_docs}, - }, - util::file_util::{load_file, save_file}, -}; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; - -pub async fn check(ui: Arc) -> (bool, bool) { - let mut state = ConsentState::load_state(); - - if ensure_initial_consent(ui.clone(), &mut state) - .await - .is_err() - { - return (false, false); - } - if ensure_updates(ui, &mut state).await.is_err() { - return (false, false); - }; - - state = state.sanitize(); - state.save_state(); - - (state.accepted_eula, state.accepted_tos && state.accepted_pp) -} - -async fn ensure_initial_consent(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { - if state.accepted_eula { - return Ok(()); - } - - let (tx, rx) = oneshot::channel(); - - ui.set_screen(Box::new(TermsCheckerScreen::new(ui.clone(), Some(tx)))) - .await; - - let result = rx.await.unwrap_or(UserChoice::Deny); - - match result { - UserChoice::AcceptEULA | UserChoice::AcceptAll => { - if let Some((eula, tos, privacy)) = get_current_docs().await { - state.accepted_eula = true; - state.eula = Some(eula); - - if matches!(result, UserChoice::AcceptAll) { - state.accepted_tos = true; - state.accepted_pp = true; - state.tos = Some(tos); - state.privacy = Some(privacy); - } - } - - let _ = &state.save_state(); - Ok(()) - } - UserChoice::Deny => Err(()), - } -} -async fn ensure_updates(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { - let Some((eula_update, tos_update, privacy_update)) = get_updates().await else { - return Ok(()); - }; - - let is_forced = matches!(eula_update, UpdateDecision::Forced(_)) - || matches!(tos_update, UpdateDecision::Forced(_)) - || matches!(privacy_update, UpdateDecision::Forced(_)); - - let (tx, rx) = oneshot::channel(); - - ui.set_screen(Box::new(TermsUpdaterScreen::new( - eula_update.clone(), - tos_update.clone(), - privacy_update.clone(), - Some(tx), - ))) - .await; - - let result = rx.await.unwrap_or(UserChoice::Deny); - - if is_forced { - match result { - UserChoice::AcceptAll => { - state.accepted_eula = true; - state.accepted_tos = true; - state.accepted_pp = true; - } - UserChoice::AcceptEULA => { - state.accepted_eula = true; - } - UserChoice::Deny => return Err(()), - } - } else { - apply_future_updates(state, result, eula_update, tos_update, privacy_update); - } - - state.save_state(); - Ok(()) -} -fn apply_future_updates( - state: &mut ConsentState, - result: UserChoice, - eula_update: UpdateDecision, - tos_update: UpdateDecision, - privacy_update: UpdateDecision, -) { - match result { - UserChoice::AcceptAll => { - if let UpdateDecision::Future { newest } = eula_update { - state.future_eula = Some(newest); - } - if let UpdateDecision::Future { newest } = tos_update { - state.future_tos = Some(newest); - } - if let UpdateDecision::Future { newest } = privacy_update { - state.future_privacy = Some(newest); - } - } - UserChoice::AcceptEULA => { - if let UpdateDecision::Future { newest } = eula_update { - state.future_eula = Some(newest); - } - } - UserChoice::Deny => {} - } -} - -async fn get_updates() -> Option<( - // Ok(None) indicates no update - // Ok(Some) Indicates a future update - // Err indicates a update that has to be accepted before the programm can continue - UpdateDecision, - UpdateDecision, - UpdateDecision, -)> { - if let ( - Some((current_eula, current_tos, current_privacy)), - Some((newest_eula, newest_tos, newest_privacy)), - ) = (get_current_docs().await, get_newest_docs().await) - { - let file = load_file("", "agreements"); - let accepted_state = ConsentState::from_str(&file).sanitize(); - save_file("", "agreements", &accepted_state.to_string()); - - let eula_update: UpdateDecision = if current_eula.equals_some(&accepted_state.eula) { - if current_eula.equals(&newest_eula) { - UpdateDecision::NoChange - } else { - if newest_eula.equals_some(&accepted_state.future_eula) { - UpdateDecision::NoChange - } else { - UpdateDecision::Future { - newest: newest_eula, - } - } - } - } else if newest_eula.equals_some(&accepted_state.eula) { - UpdateDecision::NoChange - } else { - UpdateDecision::Forced(current_eula) - }; - - let tos_update: UpdateDecision = - if !accepted_state.accepted_tos || newest_tos.equals_some(&accepted_state.tos) { - UpdateDecision::NoChange - } else if accepted_state.accepted_tos && current_tos.equals_some(&accepted_state.tos) { - if current_tos.equals(&newest_tos) { - UpdateDecision::NoChange - } else { - if newest_tos.equals_some(&accepted_state.future_tos) { - UpdateDecision::NoChange - } else { - UpdateDecision::Future { newest: newest_tos } - } - } - } else { - UpdateDecision::Forced(current_tos) - }; - - let privacy_update: UpdateDecision = if !accepted_state.accepted_pp - || newest_privacy.equals_some(&accepted_state.privacy) - { - UpdateDecision::NoChange - } else if accepted_state.accepted_pp && current_privacy.equals_some(&accepted_state.privacy) - { - if current_privacy.equals(&newest_privacy) { - UpdateDecision::NoChange - } else { - if newest_privacy.equals_some(&accepted_state.future_privacy) { - UpdateDecision::NoChange - } else { - UpdateDecision::Future { - newest: newest_privacy, - } - } - } - } else { - UpdateDecision::Forced(current_privacy) - }; - match (&eula_update, &tos_update, &privacy_update) { - (&UpdateDecision::NoChange, &UpdateDecision::NoChange, &UpdateDecision::NoChange) => { - None - } - _ => Some((eula_update, tos_update, privacy_update)), - } - } else { - None - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum UserChoice { - Deny, - AcceptEULA, - AcceptAll, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum UpdateDecision { - NoChange, - Future { newest: Doc }, - Forced(Doc), -} - -#[derive(Debug, Clone)] -pub struct ConsentState { - pub eula: Option, - pub accepted_eula: bool, - pub future_eula: Option, - - pub tos: Option, - pub accepted_tos: bool, - pub future_tos: Option, - - pub privacy: Option, - pub accepted_pp: bool, - pub future_privacy: Option, -} - -impl ConsentState { - fn sanitize(mut self) -> Self { - let current_secs = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - - if let Some(future_eula) = self.future_eula.clone() { - if future_eula.get_time() < current_secs { - self.eula = Some(future_eula); - self.future_eula = None; - } - } - if let Some(future_tos) = self.future_tos.clone() { - if future_tos.get_time() < current_secs { - self.tos = Some(future_tos); - self.future_tos = None; - } - } - if let Some(future_privacy) = self.future_privacy.clone() { - if future_privacy.get_time() < current_secs { - self.privacy = Some(future_privacy); - self.future_privacy = None; - } - } - - if !self.accepted_eula { - self.accepted_tos = false; - self.accepted_pp = false; - } - self - } - - pub fn load_state() -> ConsentState { - let file = load_file("", "agreements"); - ConsentState::from_str(&file).sanitize() - } - - pub fn save_state(&self) { - save_file("", "agreements", &self.to_string()); - } - - fn to_string(&self) -> String { - let current_secs = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - - let mut file_out: String = format!( - "This file reflects the current consent state used by the application.\ - \nIt may be regenerated or overwritten by the application.\ - \nThis file was last edited by Tensamin at:\ - \nUNIX-SECOND={}", - current_secs - ); - - if let Some(eula) = &self.eula { - file_out.push_str(&format!("\ - \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence agreement. You can find our EULA at https://legal.tensamin.net/eula/\ - \nEULA={}\ - \nEULA-VERSION={}\ - \nEULA-HASH={}\ - ", self.accepted_eula, eula.get_version(), eula.get_hash())); - - if self.accepted_tos - && let Some(tos) = &self.tos - { - file_out.push_str(&format!("\ - \n\"Terms-of-Service=true\" indicates that you read, understood and accepted Tensamin's Terms of Service. You can find our Terms of Serivce at https://legal.tensamin.net/tos/\ - \nTerms-of-Service={}\ - \nTerms-of-Service-VERSION={}\ - \nTerms-of-Service-HASH={}\ - ", self.accepted_tos, tos.get_version(), tos.get_hash())); - } - if self.accepted_pp - && let Some(pp) = &self.privacy - { - file_out.push_str(&format!("\ - \n\"Privacy-Policy=true\" indicates that you read, understood and accepted Tensamin's Privacy Policy. You can find our Privacy Policy at https://legal.tensamin.net/privacy/\ - \nPrivacy-Policy={}\ - \nPrivacy-Policy-VERSION={}\ - \nPrivacy-Policy-HASH={}\ - ", self.accepted_pp, pp.get_version(), pp.get_hash())); - } - } else { - file_out.push_str("\ - \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence Agreement. You can find Tensamin's EULA at https://legal.tensamin.net/eula/\ - \nEULA=false\ - "); - } - - if let Some(eula) = &self.future_eula { - file_out.push_str(&format!( - "\ - \nFUTURE-EULA-VERSION={}\ - \nFUTURE-EULA-HASH={}\ - \nFUTURE-EULA-TIME={}\ - ", - eula.get_version(), - eula.get_hash(), - eula.get_time() - )); - } - if let Some(tos) = &self.future_tos { - file_out.push_str(&format!( - "\ - \nFUTURE-Terms-of-Service-VERSION={}\ - \nFUTURE-Terms-of-Service-HASH={}\ - \nFUTURE-Terms-of-Service-TIME={}\ - ", - tos.get_version(), - tos.get_hash(), - tos.get_time() - )); - } - if let Some(pp) = &self.future_privacy { - file_out.push_str(&format!( - "\ - \nFUTURE-Privacy-Policy-VERSION={}\ - \nFUTURE-Privacy-Policy-HASH={}\ - \nFUTURE-Privacy-Policy-TIME={}\ - ", - pp.get_version(), - pp.get_hash(), - pp.get_time() - )); - } - - file_out - } - - fn from_str(s: &str) -> Self { - let mut eula = false; - let mut eula_version = String::new(); - let mut eula_hash = String::new(); - let mut pp = false; - let mut pp_version = String::new(); - let mut pp_hash = String::new(); - let mut tos = false; - let mut tos_version = String::new(); - let mut tos_hash = String::new(); - - let mut future_eula_version = String::new(); - let mut future_eula_hash = String::new(); - let mut future_eula_time = String::new(); - - let mut future_tos_version = String::new(); - let mut future_tos_hash = String::new(); - let mut future_tos_time = String::new(); - - let mut future_pp_version = String::new(); - let mut future_pp_hash = String::new(); - let mut future_pp_time = String::new(); - - let mut unix = String::new(); - - for line in s.lines() { - if let Some(v) = line.strip_prefix("EULA=") { - eula = v == "true"; - } else if let Some(v) = line.strip_prefix("EULA-VERSION=") { - eula_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("EULA-HASH=") { - eula_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("Terms-of-Service=") { - tos = v == "true"; - } else if let Some(v) = line.strip_prefix("Terms-of-Service-VERSION=") { - tos_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("Terms-of-Service-HASH=") { - tos_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("Privacy-Policy=") { - pp = v == "true"; - } else if let Some(v) = line.strip_prefix("Privacy-Policy-VERSION=") { - pp_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("Privacy-Policy-HASH=") { - pp_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("UNIX-SECOND=") { - unix = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-EULA-VERSION=") { - future_eula_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-EULA-HASH=") { - future_eula_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-EULA-TIME=") { - future_eula_time = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-VERSION=") { - future_tos_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-HASH=") { - future_tos_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-TIME=") { - future_tos_time = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-VERSION=") { - future_pp_version = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-HASH=") { - future_pp_hash = v.to_string(); - } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-TIME=") { - future_pp_time = v.to_string(); - } - } - let unix: u64 = unix.parse::().unwrap_or(0); - let future_eula_time = future_eula_time.parse::().unwrap_or(0); - let future_tos_time = future_tos_time.parse::().unwrap_or(0); - let future_pp_time = future_pp_time.parse::().unwrap_or(0); - let state = Self { - accepted_eula: eula, - eula: Some(Doc::new(eula_version, eula_hash, Type::EULA, unix)), - accepted_pp: pp, - privacy: Some(Doc::new(pp_version, pp_hash, Type::PP, unix)), - accepted_tos: tos, - tos: Some(Doc::new(tos_version, tos_hash, Type::TOS, unix)), - future_eula: if !future_eula_version.is_empty() { - Some(Doc::new( - future_eula_version, - future_eula_hash, - Type::EULA, - future_eula_time, - )) - } else { - None - }, - future_tos: if !future_tos_version.is_empty() { - Some(Doc::new( - future_tos_version, - future_tos_hash, - Type::TOS, - future_tos_time, - )) - } else { - None - }, - future_privacy: if !future_pp_version.is_empty() { - Some(Doc::new( - future_pp_version, - future_pp_hash, - Type::PP, - future_pp_time, - )) - } else { - None - }, - } - .sanitize(); - - state - } -} diff --git a/web-server/Cargo.toml b/web-server/Cargo.toml new file mode 100644 index 0000000..fdeeb44 --- /dev/null +++ b/web-server/Cargo.toml @@ -0,0 +1,9 @@ + +[package] +name = "iota" +version = "0.1.0" +edition = "2024" + +[dependencies] +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/web-server/src/lib.rs b/web-server/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/web-ui/Cargo.toml b/web-ui/Cargo.toml new file mode 100644 index 0000000..4d2ef71 --- /dev/null +++ b/web-ui/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "web-ui" +version = "0.1.0" +edition = "2024" + +[dependencies] +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +actix-web = { version = "4", features = ["rustls-0_23"] } +actix-web-actors = "4" +aes-gcm = "0.10.3" +async-trait = "0.1.89" +base64 = "0.22.1" +chrono = "0.4.43" +crossterm = "*" +dashmap = "6.1.0" +futures = "*" +futures-util = "*" +hex = "*" +hkdf = "0.12.4" +hyper = { version = "1.8.1", features = [ + "capi", + "client", + "full", + "http1", + "http2", + "nightly", + "server", +] } +hyper-util = { version = "*" } +json = "*" +lazy_static = "1.5.0" +once_cell = "1.21.3" +open = "5.3.3" +pnet = "0.35.0" +rand = "0.8" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +ratatui = "0.30.0" +reqwest = "0.13.2" +rusqlite = "0.39.0" +rustls = { version = "0.23.37", features = ["aws-lc-rs"] } +rustls-pemfile = "2.2.0" +serde_json = "1.0.149" +sha2 = "0.10.9" +strum = "0.27.2" +strum_macros = "0.27.2" +sysinfo = "0.38.3" +tokio = { version = "1.50.0", features = ["full"] } +tokio-tungstenite = { version = "*", features = ["native-tls"] } +tungstenite = "*" +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +warp = "*" +x448 = { version = "*" } +zip = "6.0.0" diff --git a/src/server/api.rs b/web-ui/src/api.rs similarity index 100% rename from src/server/api.rs rename to web-ui/src/api.rs diff --git a/src/server/mod.rs b/web-ui/src/lib.rs similarity index 100% rename from src/server/mod.rs rename to web-ui/src/lib.rs diff --git a/src/server/server.rs b/web-ui/src/server.rs similarity index 100% rename from src/server/server.rs rename to web-ui/src/server.rs diff --git a/src/server/web_path_parser.rs b/web-ui/src/web_path_parser.rs similarity index 100% rename from src/server/web_path_parser.rs rename to web-ui/src/web_path_parser.rs From 71ac8d97fa1ac40b83090f5ce97f276f4aa39c13 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sat, 4 Apr 2026 21:43:54 +0200 Subject: [PATCH 2/9] ... --- Cargo.lock | 1 + Cargo.toml | 2 +- iota-cli/Cargo.toml | 3 + iota-cli/src/lib.rs | 2 + .../terms => iota-cli/src/util}/buttons.rs | 2 +- .../src/util/terms_focus.rs | 0 iota-logger/src/lib.rs | 440 +++++++++++++++++- iota-storage/src/util/logger.rs | 432 ----------------- iota-terms/Cargo.toml | 10 + .../src/terms => iota-terms/src}/doc.rs | 0 .../src/terms/mod.rs => iota-terms/src/lib.rs | 2 - .../terms => iota-terms/src}/terms_getter.rs | 0 12 files changed, 447 insertions(+), 447 deletions(-) rename {iota-core/src/terms => iota-cli/src/util}/buttons.rs (99%) rename iota-core/src/terms/focus.rs => iota-cli/src/util/terms_focus.rs (100%) delete mode 100755 iota-storage/src/util/logger.rs create mode 100644 iota-terms/Cargo.toml rename {iota-core/src/terms => iota-terms/src}/doc.rs (100%) rename iota-core/src/terms/mod.rs => iota-terms/src/lib.rs (52%) rename {iota-core/src/terms => iota-terms/src}/terms_getter.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 334fe02..1b603bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1793,6 +1793,7 @@ dependencies = [ "hkdf", "hyper", "hyper-util", + "iota-core", "iota-state", "json", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 7d4ef81..f9744a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["iota-storage", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "decentralized", "iota-logger"] +members = ["iota-storage", "iota-terms", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "decentralized", "iota-logger"] diff --git a/iota-cli/Cargo.toml b/iota-cli/Cargo.toml index 029e7e0..a963a07 100644 --- a/iota-cli/Cargo.toml +++ b/iota-cli/Cargo.toml @@ -5,6 +5,9 @@ edition = "2024" [dependencies] iota-state = { path = "../iota-state" } +iota-core = { path = "../iota-terms" } + + ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/iota-cli/src/lib.rs b/iota-cli/src/lib.rs index b355046..aaa23ef 100644 --- a/iota-cli/src/lib.rs +++ b/iota-cli/src/lib.rs @@ -13,6 +13,8 @@ pub mod screens { } pub mod util { pub mod borders; + pub mod buttons; + pub mod terms_focus; } pub mod app_state; pub mod input_handler; diff --git a/iota-core/src/terms/buttons.rs b/iota-cli/src/util/buttons.rs similarity index 99% rename from iota-core/src/terms/buttons.rs rename to iota-cli/src/util/buttons.rs index c545a4c..6c93cce 100644 --- a/iota-core/src/terms/buttons.rs +++ b/iota-cli/src/util/buttons.rs @@ -5,7 +5,7 @@ use ratatui::{ widgets::{Block, Borders, Paragraph}, }; -use crate::terms::focus::Focus; +use crate::util::terms_focus::Focus; #[allow(mismatched_lifetime_syntaxes)] pub fn checkbox(label: &str, checked: bool, active: bool, allowed: bool) -> Line { diff --git a/iota-core/src/terms/focus.rs b/iota-cli/src/util/terms_focus.rs similarity index 100% rename from iota-core/src/terms/focus.rs rename to iota-cli/src/util/terms_focus.rs diff --git a/iota-logger/src/lib.rs b/iota-logger/src/lib.rs index b93cf3f..a5feb02 100644 --- a/iota-logger/src/lib.rs +++ b/iota-logger/src/lib.rs @@ -1,14 +1,432 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +use std::{ + collections::BTreeMap, + fs::{self, OpenOptions}, + io::Write, + path::Path, + sync::{OnceLock, atomic::Ordering, mpsc}, + thread, + time::{SystemTime, UNIX_EPOCH}, +}; + +use ratatui::style::Color; +use ttp_core::{CommunicationValue, DataTypes, DataValue}; + +use crate::{ + APP_STATE, + gui::{elements::log_card::LogEntry, ui::UNIQUE}, + langu::language_manager, +}; + +static LOGGER: OnceLock> = OnceLock::new(); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[allow(unused)] +pub enum PrintType { + Call, + Client, + Iota, + Omikron, + Omega, + General, + Command, } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +impl PrintType { + pub fn prefix_color(self) -> Color { + match self { + PrintType::Call => Color::Magenta, + PrintType::Client => Color::Green, + PrintType::Iota => Color::Yellow, + PrintType::Omikron => Color::Blue, + PrintType::Omega => Color::Cyan, + PrintType::General => Color::LightCyan, + PrintType::Command => Color::LightGreen, + } } } + +struct LogMessage { + timestamp_ms: u128, + prefix: String, + kind: PrintType, + is_error: bool, + translation_key: Option, + format_args: Vec, + message: Option, +} + +pub fn startup() { + let (tx, rx) = mpsc::channel::(); + LOGGER.set(tx).expect("Logger already initialized"); + + thread::spawn(move || { + let log_dir = Path::new("logs"); + fs::create_dir_all(log_dir).expect("Failed to create log directory"); + + let start_ts = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let path = log_dir.join(format!("log_{}.txt", start_ts)); + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(path) + .expect("Failed to open log file"); + + for msg in rx { + let resolved_message = if let Some(key) = msg.translation_key { + let args: Vec<&str> = msg.format_args.iter().map(|s| s.as_str()).collect(); + language_manager::format(&key, &args) + } else { + msg.message.unwrap_or_default() + }; + + let timestamp = format_timestamp_inline(msg.timestamp_ms); + let entry = LogEntry::new(msg.kind, resolved_message, msg.is_error); + + let prefix = if msg.prefix.is_empty() { + String::new() + } else { + format!("{} ", msg.prefix) + }; + + let _ = writeln!( + file, + "{} {}{}", + fixed_box(&msg.timestamp_ms.to_string(), 13), + prefix, + entry.message + ); + + let _ = writeln!(file, " {}", timestamp); + + let mut state = APP_STATE.lock().unwrap(); + state.push_log(entry.into()); + } + }); +} + +fn format_timestamp_inline(timestamp_ms: u128) -> String { + let secs = (timestamp_ms / 1000) as i64; + let hours = (secs / 3600) % 24; + let minutes = (secs / 60) % 60; + let seconds = secs % 60; + format!("[{:02}:{:02}:{:02}]", hours, minutes, seconds) +} + +fn fixed_box(content: &str, width: usize) -> String { + let s: String = content.chars().take(width).collect(); + let len = s.chars().count(); + if len < width { + format!("[{}{}]", " ".repeat(width - len), s) + } else { + s + } +} + +fn colorize(kind: PrintType, is_error: bool) -> Color { + if is_error { + return Color::Red; + } + + match kind { + PrintType::Call => Color::Magenta, + PrintType::Client => Color::Green, + PrintType::Iota => Color::Yellow, + PrintType::Omikron => Color::Blue, + PrintType::Omega => Color::Cyan, + PrintType::General => Color::LightCyan, + PrintType::Command => Color::LightGreen, + } +} + +pub fn log_internal_translated( + kind: PrintType, + prefix: String, + is_error: bool, + key: &str, + args: Vec, +) { + if let Some(tx) = LOGGER.get() { + UNIQUE.store(true, Ordering::Relaxed); + let _ = tx.send(LogMessage { + timestamp_ms: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis(), + prefix, + kind, + is_error, + translation_key: Some(key.to_string()), + format_args: args, + message: None, + }); + } +} + +pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: String) { + if let Some(tx) = LOGGER.get() { + UNIQUE.store(true, Ordering::Relaxed); + let _ = tx.send(LogMessage { + timestamp_ms: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis(), + prefix, + kind, + is_error, + translation_key: None, + format_args: Vec::new(), + message: Some(message), + }); + } +} + +#[macro_export] +macro_rules! log_t { + ($key:expr) => { + $crate::util::logger::log_internal_translated( + $crate::util::logger::PrintType::General, + "".to_string(), + false, + $key, + vec![] + ) + }; + + ($key:expr, $($arg:expr),+) => { + $crate::util::logger::log_internal_translated( + $crate::util::logger::PrintType::General, + "".to_string(), + false, + $key, + vec![$($arg),+] + ) + }; +} + +#[macro_export] +macro_rules! log_t_err { + ($key:expr) => { + $crate::util::logger::log_internal_translated( + $crate::util::logger::PrintType::General, + "".to_string(), + true, + $key, + vec![] + ) + }; + + ($key:expr, $($arg:expr),+) => { + $crate::util::logger::log_internal_translated( + $crate::util::logger::PrintType::General, + "".to_string(), + true, + $key, + vec![$($arg.to_string()),+] + ) + }; +} + +/// Log a command message. +#[macro_export] +macro_rules! log_command { + ($($arg:tt)*) => { + $crate::util::logger::log_internal( + $crate::util::logger::PrintType::Command, + "".to_string(), + false, + format!($($arg)*) + ) + }; +} + +/// Log a general informational message. +#[macro_export] +macro_rules! log { + ($($arg:tt)*) => { + $crate::util::logger::log_internal( + $crate::util::logger::PrintType::General, + "".to_string(), + false, + format!($($arg)*) + ) + }; +} + +/// Log an inbound message (`>`). +#[macro_export] +macro_rules! log_in { + ($($arg:tt)*) => { + $crate::util::logger::log_internal( + $crate::util::logger::PrintType::General, + ">".to_string(), + false, + format!($($arg)*) + ) + }; +} + +/// Log an outbound message (`<`). +#[macro_export] +macro_rules! log_out { + ($($arg:tt)*) => { + $crate::util::logger::log_internal( + $crate::util::logger::PrintType::General, + "<".to_string(), + false, + format!($($arg)*) + ) + }; +} + +/// Log an error message (`>>`). +#[macro_export] +macro_rules! log_err { + ($($arg:tt)*) => { + $crate::util::logger::log_internal( + $crate::util::logger::PrintType::General, + ">>".to_string(), + true, + format!($($arg)*) + ) + }; +} + +// ******** COMMUNICATION VALUES ******** +pub fn log_cv_internal( + prefix: &'static str, + cv: &CommunicationValue, + print_type: Option, +) { + let formatted = format_cv(cv); + + log_internal( + print_type.unwrap_or(PrintType::General), + prefix.to_string(), + false, + formatted, + ); +} + +pub fn format_cv(cv: &CommunicationValue) -> String { + let mut parts = Vec::new(); + + let sender = cv.get_sender(); + let receiver = cv.get_receiver(); + + if sender > 0 && receiver > 0 { + parts.push(format!("{} > {}", sender, receiver)); + } else if sender > 0 { + parts.push(format!("{}", sender)); + } else if receiver > 0 { + parts.push(format!("> {}", receiver)); + } + + let comm_type = cv.get_type().to_string(); + parts.push(format!("{}", comm_type)); + + let data: &BTreeMap = cv.get_data_container(); + + let formated_data = + format_data_container(data.iter().map(|(k, v)| (k.clone(), v.clone())).collect()); + + parts.push(format!("{}", formated_data)); + + parts.join(": ") +} + +fn format_data_container(data: Vec<(DataTypes, DataValue)>) -> String { + let parts: Vec = data + .into_iter() + .map(|(key, value)| { + let key_str = key.to_string(); + + match value { + DataValue::Str(s) => format!("{}=\"{}\"", key_str, s), + + DataValue::Container(inner) => { + let inner_formatted = format_data_container(inner); + format!("{}={{ {} }}", key_str, inner_formatted) + } + + DataValue::Array(arr) => { + let arr_formatted = format_array(arr); + format!("{}=[{}]", key_str, arr_formatted) + } + + DataValue::Bool(b) => format!("{}={}", key_str, b), + + DataValue::BoolTrue => format!("{}=true", key_str), + DataValue::BoolFalse => format!("{}=false", key_str), + + DataValue::Number(num) => format!("{}={}", key_str, num), + + _ => "".to_string(), + } + }) + .collect(); + + parts.join(", ") +} + +fn format_array(arr: Vec) -> String { + let parts: Vec = arr + .into_iter() + .map(|value| match value { + DataValue::Str(s) => format!("\"{}\"", s), + + DataValue::Container(inner) => { + let inner_formatted = format_data_container(inner); + format!("{{ {} }}", inner_formatted) + } + + DataValue::Array(inner_arr) => { + let formatted = format_array(inner_arr); + format!("[{}]", formatted) + } + + DataValue::Bool(b) => b.to_string(), + + DataValue::BoolTrue => "true".to_string(), + DataValue::BoolFalse => "false".to_string(), + + DataValue::Number(num) => num.to_string(), + + _ => String::new(), + }) + .collect(); + + parts.join(", ") +} + +#[macro_export] +macro_rules! log_cv { + ($kind:expr, $cv:expr) => { + $crate::util::logger::log_cv_internal("", &$cv, Some($kind)) + }; + ($cv:expr) => { + $crate::util::logger::log_cv_internal("", &$cv, None) + }; +} + +#[macro_export] +macro_rules! log_cv_in { + ($kind:expr, $cv:expr) => { + $crate::util::logger::log_cv_internal("> ", &$cv, Some($kind)) + }; + ($cv:expr) => { + $crate::util::logger::log_cv_internal("> ", &$cv, None) + }; +} + +#[macro_export] +macro_rules! log_cv_out { + ($kind:expr, $cv:expr) => { + $crate::util::logger::log_cv_internal("< ", &$cv, Some($kind)) + }; + ($cv:expr) => { + $crate::util::logger::log_cv_internal("< ", &$cv, None) + }; +} diff --git a/iota-storage/src/util/logger.rs b/iota-storage/src/util/logger.rs deleted file mode 100755 index a5feb02..0000000 --- a/iota-storage/src/util/logger.rs +++ /dev/null @@ -1,432 +0,0 @@ -use std::{ - collections::BTreeMap, - fs::{self, OpenOptions}, - io::Write, - path::Path, - sync::{OnceLock, atomic::Ordering, mpsc}, - thread, - time::{SystemTime, UNIX_EPOCH}, -}; - -use ratatui::style::Color; -use ttp_core::{CommunicationValue, DataTypes, DataValue}; - -use crate::{ - APP_STATE, - gui::{elements::log_card::LogEntry, ui::UNIQUE}, - langu::language_manager, -}; - -static LOGGER: OnceLock> = OnceLock::new(); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -#[allow(unused)] -pub enum PrintType { - Call, - Client, - Iota, - Omikron, - Omega, - General, - Command, -} -impl PrintType { - pub fn prefix_color(self) -> Color { - match self { - PrintType::Call => Color::Magenta, - PrintType::Client => Color::Green, - PrintType::Iota => Color::Yellow, - PrintType::Omikron => Color::Blue, - PrintType::Omega => Color::Cyan, - PrintType::General => Color::LightCyan, - PrintType::Command => Color::LightGreen, - } - } -} - -struct LogMessage { - timestamp_ms: u128, - prefix: String, - kind: PrintType, - is_error: bool, - translation_key: Option, - format_args: Vec, - message: Option, -} - -pub fn startup() { - let (tx, rx) = mpsc::channel::(); - LOGGER.set(tx).expect("Logger already initialized"); - - thread::spawn(move || { - let log_dir = Path::new("logs"); - fs::create_dir_all(log_dir).expect("Failed to create log directory"); - - let start_ts = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - - let path = log_dir.join(format!("log_{}.txt", start_ts)); - let mut file = OpenOptions::new() - .create(true) - .append(true) - .open(path) - .expect("Failed to open log file"); - - for msg in rx { - let resolved_message = if let Some(key) = msg.translation_key { - let args: Vec<&str> = msg.format_args.iter().map(|s| s.as_str()).collect(); - language_manager::format(&key, &args) - } else { - msg.message.unwrap_or_default() - }; - - let timestamp = format_timestamp_inline(msg.timestamp_ms); - let entry = LogEntry::new(msg.kind, resolved_message, msg.is_error); - - let prefix = if msg.prefix.is_empty() { - String::new() - } else { - format!("{} ", msg.prefix) - }; - - let _ = writeln!( - file, - "{} {}{}", - fixed_box(&msg.timestamp_ms.to_string(), 13), - prefix, - entry.message - ); - - let _ = writeln!(file, " {}", timestamp); - - let mut state = APP_STATE.lock().unwrap(); - state.push_log(entry.into()); - } - }); -} - -fn format_timestamp_inline(timestamp_ms: u128) -> String { - let secs = (timestamp_ms / 1000) as i64; - let hours = (secs / 3600) % 24; - let minutes = (secs / 60) % 60; - let seconds = secs % 60; - format!("[{:02}:{:02}:{:02}]", hours, minutes, seconds) -} - -fn fixed_box(content: &str, width: usize) -> String { - let s: String = content.chars().take(width).collect(); - let len = s.chars().count(); - if len < width { - format!("[{}{}]", " ".repeat(width - len), s) - } else { - s - } -} - -fn colorize(kind: PrintType, is_error: bool) -> Color { - if is_error { - return Color::Red; - } - - match kind { - PrintType::Call => Color::Magenta, - PrintType::Client => Color::Green, - PrintType::Iota => Color::Yellow, - PrintType::Omikron => Color::Blue, - PrintType::Omega => Color::Cyan, - PrintType::General => Color::LightCyan, - PrintType::Command => Color::LightGreen, - } -} - -pub fn log_internal_translated( - kind: PrintType, - prefix: String, - is_error: bool, - key: &str, - args: Vec, -) { - if let Some(tx) = LOGGER.get() { - UNIQUE.store(true, Ordering::Relaxed); - let _ = tx.send(LogMessage { - timestamp_ms: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis(), - prefix, - kind, - is_error, - translation_key: Some(key.to_string()), - format_args: args, - message: None, - }); - } -} - -pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: String) { - if let Some(tx) = LOGGER.get() { - UNIQUE.store(true, Ordering::Relaxed); - let _ = tx.send(LogMessage { - timestamp_ms: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis(), - prefix, - kind, - is_error, - translation_key: None, - format_args: Vec::new(), - message: Some(message), - }); - } -} - -#[macro_export] -macro_rules! log_t { - ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, - "".to_string(), - false, - $key, - vec![] - ) - }; - - ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, - "".to_string(), - false, - $key, - vec![$($arg),+] - ) - }; -} - -#[macro_export] -macro_rules! log_t_err { - ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, - "".to_string(), - true, - $key, - vec![] - ) - }; - - ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, - "".to_string(), - true, - $key, - vec![$($arg.to_string()),+] - ) - }; -} - -/// Log a command message. -#[macro_export] -macro_rules! log_command { - ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::Command, - "".to_string(), - false, - format!($($arg)*) - ) - }; -} - -/// Log a general informational message. -#[macro_export] -macro_rules! log { - ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, - "".to_string(), - false, - format!($($arg)*) - ) - }; -} - -/// Log an inbound message (`>`). -#[macro_export] -macro_rules! log_in { - ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, - ">".to_string(), - false, - format!($($arg)*) - ) - }; -} - -/// Log an outbound message (`<`). -#[macro_export] -macro_rules! log_out { - ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, - "<".to_string(), - false, - format!($($arg)*) - ) - }; -} - -/// Log an error message (`>>`). -#[macro_export] -macro_rules! log_err { - ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, - ">>".to_string(), - true, - format!($($arg)*) - ) - }; -} - -// ******** COMMUNICATION VALUES ******** -pub fn log_cv_internal( - prefix: &'static str, - cv: &CommunicationValue, - print_type: Option, -) { - let formatted = format_cv(cv); - - log_internal( - print_type.unwrap_or(PrintType::General), - prefix.to_string(), - false, - formatted, - ); -} - -pub fn format_cv(cv: &CommunicationValue) -> String { - let mut parts = Vec::new(); - - let sender = cv.get_sender(); - let receiver = cv.get_receiver(); - - if sender > 0 && receiver > 0 { - parts.push(format!("{} > {}", sender, receiver)); - } else if sender > 0 { - parts.push(format!("{}", sender)); - } else if receiver > 0 { - parts.push(format!("> {}", receiver)); - } - - let comm_type = cv.get_type().to_string(); - parts.push(format!("{}", comm_type)); - - let data: &BTreeMap = cv.get_data_container(); - - let formated_data = - format_data_container(data.iter().map(|(k, v)| (k.clone(), v.clone())).collect()); - - parts.push(format!("{}", formated_data)); - - parts.join(": ") -} - -fn format_data_container(data: Vec<(DataTypes, DataValue)>) -> String { - let parts: Vec = data - .into_iter() - .map(|(key, value)| { - let key_str = key.to_string(); - - match value { - DataValue::Str(s) => format!("{}=\"{}\"", key_str, s), - - DataValue::Container(inner) => { - let inner_formatted = format_data_container(inner); - format!("{}={{ {} }}", key_str, inner_formatted) - } - - DataValue::Array(arr) => { - let arr_formatted = format_array(arr); - format!("{}=[{}]", key_str, arr_formatted) - } - - DataValue::Bool(b) => format!("{}={}", key_str, b), - - DataValue::BoolTrue => format!("{}=true", key_str), - DataValue::BoolFalse => format!("{}=false", key_str), - - DataValue::Number(num) => format!("{}={}", key_str, num), - - _ => "".to_string(), - } - }) - .collect(); - - parts.join(", ") -} - -fn format_array(arr: Vec) -> String { - let parts: Vec = arr - .into_iter() - .map(|value| match value { - DataValue::Str(s) => format!("\"{}\"", s), - - DataValue::Container(inner) => { - let inner_formatted = format_data_container(inner); - format!("{{ {} }}", inner_formatted) - } - - DataValue::Array(inner_arr) => { - let formatted = format_array(inner_arr); - format!("[{}]", formatted) - } - - DataValue::Bool(b) => b.to_string(), - - DataValue::BoolTrue => "true".to_string(), - DataValue::BoolFalse => "false".to_string(), - - DataValue::Number(num) => num.to_string(), - - _ => String::new(), - }) - .collect(); - - parts.join(", ") -} - -#[macro_export] -macro_rules! log_cv { - ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, Some($kind)) - }; - ($cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, None) - }; -} - -#[macro_export] -macro_rules! log_cv_in { - ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, Some($kind)) - }; - ($cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, None) - }; -} - -#[macro_export] -macro_rules! log_cv_out { - ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, Some($kind)) - }; - ($cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, None) - }; -} diff --git a/iota-terms/Cargo.toml b/iota-terms/Cargo.toml new file mode 100644 index 0000000..070687c --- /dev/null +++ b/iota-terms/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "iota-terms" +version = "0.1.0" +edition = "2024" + +[dependencies] +iota-state = { path = "../iota-state" } + +json = "*" +reqwest = "0.13.2" diff --git a/iota-core/src/terms/doc.rs b/iota-terms/src/doc.rs similarity index 100% rename from iota-core/src/terms/doc.rs rename to iota-terms/src/doc.rs diff --git a/iota-core/src/terms/mod.rs b/iota-terms/src/lib.rs similarity index 52% rename from iota-core/src/terms/mod.rs rename to iota-terms/src/lib.rs index 947fc13..b03efc9 100644 --- a/iota-core/src/terms/mod.rs +++ b/iota-terms/src/lib.rs @@ -1,4 +1,2 @@ -pub mod buttons; pub mod doc; -pub mod focus; pub mod terms_getter; diff --git a/iota-core/src/terms/terms_getter.rs b/iota-terms/src/terms_getter.rs similarity index 100% rename from iota-core/src/terms/terms_getter.rs rename to iota-terms/src/terms_getter.rs From 05763e7dd39e8579d36bd959ff6b765e65111a64 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:22:46 +0200 Subject: [PATCH 3/9] ... --- Cargo.lock | 52 +++++++++++++++---- iota-cli/Cargo.toml | 6 ++- iota-core/Cargo.toml | 9 ++++ iota-util/Cargo.toml | 15 ++++++ .../util => iota-util/src}/crypto_helper.rs | 0 .../src/util => iota-util/src}/crypto_util.rs | 0 .../src/util => iota-util/src}/file_util.rs | 0 iota-util/src/lib.rs | 0 web-server/Cargo.toml | 2 +- 9 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 iota-util/Cargo.toml rename {iota-storage/src/util => iota-util/src}/crypto_helper.rs (100%) rename {iota-storage/src/util => iota-util/src}/crypto_util.rs (100%) rename {iota-storage/src/util => iota-util/src}/file_util.rs (100%) create mode 100644 iota-util/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1b603bc..d48cc69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1767,14 +1767,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "iota" -version = "0.1.0" -dependencies = [ - "ttp-core", - "ttp-native", -] - [[package]] name = "iota-cli" version = "0.1.0" @@ -1793,10 +1785,14 @@ dependencies = [ "hkdf", "hyper", "hyper-util", - "iota-core", + "iota-logger", "iota-state", + "iota-storage", + "iota-terms", + "iota-util", "json", "lazy_static", + "omikron-connector", "once_cell", "open", "pnet", @@ -1829,8 +1825,14 @@ name = "iota-core" version = "0.1.0" dependencies = [ "dashmap", + "iota-cli", + "iota-logger", "iota-state", + "iota-storage", + "iota-terms", + "iota-util", "json", + "omikron-connector", "once_cell", "pnet", "ratatui", @@ -1838,6 +1840,8 @@ dependencies = [ "tokio", "ttp-core", "ttp-native", + "web-server", + "web-ui", ] [[package]] @@ -1882,6 +1886,28 @@ dependencies = [ "zip", ] +[[package]] +name = "iota-terms" +version = "0.1.0" +dependencies = [ + "iota-state", + "json", + "reqwest", +] + +[[package]] +name = "iota-util" +version = "0.1.0" +dependencies = [ + "json", + "pnet", + "ratatui", + "reqwest", + "tokio", + "ttp-core", + "ttp-native", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -4331,6 +4357,14 @@ dependencies = [ "semver", ] +[[package]] +name = "web-server" +version = "0.1.0" +dependencies = [ + "ttp-core", + "ttp-native", +] + [[package]] name = "web-sys" version = "0.3.94" diff --git a/iota-cli/Cargo.toml b/iota-cli/Cargo.toml index a963a07..99e2051 100644 --- a/iota-cli/Cargo.toml +++ b/iota-cli/Cargo.toml @@ -4,8 +4,12 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-logger = { path = "../iota-logger" } iota-state = { path = "../iota-state" } -iota-core = { path = "../iota-terms" } +iota-storage = { path = "../iota-storage" } +iota-terms = { path = "../iota-terms" } +iota-util = { path = "../iota-util" } +omikron-connector = { path = "../omikron-connector" } ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } diff --git a/iota-core/Cargo.toml b/iota-core/Cargo.toml index 7db34a2..5ecc90a 100644 --- a/iota-core/Cargo.toml +++ b/iota-core/Cargo.toml @@ -4,7 +4,16 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-cli = { path = "../iota-cli" } +iota-logger = { path = "../iota-logger" } iota-state = { path = "../iota-state" } +iota-storage = { path = "../iota-storage" } +iota-terms = { path = "../iota-terms" } +iota-util = { path = "../iota-util" } +omikron-connector = { path = "../omikron-connector" } +web-server = { path = "../web-server" } +web-ui = { path = "../web-ui" } + ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/iota-util/Cargo.toml b/iota-util/Cargo.toml new file mode 100644 index 0000000..369ad84 --- /dev/null +++ b/iota-util/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "iota-util" +version = "0.1.0" +edition = "2024" + +[dependencies] + +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } + +json = "*" +pnet = "0.35.0" +ratatui = "0.30.0" +reqwest = "0.13.2" +tokio = { version = "1.50.0", features = ["full"] } diff --git a/iota-storage/src/util/crypto_helper.rs b/iota-util/src/crypto_helper.rs similarity index 100% rename from iota-storage/src/util/crypto_helper.rs rename to iota-util/src/crypto_helper.rs diff --git a/iota-storage/src/util/crypto_util.rs b/iota-util/src/crypto_util.rs similarity index 100% rename from iota-storage/src/util/crypto_util.rs rename to iota-util/src/crypto_util.rs diff --git a/iota-storage/src/util/file_util.rs b/iota-util/src/file_util.rs similarity index 100% rename from iota-storage/src/util/file_util.rs rename to iota-util/src/file_util.rs diff --git a/iota-util/src/lib.rs b/iota-util/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/web-server/Cargo.toml b/web-server/Cargo.toml index fdeeb44..0e99c39 100644 --- a/web-server/Cargo.toml +++ b/web-server/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "iota" +name = "web-server" version = "0.1.0" edition = "2024" From 1ea0b97f6dcc8ac7e9a6474f63d694e089279219 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:03:19 +0200 Subject: [PATCH 4/9] ... --- Cargo.lock | 83 ++- Cargo.toml | 2 +- decentralized/src/lib.rs | 2 + .../{local-auth => local_auth}/auth_user.rs | 0 .../{local-auth => local_auth}/local_auth.rs | 2 +- .../src/{local-auth => local_auth}/mod.rs | 0 .../{Cargo.toml => unused-Cargo.toml} | 4 + iota-cli/src/elements/console_card.rs | 28 +- iota-cli/src/elements/elements.rs | 2 +- iota-cli/src/elements/graph_card.rs | 12 +- iota-cli/src/elements/log_card.rs | 29 +- iota-cli/src/input_handler.rs | 4 +- iota-cli/src/screens/terms_checker.rs | 24 +- iota-cli/src/screens/terms_updater.rs | 25 +- iota-cli/src/ui.rs | 2 +- iota-core/src/consent_state.rs | 473 ++++++++++++++++++ iota-core/src/main.rs | 11 + iota-logger/Cargo.toml | 4 + iota-logger/src/lib.rs | 67 +-- iota-state/src/lib.rs | 4 +- iota-storage/Cargo.toml | 4 + iota-storage/src/lib.rs | 4 +- iota-storage/src/users/user_community_util.rs | 2 +- iota-storage/src/users/user_manager.rs | 88 +--- iota-storage/src/users/user_profile.rs | 2 +- iota-storage/src/util/chat_files.rs | 2 +- iota-storage/src/util/config_util.rs | 2 +- iota-storage/src/util/db.rs | 2 +- iota-storage/src/util/mod.rs | 4 - iota-terms/Cargo.toml | 1 + iota-terms/src/doc.rs | 3 +- iota-terms/src/lib.rs | 14 +- iota-terms/src/terms_getter.rs | 2 +- iota-util/Cargo.toml | 12 + iota-util/src/file_util.rs | 26 +- .../src/langu/language_creator.rs | 2 +- .../src/langu/language_manager.rs | 2 +- {iota-cli => iota-util}/src/langu/mod.rs | 0 iota-util/src/lib.rs | 4 + omikron-connector/Cargo.toml | 9 + omikron-connector/src/lib.rs | 1 + omikron-connector/src/omikron_connection.rs | 20 +- omikron-connector/src/ping_pong_task.rs | 5 +- omikron-connector/src/user_ops.rs | 93 ++++ web-ui/Cargo.toml | 5 + web-ui/src/api.rs | 49 +- web-ui/src/server.rs | 20 +- web-ui/src/socket.rs | 0 web-ui/src/web_path_parser.rs | 2 +- 49 files changed, 869 insertions(+), 289 deletions(-) rename decentralized/src/{local-auth => local_auth}/auth_user.rs (100%) rename decentralized/src/{local-auth => local_auth}/local_auth.rs (91%) rename decentralized/src/{local-auth => local_auth}/mod.rs (100%) rename decentralized/{Cargo.toml => unused-Cargo.toml} (88%) create mode 100644 iota-core/src/consent_state.rs rename {iota-cli => iota-util}/src/langu/language_creator.rs (98%) rename {iota-cli => iota-util}/src/langu/language_manager.rs (98%) rename {iota-cli => iota-util}/src/langu/mod.rs (100%) create mode 100644 omikron-connector/src/user_ops.rs create mode 100644 web-ui/src/socket.rs diff --git a/Cargo.lock b/Cargo.lock index d48cc69..a9dcfc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -847,53 +847,6 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" -[[package]] -name = "decentralized" -version = "0.1.0" -dependencies = [ - "actix-web", - "actix-web-actors", - "aes-gcm", - "async-trait", - "base64", - "chrono", - "crossterm", - "dashmap", - "futures", - "futures-util", - "hex", - "hkdf", - "hyper", - "hyper-util", - "json", - "lazy_static", - "once_cell", - "open", - "pnet", - "rand 0.8.5", - "rand_core 0.6.4", - "ratatui", - "reqwest", - "rusqlite", - "rustls", - "rustls-pemfile", - "serde_json", - "sha2", - "strum 0.27.2", - "strum_macros 0.27.2", - "sysinfo", - "tokio", - "tokio-tungstenite", - "ttp-core", - "ttp-native", - "tungstenite", - "uuid", - "walkdir", - "warp", - "x448", - "zip", -] - [[package]] name = "deflate64" version = "0.1.12" @@ -1847,6 +1800,12 @@ dependencies = [ [[package]] name = "iota-logger" version = "0.1.0" +dependencies = [ + "iota-state", + "iota-util", + "ratatui", + "ttp-core", +] [[package]] name = "iota-state" @@ -1868,6 +1827,9 @@ dependencies = [ "base64", "hex", "hkdf", + "iota-logger", + "iota-state", + "iota-util", "json", "once_cell", "rand 0.8.5", @@ -1891,6 +1853,7 @@ name = "iota-terms" version = "0.1.0" dependencies = [ "iota-state", + "iota-util", "json", "reqwest", ] @@ -1899,13 +1862,25 @@ dependencies = [ name = "iota-util" version = "0.1.0" dependencies = [ + "aes-gcm", + "base64", + "hex", + "hkdf", "json", + "once_cell", "pnet", + "rand_core 0.6.4", "ratatui", "reqwest", + "sha2", + "sysinfo", "tokio", "ttp-core", "ttp-native", + "uuid", + "walkdir", + "x448", + "zip", ] [[package]] @@ -2402,12 +2377,21 @@ dependencies = [ name = "omikron-connector" version = "0.1.0" dependencies = [ + "base64", "dashmap", + "hex", + "iota-logger", + "iota-state", + "iota-storage", + "iota-util", "json", + "rand_core 0.6.4", + "sha2", "tokio", "ttp-core", "ttp-native", "uuid", + "x448", ] [[package]] @@ -4403,8 +4387,13 @@ dependencies = [ "hkdf", "hyper", "hyper-util", + "iota-logger", + "iota-state", + "iota-storage", + "iota-util", "json", "lazy_static", + "omikron-connector", "once_cell", "open", "pnet", diff --git a/Cargo.toml b/Cargo.toml index f9744a3..30a7a09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["iota-storage", "iota-terms", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "decentralized", "iota-logger"] +members = ["iota-storage", "iota-terms", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "iota-logger", "iota-util"] diff --git a/decentralized/src/lib.rs b/decentralized/src/lib.rs index e69de29..e7896d5 100644 --- a/decentralized/src/lib.rs +++ b/decentralized/src/lib.rs @@ -0,0 +1,2 @@ +pub mod communities; +pub mod local_auth; diff --git a/decentralized/src/local-auth/auth_user.rs b/decentralized/src/local_auth/auth_user.rs similarity index 100% rename from decentralized/src/local-auth/auth_user.rs rename to decentralized/src/local_auth/auth_user.rs diff --git a/decentralized/src/local-auth/local_auth.rs b/decentralized/src/local_auth/local_auth.rs similarity index 91% rename from decentralized/src/local-auth/local_auth.rs rename to decentralized/src/local_auth/local_auth.rs index 112ee2b..f9c0fd1 100644 --- a/decentralized/src/local-auth/local_auth.rs +++ b/decentralized/src/local_auth/local_auth.rs @@ -1,6 +1,6 @@ use json::JsonValue; -use crate::util::file_util::load_file; +use iota_iota_util::file_util::load_file; // NOT USED AT MOMENT pub fn is_private_key_valid(user_id: &i64, key_hash: &str) -> bool { let file_contents = load_file("", "users.json"); diff --git a/decentralized/src/local-auth/mod.rs b/decentralized/src/local_auth/mod.rs similarity index 100% rename from decentralized/src/local-auth/mod.rs rename to decentralized/src/local_auth/mod.rs diff --git a/decentralized/Cargo.toml b/decentralized/unused-Cargo.toml similarity index 88% rename from decentralized/Cargo.toml rename to decentralized/unused-Cargo.toml index 9c21cdf..2c9c97c 100644 --- a/decentralized/Cargo.toml +++ b/decentralized/unused-Cargo.toml @@ -6,6 +6,10 @@ edition = "2024" [dependencies] ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +iota-logger = { path = "../iota-logger" } +iota-util = { path = "../iota-util" } +iota-storage = { path = "../iota-storage" } +iota-state = { path = "../iota-state" } actix-web = { version = "4", features = ["rustls-0_23"] } actix-web-actors = "4" diff --git a/iota-cli/src/elements/console_card.rs b/iota-cli/src/elements/console_card.rs index b189bd4..f7b0c8f 100644 --- a/iota-cli/src/elements/console_card.rs +++ b/iota-cli/src/elements/console_card.rs @@ -1,4 +1,9 @@ use crossterm::event::{KeyCode, KeyEvent}; +use iota_logger::{log, log_command, log_cv}; +use iota_state::{ACTIVE_TASKS, RELOAD, SHUTDOWN}; +use iota_storage::users::{user_manager, user_profile::UserProfile}; +use iota_util::file_util; +use omikron_connector::omikron_connection::OMIKRON_CONNECTION; use ratatui::{ Frame, layout::Rect, @@ -9,19 +14,6 @@ use ratatui::{ use ttp_core::{CommunicationType, CommunicationValue}; use uuid::Uuid; -use crate::{ - ACTIVE_TASKS, RELOAD, SHUTDOWN, - gui::{ - elements::elements::{Element, InteractableElement, JoinableElement}, - interaction_result::InteractionResult, - ui::FPS, - util::borders::draw_block_joins, - }, - log, log_command, log_cv, - omikron::omikron_connection::OMIKRON_CONNECTION, - users::{user_manager, user_profile::UserProfile}, - util::file_util, -}; use std::{ any::Any, sync::{Arc, Mutex}, @@ -29,6 +21,13 @@ use std::{ }; use tokio::time::Instant; +use crate::{ + elements::elements::{Element, InteractableElement, JoinableElement}, + interaction_result::InteractionResult, + ui::FPS, + util::borders::draw_block_joins, +}; + pub struct ConsoleCard { focused: bool, pub title: String, @@ -425,7 +424,8 @@ pub async fn run_command(command: &str) { ping(time).await; } ["user", "add", username] => { - if let (Some(user), Some(_)) = user_manager::create_user(username).await { + if let (Some(user), Some(_)) = omikron_connector::user_ops::create_user(username).await + { log!("Created user {}", user.user_id); } else { log!("Failed to create user"); diff --git a/iota-cli/src/elements/elements.rs b/iota-cli/src/elements/elements.rs index 3429e52..abe9ab9 100644 --- a/iota-cli/src/elements/elements.rs +++ b/iota-cli/src/elements/elements.rs @@ -3,7 +3,7 @@ use std::any::Any; use crossterm::event::KeyEvent; use ratatui::{Frame, layout::Rect, widgets::Borders}; -use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen}; +use crate::{interaction_result::InteractionResult, screens::screens::Screen}; #[allow(unused)] pub trait Element: Send + Sync + Any { diff --git a/iota-cli/src/elements/graph_card.rs b/iota-cli/src/elements/graph_card.rs index d95f937..c7ec2d6 100644 --- a/iota-cli/src/elements/graph_card.rs +++ b/iota-cli/src/elements/graph_card.rs @@ -1,6 +1,7 @@ use std::{any::Any, sync::Arc}; use crossterm::event::KeyEvent; +use iota_state::APP_STATE; use ratatui::{ Frame, layout::Rect, @@ -12,13 +13,10 @@ use ratatui::{ }; use crate::{ - APP_STATE, - gui::{ - elements::elements::{Element, InteractableElement, JoinableElement}, - interaction_result::InteractionResult, - ui::UI, - util::borders::draw_block_joins, - }, + elements::elements::{Element, InteractableElement, JoinableElement}, + interaction_result::InteractionResult, + ui::UI, + util::borders::draw_block_joins, }; pub enum GRAPHS { diff --git a/iota-cli/src/elements/log_card.rs b/iota-cli/src/elements/log_card.rs index e2d4ba1..a0ce8fd 100755 --- a/iota-cli/src/elements/log_card.rs +++ b/iota-cli/src/elements/log_card.rs @@ -1,9 +1,9 @@ -use crate::APP_STATE; -use crate::gui::elements::elements::{Element, InteractableElement, JoinableElement}; -use crate::gui::interaction_result::InteractionResult; -use crate::gui::util::borders::draw_block_joins; -use crate::util::logger::PrintType; +use crate::app_state::APP_STATE; +use crate::elements::elements::{Element, InteractableElement, JoinableElement}; +use crate::interaction_result::InteractionResult; +use crate::util::borders::draw_block_joins; use crossterm::event::{KeyCode, KeyEvent}; +use iota_logger::PrintType; use ratatui::{ Frame, layout::Rect, @@ -90,7 +90,24 @@ impl LogCard { fn get_logs(&self) -> Vec { let state = APP_STATE.lock().unwrap(); - state.get_logs().iter().cloned().collect() + state + .get_logs() + .iter() + .map(|e| UiLogEntry { + timestamp_ms: e.timestamp_ms, + sender: match e.sender.as_str() { + "Call" => PrintType::Call, + "Client" => PrintType::Client, + "Iota" => PrintType::Iota, + "Omikron" => PrintType::Omikron, + "Omega" => PrintType::Omega, + "Command" => PrintType::Command, + _ => PrintType::General, + }, + message: e.message.clone(), + is_error: e.is_error, + }) + .collect() } fn find_split_point(s: &str, max_width: usize) -> usize { diff --git a/iota-cli/src/input_handler.rs b/iota-cli/src/input_handler.rs index 92b899c..524ce2e 100644 --- a/iota-cli/src/input_handler.rs +++ b/iota-cli/src/input_handler.rs @@ -1,6 +1,6 @@ -use crate::ui::{UI, UNIQUE}; -use crate::{RELOAD, SHUTDOWN}; +use crate::ui::UI; use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyModifiers, poll, read}; +use iota_state::{RELOAD, SHUTDOWN, UNIQUE}; use std::sync::Arc; use std::sync::atomic::Ordering; use std::time::Duration; diff --git a/iota-cli/src/screens/terms_checker.rs b/iota-cli/src/screens/terms_checker.rs index 0808ac5..0d64187 100644 --- a/iota-cli/src/screens/terms_checker.rs +++ b/iota-cli/src/screens/terms_checker.rs @@ -2,8 +2,13 @@ use crate::{ interaction_result::InteractionResult, screens::{md_viewer::FileViewer, screens::Screen}, ui::UI, + util::{ + buttons::{checkbox, draw_buttons}, + terms_focus::Focus, + }, }; use crossterm::event::{KeyCode, KeyEvent}; +use iota_terms::{TermsType, get_link, get_terms}; use ratatui::{ Frame, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -14,6 +19,13 @@ use ratatui::{ use std::{any::Any, pin::Pin, sync::Arc}; use tokio::sync::oneshot; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UserChoice { + Deny, + AcceptEULA, + AcceptAll, +} + pub struct TermsCheckerScreen { ui: Arc, sender: Option>, @@ -268,9 +280,9 @@ impl Screen for TermsCheckerScreen { } KeyCode::Char('o') | KeyCode::Char('O') => { let terms_type = match self.focus { - Focus::Eula => Some(Type::EULA), - Focus::Tos => Some(Type::TOS), - Focus::Pp => Some(Type::PP), + Focus::Eula => Some(TermsType::EULA), + Focus::Tos => Some(TermsType::TOS), + Focus::Pp => Some(TermsType::PP), _ => None, }; if let Some(terms_type) = terms_type { @@ -288,15 +300,15 @@ impl Screen for TermsCheckerScreen { } KeyCode::Char('l') | KeyCode::Char('L') => match self.focus { Focus::Eula => { - let _ = open::that(get_link(Type::EULA)); + let _ = open::that(get_link(TermsType::EULA)); InteractionResult::Handled } Focus::Tos => { - let _ = open::that(get_link(Type::TOS)); + let _ = open::that(get_link(TermsType::TOS)); InteractionResult::Handled } Focus::Pp => { - let _ = open::that(get_link(Type::PP)); + let _ = open::that(get_link(TermsType::PP)); InteractionResult::Handled } _ => InteractionResult::Unhandled, diff --git a/iota-cli/src/screens/terms_updater.rs b/iota-cli/src/screens/terms_updater.rs index 909da8d..ee91cba 100644 --- a/iota-cli/src/screens/terms_updater.rs +++ b/iota-cli/src/screens/terms_updater.rs @@ -1,9 +1,15 @@ +use crate::screens::terms_checker::UserChoice; use crate::{ interaction_result::InteractionResult, screens::{md_viewer::FileViewer, screens::Screen}, + util::{ + buttons::{checkbox, draw_buttons}, + terms_focus::Focus, + }, }; use chrono::{Local, TimeZone, Utc}; use crossterm::event::{KeyCode, KeyEvent}; +use iota_terms::{Doc, TermsType, get_newest_link, get_terms}; use ratatui::{ Frame, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -14,6 +20,13 @@ use ratatui::{ use std::any::Any; use tokio::sync::oneshot; +#[derive(Debug, Clone)] +pub enum UpdateDecision { + NoChange, + Future { newest: Doc }, + Forced(Doc), +} + pub struct TermsUpdaterScreen { sender: Option>, @@ -635,9 +648,9 @@ impl Screen for TermsUpdaterScreen { }, KeyCode::Char('o') | KeyCode::Char('O') => { let terms_type = match self.focus { - Focus::Eula => Some(Type::EULA), - Focus::Tos => Some(Type::TOS), - Focus::Pp => Some(Type::PP), + Focus::Eula => Some(TermsType::EULA), + Focus::Tos => Some(TermsType::TOS), + Focus::Pp => Some(TermsType::PP), _ => None, }; @@ -655,15 +668,15 @@ impl Screen for TermsUpdaterScreen { } KeyCode::Char('l') | KeyCode::Char('L') => match self.focus { Focus::Eula => { - let _ = open::that(get_newest_link(Type::EULA)); + let _ = open::that(get_newest_link(TermsType::EULA)); InteractionResult::Handled } Focus::Tos => { - let _ = open::that(get_newest_link(Type::TOS)); + let _ = open::that(get_newest_link(TermsType::TOS)); InteractionResult::Handled } Focus::Pp => { - let _ = open::that(get_newest_link(Type::PP)); + let _ = open::that(get_newest_link(TermsType::PP)); InteractionResult::Handled } _ => InteractionResult::Unhandled, diff --git a/iota-cli/src/ui.rs b/iota-cli/src/ui.rs index 71e9847..723babe 100644 --- a/iota-cli/src/ui.rs +++ b/iota-cli/src/ui.rs @@ -3,6 +3,7 @@ use crate::{ screens::screens::Screen, }; use crossterm::event::KeyEvent; +use iota_state::{ACTIVE_TASKS, SHUTDOWN, UNIQUE}; use once_cell::sync::Lazy; use ratatui::{Terminal, backend::CrosstermBackend, init}; use std::{ @@ -17,7 +18,6 @@ use std::{ use tokio::{sync::RwLock, time::Instant}; /// UI state and rendering -pub static UNIQUE: AtomicBool = AtomicBool::new(true); pub static FPS: Lazy> = Lazy::new(|| RwLock::new((0.0, 0.0))); diff --git a/iota-core/src/consent_state.rs b/iota-core/src/consent_state.rs new file mode 100644 index 0000000..723c5a7 --- /dev/null +++ b/iota-core/src/consent_state.rs @@ -0,0 +1,473 @@ +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use tokio::sync::oneshot; +use iota_cli::ui::UI; +use iota_cli::screens::terms_checker::{TermsCheckerScreen, UserChoice}; +use iota_cli::screens::terms_updater::{TermsUpdaterScreen, UpdateDecision}; +use iota_terms::{Doc, get_current_docs, get_newest_docs, TermsType as Type}; +use iota_util::file_util::{load_file, save_file}; + + +pub async fn check(ui: Arc) -> (bool, bool) { + let mut state = ConsentState::load_state(); + + if ensure_initial_consent(ui.clone(), &mut state) + .await + .is_err() + { + return (false, false); + } + if ensure_updates(ui, &mut state).await.is_err() { + return (false, false); + }; + + state = state.sanitize(); + state.save_state(); + + (state.accepted_eula, state.accepted_tos && state.accepted_pp) +} + +async fn ensure_initial_consent(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { + if state.accepted_eula { + return Ok(()); + } + + let (tx, rx) = oneshot::channel(); + + ui.set_screen(Box::new(TermsCheckerScreen::new(ui.clone(), Some(tx)))) + .await; + + let result = rx.await.unwrap_or(UserChoice::Deny); + + match result { + UserChoice::AcceptEULA | UserChoice::AcceptAll => { + if let Some((eula, tos, privacy)) = get_current_docs().await { + state.accepted_eula = true; + state.eula = Some(eula); + + if matches!(result, UserChoice::AcceptAll) { + state.accepted_tos = true; + state.accepted_pp = true; + state.tos = Some(tos); + state.privacy = Some(privacy); + } + } + + let _ = &state.save_state(); + Ok(()) + } + UserChoice::Deny => Err(()), + } +} +async fn ensure_updates(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { + let Some((eula_update, tos_update, privacy_update)) = get_updates().await else { + return Ok(()); + }; + + let is_forced = matches!(eula_update, UpdateDecision::Forced(_)) + || matches!(tos_update, UpdateDecision::Forced(_)) + || matches!(privacy_update, UpdateDecision::Forced(_)); + + let (tx, rx) = oneshot::channel(); + + ui.set_screen(Box::new(TermsUpdaterScreen::new( + eula_update.clone(), + tos_update.clone(), + privacy_update.clone(), + Some(tx), + ))) + .await; + + let result = rx.await.unwrap_or(UserChoice::Deny); + + if is_forced { + match result { + UserChoice::AcceptAll => { + state.accepted_eula = true; + state.accepted_tos = true; + state.accepted_pp = true; + } + UserChoice::AcceptEULA => { + state.accepted_eula = true; + } + UserChoice::Deny => return Err(()), + } + } else { + apply_future_updates(state, result, eula_update, tos_update, privacy_update); + } + + state.save_state(); + Ok(()) +} +fn apply_future_updates( + state: &mut ConsentState, + result: UserChoice, + eula_update: UpdateDecision, + tos_update: UpdateDecision, + privacy_update: UpdateDecision, +) { + match result { + UserChoice::AcceptAll => { + if let UpdateDecision::Future { newest } = eula_update { + state.future_eula = Some(newest); + } + if let UpdateDecision::Future { newest } = tos_update { + state.future_tos = Some(newest); + } + if let UpdateDecision::Future { newest } = privacy_update { + state.future_privacy = Some(newest); + } + } + UserChoice::AcceptEULA => { + if let UpdateDecision::Future { newest } = eula_update { + state.future_eula = Some(newest); + } + } + UserChoice::Deny => {} + } +} + +async fn get_updates() -> Option<( + // Ok(None) indicates no update + // Ok(Some) Indicates a future update + // Err indicates a update that has to be accepted before the programm can continue + UpdateDecision, + UpdateDecision, + UpdateDecision, +)> { + if let ( + Some((current_eula, current_tos, current_privacy)), + Some((newest_eula, newest_tos, newest_privacy)), + ) = (get_current_docs().await, get_newest_docs().await) + { + let file = load_file("", "agreements"); + let accepted_state = ConsentState::from_str(&file).sanitize(); + save_file("", "agreements", &accepted_state.to_string()); + + let eula_update: UpdateDecision = if current_eula.equals_some(&accepted_state.eula) { + if current_eula.equals(&newest_eula) { + UpdateDecision::NoChange + } else { + if newest_eula.equals_some(&accepted_state.future_eula) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { + newest: newest_eula, + } + } + } + } else if newest_eula.equals_some(&accepted_state.eula) { + UpdateDecision::NoChange + } else { + UpdateDecision::Forced(current_eula) + }; + + let tos_update: UpdateDecision = + if !accepted_state.accepted_tos || newest_tos.equals_some(&accepted_state.tos) { + UpdateDecision::NoChange + } else if accepted_state.accepted_tos && current_tos.equals_some(&accepted_state.tos) { + if current_tos.equals(&newest_tos) { + UpdateDecision::NoChange + } else { + if newest_tos.equals_some(&accepted_state.future_tos) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { newest: newest_tos } + } + } + } else { + UpdateDecision::Forced(current_tos) + }; + + let privacy_update: UpdateDecision = if !accepted_state.accepted_pp + || newest_privacy.equals_some(&accepted_state.privacy) + { + UpdateDecision::NoChange + } else if accepted_state.accepted_pp && current_privacy.equals_some(&accepted_state.privacy) + { + if current_privacy.equals(&newest_privacy) { + UpdateDecision::NoChange + } else { + if newest_privacy.equals_some(&accepted_state.future_privacy) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { + newest: newest_privacy, + } + } + } + } else { + UpdateDecision::Forced(current_privacy) + }; + match (&eula_update, &tos_update, &privacy_update) { + (&UpdateDecision::NoChange, &UpdateDecision::NoChange, &UpdateDecision::NoChange) => { + None + } + _ => Some((eula_update, tos_update, privacy_update)), + } + } else { + None + } +} + + +#[derive(Debug, Clone)] +pub struct ConsentState { + pub eula: Option, + pub accepted_eula: bool, + pub future_eula: Option, + + pub tos: Option, + pub accepted_tos: bool, + pub future_tos: Option, + + pub privacy: Option, + pub accepted_pp: bool, + pub future_privacy: Option, +} + +impl ConsentState { + fn sanitize(mut self) -> Self { + let current_secs = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + if let Some(future_eula) = self.future_eula.clone() { + if future_eula.get_time() < current_secs { + self.eula = Some(future_eula); + self.future_eula = None; + } + } + if let Some(future_tos) = self.future_tos.clone() { + if future_tos.get_time() < current_secs { + self.tos = Some(future_tos); + self.future_tos = None; + } + } + if let Some(future_privacy) = self.future_privacy.clone() { + if future_privacy.get_time() < current_secs { + self.privacy = Some(future_privacy); + self.future_privacy = None; + } + } + + if !self.accepted_eula { + self.accepted_tos = false; + self.accepted_pp = false; + } + self + } + + pub fn load_state() -> ConsentState { + let file = load_file("", "agreements"); + ConsentState::from_str(&file).sanitize() + } + + pub fn save_state(&self) { + save_file("", "agreements", &self.to_string()); + } + + fn to_string(&self) -> String { + let current_secs = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let mut file_out: String = format!( + "This file reflects the current consent state used by the application.\ + \nIt may be regenerated or overwritten by the application.\ + \nThis file was last edited by Tensamin at:\ + \nUNIX-SECOND={}", + current_secs + ); + + if let Some(eula) = &self.eula { + file_out.push_str(&format!("\ + \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence agreement. You can find our EULA at https://legal.tensamin.net/eula/\ + \nEULA={}\ + \nEULA-VERSION={}\ + \nEULA-HASH={}\ + ", self.accepted_eula, eula.get_version(), eula.get_hash())); + + if self.accepted_tos + && let Some(tos) = &self.tos + { + file_out.push_str(&format!("\ + \n\"Terms-of-Service=true\" indicates that you read, understood and accepted Tensamin's Terms of Service. You can find our Terms of Serivce at https://legal.tensamin.net/tos/\ + \nTerms-of-Service={}\ + \nTerms-of-Service-VERSION={}\ + \nTerms-of-Service-HASH={}\ + ", self.accepted_tos, tos.get_version(), tos.get_hash())); + } + if self.accepted_pp + && let Some(pp) = &self.privacy + { + file_out.push_str(&format!("\ + \n\"Privacy-Policy=true\" indicates that you read, understood and accepted Tensamin's Privacy Policy. You can find our Privacy Policy at https://legal.tensamin.net/privacy/\ + \nPrivacy-Policy={}\ + \nPrivacy-Policy-VERSION={}\ + \nPrivacy-Policy-HASH={}\ + ", self.accepted_pp, pp.get_version(), pp.get_hash())); + } + } else { + file_out.push_str("\ + \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence Agreement. You can find Tensamin's EULA at https://legal.tensamin.net/eula/\ + \nEULA=false\ + "); + } + + if let Some(eula) = &self.future_eula { + file_out.push_str(&format!( + "\ + \nFUTURE-EULA-VERSION={}\ + \nFUTURE-EULA-HASH={}\ + \nFUTURE-EULA-TIME={}\ + ", + eula.get_version(), + eula.get_hash(), + eula.get_time() + )); + } + if let Some(tos) = &self.future_tos { + file_out.push_str(&format!( + "\ + \nFUTURE-Terms-of-Service-VERSION={}\ + \nFUTURE-Terms-of-Service-HASH={}\ + \nFUTURE-Terms-of-Service-TIME={}\ + ", + tos.get_version(), + tos.get_hash(), + tos.get_time() + )); + } + if let Some(pp) = &self.future_privacy { + file_out.push_str(&format!( + "\ + \nFUTURE-Privacy-Policy-VERSION={}\ + \nFUTURE-Privacy-Policy-HASH={}\ + \nFUTURE-Privacy-Policy-TIME={}\ + ", + pp.get_version(), + pp.get_hash(), + pp.get_time() + )); + } + + file_out + } + + fn from_str(s: &str) -> Self { + let mut eula = false; + let mut eula_version = String::new(); + let mut eula_hash = String::new(); + let mut pp = false; + let mut pp_version = String::new(); + let mut pp_hash = String::new(); + let mut tos = false; + let mut tos_version = String::new(); + let mut tos_hash = String::new(); + + let mut future_eula_version = String::new(); + let mut future_eula_hash = String::new(); + let mut future_eula_time = String::new(); + + let mut future_tos_version = String::new(); + let mut future_tos_hash = String::new(); + let mut future_tos_time = String::new(); + + let mut future_pp_version = String::new(); + let mut future_pp_hash = String::new(); + let mut future_pp_time = String::new(); + + let mut unix = String::new(); + + for line in s.lines() { + if let Some(v) = line.strip_prefix("EULA=") { + eula = v == "true"; + } else if let Some(v) = line.strip_prefix("EULA-VERSION=") { + eula_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("EULA-HASH=") { + eula_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("Terms-of-Service=") { + tos = v == "true"; + } else if let Some(v) = line.strip_prefix("Terms-of-Service-VERSION=") { + tos_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("Terms-of-Service-HASH=") { + tos_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("Privacy-Policy=") { + pp = v == "true"; + } else if let Some(v) = line.strip_prefix("Privacy-Policy-VERSION=") { + pp_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("Privacy-Policy-HASH=") { + pp_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("UNIX-SECOND=") { + unix = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-VERSION=") { + future_eula_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-HASH=") { + future_eula_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-TIME=") { + future_eula_time = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-VERSION=") { + future_tos_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-HASH=") { + future_tos_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-TIME=") { + future_tos_time = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-VERSION=") { + future_pp_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-HASH=") { + future_pp_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-TIME=") { + future_pp_time = v.to_string(); + } + } + let unix: u64 = unix.parse::().unwrap_or(0); + let future_eula_time = future_eula_time.parse::().unwrap_or(0); + let future_tos_time = future_tos_time.parse::().unwrap_or(0); + let future_pp_time = future_pp_time.parse::().unwrap_or(0); + let state = Self { + accepted_eula: eula, + eula: Some(Doc::new(eula_version, eula_hash, Type::EULA, unix)), + accepted_pp: pp, + privacy: Some(Doc::new(pp_version, pp_hash, Type::PP, unix)), + accepted_tos: tos, + tos: Some(Doc::new(tos_version, tos_hash, Type::TOS, unix)), + future_eula: if !future_eula_version.is_empty() { + Some(Doc::new( + future_eula_version, + future_eula_hash, + Type::EULA, + future_eula_time, + )) + } else { + None + }, + future_tos: if !future_tos_version.is_empty() { + Some(Doc::new( + future_tos_version, + future_tos_hash, + Type::TOS, + future_tos_time, + )) + } else { + None + }, + future_privacy: if !future_pp_version.is_empty() { + Some(Doc::new( + future_pp_version, + future_pp_hash, + Type::PP, + future_pp_time, + )) + } else { + None + }, + } + .sanitize(); + + state + } +} diff --git a/iota-core/src/main.rs b/iota-core/src/main.rs index f8f4847..6e4a035 100644 --- a/iota-core/src/main.rs +++ b/iota-core/src/main.rs @@ -1,8 +1,19 @@ +mod consent_state; use pnet::datalink::NetworkInterface; use tokio::time::{Duration, sleep}; use iota_state::{ACTIVE_TASKS, APP_STATE, AppState, RELOAD, SHUTDOWN}; +use iota_cli::screens::main_screen::MainScreen; +use iota_cli::ui::start_tui; +use iota_logger as logger; +use iota_logger::{log, log_t}; +use iota_storage::users::user_manager; +use iota_storage::util::config_util::CONFIG; +use iota_util::file_util::{download_and_extract_zip, has_dir}; +use iota_util::langu::language_creator; +use omikron_connector as omikron; + #[tokio::main(flavor = "multi_thread", worker_threads = 16)] #[allow(unused_must_use, dead_code)] async fn main() { diff --git a/iota-logger/Cargo.toml b/iota-logger/Cargo.toml index a07b745..f03eac3 100644 --- a/iota-logger/Cargo.toml +++ b/iota-logger/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +ratatui = "0.30.0" +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } diff --git a/iota-logger/src/lib.rs b/iota-logger/src/lib.rs index a5feb02..8a4b8b0 100644 --- a/iota-logger/src/lib.rs +++ b/iota-logger/src/lib.rs @@ -11,11 +11,8 @@ use std::{ use ratatui::style::Color; use ttp_core::{CommunicationValue, DataTypes, DataValue}; -use crate::{ - APP_STATE, - gui::{elements::log_card::LogEntry, ui::UNIQUE}, - langu::language_manager, -}; +use iota_state::{APP_STATE, UNIQUE, UiLogEntry}; +use iota_util::langu::language_manager; static LOGGER: OnceLock> = OnceLock::new(); @@ -83,7 +80,6 @@ pub fn startup() { }; let timestamp = format_timestamp_inline(msg.timestamp_ms); - let entry = LogEntry::new(msg.kind, resolved_message, msg.is_error); let prefix = if msg.prefix.is_empty() { String::new() @@ -96,13 +92,20 @@ pub fn startup() { "{} {}{}", fixed_box(&msg.timestamp_ms.to_string(), 13), prefix, - entry.message + resolved_message ); let _ = writeln!(file, " {}", timestamp); + let entry = UiLogEntry { + timestamp_ms: msg.timestamp_ms, + sender: format!("{:?}", msg.kind), + message: resolved_message, + is_error: msg.is_error, + }; + let mut state = APP_STATE.lock().unwrap(); - state.push_log(entry.into()); + state.push_log(entry); } }); } @@ -186,8 +189,8 @@ pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: St #[macro_export] macro_rules! log_t { ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), false, $key, @@ -196,8 +199,8 @@ macro_rules! log_t { }; ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), false, $key, @@ -209,8 +212,8 @@ macro_rules! log_t { #[macro_export] macro_rules! log_t_err { ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), true, $key, @@ -219,8 +222,8 @@ macro_rules! log_t_err { }; ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), true, $key, @@ -233,8 +236,8 @@ macro_rules! log_t_err { #[macro_export] macro_rules! log_command { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::Command, + $crate::log_internal( + $crate::PrintType::Command, "".to_string(), false, format!($($arg)*) @@ -246,8 +249,8 @@ macro_rules! log_command { #[macro_export] macro_rules! log { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, "".to_string(), false, format!($($arg)*) @@ -259,8 +262,8 @@ macro_rules! log { #[macro_export] macro_rules! log_in { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, ">".to_string(), false, format!($($arg)*) @@ -272,8 +275,8 @@ macro_rules! log_in { #[macro_export] macro_rules! log_out { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, "<".to_string(), false, format!($($arg)*) @@ -285,8 +288,8 @@ macro_rules! log_out { #[macro_export] macro_rules! log_err { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, ">>".to_string(), true, format!($($arg)*) @@ -404,29 +407,29 @@ fn format_array(arr: Vec) -> String { #[macro_export] macro_rules! log_cv { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, Some($kind)) + $crate::log_cv_internal("", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, None) + $crate::log_cv_internal("", &$cv, None) }; } #[macro_export] macro_rules! log_cv_in { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, Some($kind)) + $crate::log_cv_internal("> ", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, None) + $crate::log_cv_internal("> ", &$cv, None) }; } #[macro_export] macro_rules! log_cv_out { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, Some($kind)) + $crate::log_cv_internal("< ", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, None) + $crate::log_cv_internal("< ", &$cv, None) }; } diff --git a/iota-state/src/lib.rs b/iota-state/src/lib.rs index 5d8d351..1e5d1c2 100644 --- a/iota-state/src/lib.rs +++ b/iota-state/src/lib.rs @@ -2,7 +2,7 @@ use dashmap::DashSet; use json::{JsonValue, object}; use once_cell::sync::Lazy; use std::collections::VecDeque; -use std::sync::{Arc, LazyLock, Mutex}; +use std::sync::{Arc, LazyLock, Mutex, atomic::AtomicBool}; use std::thread; use std::time::Duration; use sysinfo::{RefreshKind, System}; @@ -11,6 +11,8 @@ use tokio::sync::RwLock; pub const MAX_POINTS: usize = 1000; pub const MAX_LOGS: usize = 100; +pub static UNIQUE: AtomicBool = AtomicBool::new(true); + #[derive(Clone, Debug)] pub struct UiLogEntry { pub timestamp_ms: u128, diff --git a/iota-storage/Cargo.toml b/iota-storage/Cargo.toml index b62ac11..6bab29e 100644 --- a/iota-storage/Cargo.toml +++ b/iota-storage/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-logger = { path = "../iota-logger" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } + ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/iota-storage/src/lib.rs b/iota-storage/src/lib.rs index 778de0f..7f0e8ef 100644 --- a/iota-storage/src/lib.rs +++ b/iota-storage/src/lib.rs @@ -1,2 +1,2 @@ -mod users; -mod util; +pub mod users; +pub mod util; diff --git a/iota-storage/src/users/user_community_util.rs b/iota-storage/src/users/user_community_util.rs index 45b036c..6f01e74 100644 --- a/iota-storage/src/users/user_community_util.rs +++ b/iota-storage/src/users/user_community_util.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::save_file; +use iota_util::file_util::save_file; use json::{self, Array, JsonValue}; use std::fs; use std::path::Path; diff --git a/iota-storage/src/users/user_manager.rs b/iota-storage/src/users/user_manager.rs index bcb5e26..add6ea4 100644 --- a/iota-storage/src/users/user_manager.rs +++ b/iota-storage/src/users/user_manager.rs @@ -1,12 +1,9 @@ -use crate::omikron::omikron_connection::OMIKRON_CONNECTION; use crate::users::user_profile::UserProfile; -use crate::util::crypto_helper::{self, public_key_to_base64}; -use crate::util::file_util::{load_file, save_file}; -use crate::util::logger::PrintType; -use crate::{RELOAD, SHUTDOWN}; -use crate::{log, log_cv}; use base64::{Engine as _, engine::general_purpose::STANDARD}; use hex::{self}; +use iota_logger::{log, log_cv}; +use iota_util::crypto_helper::{self, public_key_to_base64}; +use iota_util::file_util::{load_file, save_file}; use json::JsonValue; use once_cell::sync::Lazy; use rand::Rng; @@ -48,84 +45,7 @@ pub async fn load_from_tu(username: &str) -> Result<(), ()> { Ok(()) } -pub async fn create_user(username: &str) -> (Option, Option) { - let register_cv = CommunicationValue::new(CommunicationType::get_register); - - let conn = OMIKRON_CONNECTION.clone(); - - let response_cv = match conn - .await_response(®ister_cv, Some(Duration::from_secs(20))) - .await - { - Ok(cv) => cv, - Err(_) => return (None, None), - }; - log_cv!(PrintType::Omega, response_cv); - - let user_id = match response_cv.get_data(DataTypes::user_id).as_number() { - Some(id) => id, - None => return (None, None), - }; - let mut buf = [0u8; 56]; - let mut rng = OsRng; - rng.fill_bytes(&mut buf); - let private_key = Secret::from_bytes(&buf).unwrap(); - let public_key = PublicKey::from(&private_key); - - let mut hasher = Sha256::new(); - hasher.update(&STANDARD.encode(&private_key.as_bytes()).as_bytes()); - let result = hasher.finalize(); - let private_key_hash = hex::encode(result); - - let mut bytes = [0u8; 192]; - OsRng.fill(bytes.as_mut()); - let reset_token = STANDARD.encode(&bytes); - - let up = UserProfile::new( - user_id, - username.to_string(), - None, - STANDARD.encode(&public_key.as_bytes()), - private_key_hash, - reset_token.clone(), - ); - - let cv = CommunicationValue::new(CommunicationType::complete_register_user) - .add_data(DataTypes::user_id, DataValue::Number(user_id)) - .add_data(DataTypes::username, DataValue::Str(username.to_string())) - .add_data( - DataTypes::public_key, - DataValue::Str(public_key_to_base64(&public_key)), - ) - .add_data(DataTypes::iota_id, DataValue::Number(user_id)) - .add_data(DataTypes::reset_token, DataValue::Str(reset_token)); - - let response_cv = conn - .await_response(&cv, Some(Duration::from_secs(20))) - .await; - - if let Ok(resp) = response_cv { - log_cv!(PrintType::Omega, resp); - if !resp.is_type(CommunicationType::success) { - return (None, None); - } - } else { - return (None, None); - } - *SHUTDOWN.write().await = true; - *RELOAD.write().await = true; - log!("Created User"); - save_file( - "", - &format!("{}.tu", username), - &format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())), - ); - - USERS.lock().unwrap().push(up.clone()); - save_users(); - (Some(up), Some(STANDARD.encode(&private_key.as_bytes()))) -} - +pub fn add_user(user: UserProfile) { USERS.lock().unwrap().push(user); } pub fn get_user_by_username(username: &str) -> Option { USERS .lock() diff --git a/iota-storage/src/users/user_profile.rs b/iota-storage/src/users/user_profile.rs index 5d60277..ba413ff 100644 --- a/iota-storage/src/users/user_profile.rs +++ b/iota-storage/src/users/user_profile.rs @@ -1,6 +1,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; -use crate::util::file_util::{has_file, load_file, used_dir_space}; +use iota_util::file_util::{has_file, load_file, used_dir_space}; use base64::{Engine as _, engine::general_purpose}; use json::{JsonValue, object}; use rand::Rng; diff --git a/iota-storage/src/util/chat_files.rs b/iota-storage/src/util/chat_files.rs index e54fe29..143aa14 100644 --- a/iota-storage/src/util/chat_files.rs +++ b/iota-storage/src/util/chat_files.rs @@ -1,5 +1,5 @@ -use crate::log; use crate::util::db; +use iota_logger::log; use json::{JsonValue, array, object}; use rusqlite::params; use std::io; diff --git a/iota-storage/src/util/config_util.rs b/iota-storage/src/util/config_util.rs index 6330b59..0ad7827 100644 --- a/iota-storage/src/util/config_util.rs +++ b/iota-storage/src/util/config_util.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::{load_file, save_file}; +use iota_util::file_util::{load_file, save_file}; use json::JsonValue; use once_cell::sync::Lazy; use tokio::sync::RwLock; diff --git a/iota-storage/src/util/db.rs b/iota-storage/src/util/db.rs index 9fb40a0..eb48400 100644 --- a/iota-storage/src/util/db.rs +++ b/iota-storage/src/util/db.rs @@ -5,7 +5,7 @@ //! reuse. The goal is to centralize the "open and initialize" logic and //! provide small convenience helpers used by other util modules. -use crate::util::file_util::get_directory; +use iota_util::file_util::get_directory; use rusqlite::{Connection, Error as RusqliteError}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; diff --git a/iota-storage/src/util/mod.rs b/iota-storage/src/util/mod.rs index 47901f9..dff0d65 100644 --- a/iota-storage/src/util/mod.rs +++ b/iota-storage/src/util/mod.rs @@ -2,8 +2,4 @@ pub mod chat_files; pub mod chats_util; pub mod communities_util; pub mod config_util; -pub mod crypto_helper; -pub mod crypto_util; pub mod db; -pub mod file_util; -pub mod logger; diff --git a/iota-terms/Cargo.toml b/iota-terms/Cargo.toml index 070687c..607dce1 100644 --- a/iota-terms/Cargo.toml +++ b/iota-terms/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } json = "*" reqwest = "0.13.2" diff --git a/iota-terms/src/doc.rs b/iota-terms/src/doc.rs index 2365ba3..0c2e0d2 100644 --- a/iota-terms/src/doc.rs +++ b/iota-terms/src/doc.rs @@ -1,6 +1,7 @@ use json::{JsonValue, object::Object}; -use crate::{terms::terms_getter::Type, util::file_util::load_file}; +use crate::terms_getter::Type; +use iota_util::file_util::load_file; #[derive(Clone, Debug, PartialEq, Eq)] #[allow(unused)] diff --git a/iota-terms/src/lib.rs b/iota-terms/src/lib.rs index b03efc9..4d99cc6 100644 --- a/iota-terms/src/lib.rs +++ b/iota-terms/src/lib.rs @@ -1,2 +1,14 @@ -pub mod doc; + + pub mod terms_getter; + +pub use terms_getter::Type as TermsType; +pub use terms_getter::get_current_docs; +pub use terms_getter::get_link; +pub use terms_getter::get_newest_docs; +pub use terms_getter::get_newest_link; +pub use terms_getter::get_terms; + +pub mod doc; + +pub use doc::Doc; diff --git a/iota-terms/src/terms_getter.rs b/iota-terms/src/terms_getter.rs index a0fa53b..65de9b1 100755 --- a/iota-terms/src/terms_getter.rs +++ b/iota-terms/src/terms_getter.rs @@ -1,6 +1,6 @@ use json::JsonValue::Object; -use crate::terms::doc::Doc; +use crate::doc::Doc; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Type { diff --git a/iota-util/Cargo.toml b/iota-util/Cargo.toml index 369ad84..77ecde1 100644 --- a/iota-util/Cargo.toml +++ b/iota-util/Cargo.toml @@ -13,3 +13,15 @@ pnet = "0.35.0" ratatui = "0.30.0" reqwest = "0.13.2" tokio = { version = "1.50.0", features = ["full"] } +sysinfo = "0.38.3" +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +zip = "6.0.0" +aes-gcm = "0.10.3" +base64 = "0.22.1" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +sha2 = "0.10.9" +x448 = { version = "*" } +hkdf = "0.12.4" +once_cell = "1.21.3" +hex = "*" diff --git a/iota-util/src/file_util.rs b/iota-util/src/file_util.rs index 2d00718..1326feb 100755 --- a/iota-util/src/file_util.rs +++ b/iota-util/src/file_util.rs @@ -9,7 +9,7 @@ use uuid::Uuid; use walkdir::WalkDir; use zip::ZipArchive; -use crate::log; + #[allow(dead_code)] pub fn delete_directory(path: &str) -> bool { @@ -23,7 +23,7 @@ fn delete_dir_recursive(directory: &Path) -> bool { return false; } if let Err(e) = fs::remove_dir_all(directory) { - log!( + println!( "[IMPORTANT] Couldn't delete directory {}: {}", directory.display(), e, @@ -97,7 +97,7 @@ pub fn load_file(path: &str, name: &str) -> String { if !dir.exists() { if let Err(e) = fs::create_dir_all(&dir) { - log!("[IMPORTANT] Couldn't create directories: {}", e); + println!("[IMPORTANT] Couldn't create directories: {}", e); return String::new(); } return String::new(); @@ -105,7 +105,7 @@ pub fn load_file(path: &str, name: &str) -> String { if !file_path.exists() { if let Err(e) = File::create(&file_path) { - log!("[IMPORTANT] Couldn't create file: {}", e); + println!("[IMPORTANT] Couldn't create file: {}", e); } return String::new(); } @@ -130,13 +130,13 @@ pub fn save_file(path: &str, name: &str, value: &str) { if !dir.exists() { if let Err(e) = fs::create_dir_all(&dir) { - log!("[IMPORTANT] Couldn't create directories: {}", e); + println!("[IMPORTANT] Couldn't create directories: {}", e); return; } } if let Err(e) = fs::write(&file_path, value) { - log!( + println!( "[IMPORTANT] Couldn't write file {}: {}", file_path.display(), e @@ -231,7 +231,7 @@ pub async fn download_zip(url: &str, zip_path: &Path) -> Result<(), Box true, Err(e) => { - log!("Error during ZIP extraction: {}", e); + println!("Error during ZIP extraction: {}", e); false } }; if let Err(e) = tokio::fs::remove_file(&zip_path).await { - log!("Error cleaning up ZIP file {}: {}", zip_path.display(), e); + println!("Error cleaning up ZIP file {}: {}", zip_path.display(), e); } else if successful { - log!("Downloaded and extracted ZIP file successfully."); + println!("Downloaded and extracted ZIP file successfully."); } } diff --git a/iota-cli/src/langu/language_creator.rs b/iota-util/src/langu/language_creator.rs similarity index 98% rename from iota-cli/src/langu/language_creator.rs rename to iota-util/src/langu/language_creator.rs index fc6d1c5..e740e5b 100644 --- a/iota-cli/src/langu/language_creator.rs +++ b/iota-util/src/langu/language_creator.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::save_file; +use crate::file_util::save_file; use json::{self, JsonError, JsonValue}; pub fn create_languages() -> Result<(), JsonError> { diff --git a/iota-cli/src/langu/language_manager.rs b/iota-util/src/langu/language_manager.rs similarity index 98% rename from iota-cli/src/langu/language_manager.rs rename to iota-util/src/langu/language_manager.rs index c903886..0dcfa70 100644 --- a/iota-cli/src/langu/language_manager.rs +++ b/iota-util/src/langu/language_manager.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::{self}; +use crate::file_util::{self}; use json::parse; use once_cell::sync::Lazy; use std::collections::HashMap; diff --git a/iota-cli/src/langu/mod.rs b/iota-util/src/langu/mod.rs similarity index 100% rename from iota-cli/src/langu/mod.rs rename to iota-util/src/langu/mod.rs diff --git a/iota-util/src/lib.rs b/iota-util/src/lib.rs index e69de29..d104f80 100644 --- a/iota-util/src/lib.rs +++ b/iota-util/src/lib.rs @@ -0,0 +1,4 @@ +pub mod crypto_helper; +pub mod crypto_util; +pub mod file_util; +pub mod langu; diff --git a/omikron-connector/Cargo.toml b/omikron-connector/Cargo.toml index 89aa2d4..41f7d55 100644 --- a/omikron-connector/Cargo.toml +++ b/omikron-connector/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-logger = { path = "../iota-logger" } +iota-state = { path = "../iota-state" } +iota-storage = { path = "../iota-storage" } +iota-util = { path = "../iota-util" } ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } @@ -11,3 +15,8 @@ dashmap = "6.1.0" json = "*" tokio = { version = "1.50.0", features = ["full"] } uuid = { version = "*", features = ["v4"] } +base64 = "0.22.1" +hex = "*" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +sha2 = "0.10.9" +x448 = { version = "*" } diff --git a/omikron-connector/src/lib.rs b/omikron-connector/src/lib.rs index acb0f59..5d9124d 100644 --- a/omikron-connector/src/lib.rs +++ b/omikron-connector/src/lib.rs @@ -1,2 +1,3 @@ pub mod omikron_connection; pub mod ping_pong_task; +pub mod user_ops; diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index 240da6f..def2cc6 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -1,12 +1,14 @@ -use crate::users::contact::Contact; -use crate::util::chat_files::{MessageState, change_message_state}; -use crate::util::chats_util::{get_user, mod_user}; -use crate::util::communities_util::CommunitiesUtil; -use crate::util::crypto_util::{DataFormat, SecurePayload}; -use crate::util::file_util::{get_children, load_file, save_file}; -use crate::util::{chat_files, chats_util}; -use crate::util::{config_util::CONFIG, crypto_helper}; -use crate::{ACTIVE_TASKS, SHUTDOWN, log, log_cv_in, log_cv_out, log_t}; +use iota_storage::users::contact::Contact; +use iota_storage::util::chat_files::{MessageState, change_message_state}; +use iota_storage::util::chats_util::{get_user, mod_user}; +use iota_storage::util::communities_util::CommunitiesUtil; +use iota_util::crypto_util::{DataFormat, SecurePayload}; +use iota_util::file_util::{get_children, load_file, save_file}; +use iota_storage::util::{chat_files, chats_util}; +use iota_storage::util::config_util::CONFIG; +use iota_util::crypto_helper; +use iota_state::{ACTIVE_TASKS, SHUTDOWN}; +use iota_logger::{log, log_cv_in, log_cv_out, log_t}; use dashmap::DashMap; use json::JsonValue; use std::collections::HashMap; diff --git a/omikron-connector/src/ping_pong_task.rs b/omikron-connector/src/ping_pong_task.rs index f1a891f..26bec38 100644 --- a/omikron-connector/src/ping_pong_task.rs +++ b/omikron-connector/src/ping_pong_task.rs @@ -1,5 +1,6 @@ -use crate::omikron::omikron_connection::OmikronConnection; -use crate::{APP_STATE, log}; +use crate::omikron_connection::OmikronConnection; +use iota_state::APP_STATE; +use iota_logger::log; use dashmap::DashMap; use std::sync::LazyLock; use std::time::Instant; diff --git a/omikron-connector/src/user_ops.rs b/omikron-connector/src/user_ops.rs new file mode 100644 index 0000000..1c34670 --- /dev/null +++ b/omikron-connector/src/user_ops.rs @@ -0,0 +1,93 @@ +use base64::{Engine as _, engine::general_purpose::STANDARD}; +use hex; +use iota_logger::{PrintType, log, log_cv}; +use iota_state::{RELOAD, SHUTDOWN}; +use iota_storage::users::user_manager::{add_user, save_users}; +use iota_storage::users::user_profile::UserProfile; +use iota_util::crypto_helper::public_key_to_base64; +use iota_util::file_util::save_file; +use rand_core::{OsRng, RngCore}; +use sha2::{Digest, Sha256}; +use std::time::Duration; +use ttp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue}; +use x448::{PublicKey, Secret}; + +use crate::omikron_connection::OMIKRON_CONNECTION; + +pub async fn create_user(username: &str) -> (Option, Option) { + let register_cv = CommunicationValue::new(CommunicationType::get_register); + + let conn = OMIKRON_CONNECTION.clone(); + + let response_cv = match conn + .await_response(®ister_cv, Some(Duration::from_secs(20))) + .await + { + Ok(cv) => cv, + Err(_) => return (None, None), + }; + log_cv!(PrintType::Omega, response_cv); + + let user_id = match response_cv.get_data(DataTypes::user_id).as_number() { + Some(id) => id, + None => return (None, None), + }; + let mut buf = [0u8; 56]; + let mut rng = OsRng; + rng.fill_bytes(&mut buf); + let private_key = Secret::from_bytes(&buf).unwrap(); + let public_key = PublicKey::from(&private_key); + + let mut hasher = Sha256::new(); + hasher.update(&STANDARD.encode(&private_key.as_bytes()).as_bytes()); + let result = hasher.finalize(); + let private_key_hash = hex::encode(result); + + let mut bytes = [0u8; 192]; + OsRng.fill_bytes(&mut bytes); + let reset_token = STANDARD.encode(&bytes); + + let up = UserProfile::new( + user_id, + username.to_string(), + None, + STANDARD.encode(&public_key.as_bytes()), + private_key_hash, + reset_token.clone(), + ); + + let cv = CommunicationValue::new(CommunicationType::complete_register_user) + .add_data(DataTypes::user_id, DataValue::Number(user_id)) + .add_data(DataTypes::username, DataValue::Str(username.to_string())) + .add_data( + DataTypes::public_key, + DataValue::Str(public_key_to_base64(&public_key)), + ) + .add_data(DataTypes::iota_id, DataValue::Number(user_id)) + .add_data(DataTypes::reset_token, DataValue::Str(reset_token)); + + let response_cv = conn + .await_response(&cv, Some(Duration::from_secs(20))) + .await; + + if let Ok(resp) = response_cv { + log_cv!(PrintType::Omega, resp); + if !resp.is_type(CommunicationType::success) { + return (None, None); + } + } else { + return (None, None); + } + *SHUTDOWN.write().await = true; + *RELOAD.write().await = true; + log!("Created User"); + save_file( + "", + &format!("{}.tu", username), + &format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())), + ); + + add_user(up.clone()); + save_users(); + (Some(up), Some(STANDARD.encode(&private_key.as_bytes()))) +} diff --git a/web-ui/Cargo.toml b/web-ui/Cargo.toml index 4d2ef71..6734582 100644 --- a/web-ui/Cargo.toml +++ b/web-ui/Cargo.toml @@ -4,6 +4,11 @@ version = "0.1.0" edition = "2024" [dependencies] +omikron-connector = { path = "../omikron-connector" } +iota-storage = { path = "../iota-storage" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } +iota-logger = { path = "../iota-logger" } ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/web-ui/src/api.rs b/web-ui/src/api.rs index f9a87a4..26a0544 100755 --- a/web-ui/src/api.rs +++ b/web-ui/src/api.rs @@ -1,6 +1,6 @@ -use crate::server::server::is_local_network; -use crate::util::config_util::CONFIG; +use crate::server::is_local_network; use actix_web::{HttpRequest, HttpResponse, Responder, web}; +use iota_storage::util::config_util::CONFIG; use serde_json::{Value, json}; use std::net::SocketAddr; use std::sync::Arc; @@ -56,15 +56,15 @@ async fn communities_get(req: HttpRequest, ssl: web::Data) -> impl Respond return forbidden(); } - let communities = crate::communities::community_manager::get_communities().await; + // let communities = decentralized::communities::community_manager::get_communities().await; - let mut list = Vec::new(); + let list: Vec = Vec::new(); - for c in communities { - let val = c.frontend().await; - let s_val: Value = serde_json::to_value(val.to_string()).unwrap(); - list.push(s_val); - } + // for c in communities { + // let val = c.frontend().await.to_string(); + // let s_val: Value = serde_json::from_str(&val).unwrap_or(Value::Null); + // list.push(s_val); + // } HttpResponse::Ok().json(list) } @@ -77,12 +77,13 @@ async fn communities_add( return forbidden(); } - let name = payload["name"].as_str().unwrap_or("").to_string(); - let owner = payload["owner"].as_i64().unwrap_or(0); + // let name = payload["name"].as_str().unwrap_or("").to_string(); + // let owner = payload["owner"].as_i64().unwrap_or(0); - let community = Arc::new(crate::communities::community::Community::create(name, owner).await); + // let community = + // Arc::new(decentralized::communities::community::Community::create(name, owner).await); - crate::communities::community_manager::add_community(community).await; + // decentralized::communities::community_manager::add_community(community).await; success() } @@ -92,13 +93,13 @@ async fn users_get(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - let users = crate::users::user_manager::get_users(); + let users = iota_storage::users::user_manager::get_users(); let list: Vec<_> = users .into_iter() .map(|u| { - let val = u.frontend(); - serde_json::to_value(val.to_string()).unwrap() + let val = u.frontend().to_string(); + serde_json::from_str(&val).unwrap_or(Value::Null) }) .collect(); @@ -116,8 +117,8 @@ async fn users_remove( let uuid = payload.get("uuid").and_then(|v| v.as_i64()).unwrap_or(0); - crate::users::user_manager::remove_user(uuid); - crate::users::user_manager::save_users(); + iota_storage::users::user_manager::remove_user(uuid); + iota_storage::users::user_manager::save_users(); success() } @@ -136,9 +137,9 @@ async fn users_add( _ => return error(), }; - if let (Some(user), Some(_)) = crate::users::user_manager::create_user(username).await { - let val = user.frontend(); - let s_val: Value = serde_json::to_value(val.to_string()).unwrap(); + if let (Some(user), Some(_)) = omikron_connector::user_ops::create_user(username).await { + let val = user.frontend().to_string(); + let s_val: Value = serde_json::from_str(&val).unwrap_or(Value::Null); HttpResponse::Ok().json(s_val) } else { error() @@ -150,7 +151,7 @@ async fn shutdown(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - *crate::SHUTDOWN.write().await = true; + *iota_state::SHUTDOWN.write().await = true; success() } @@ -159,8 +160,8 @@ async fn reload(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - *crate::SHUTDOWN.write().await = true; - *crate::RELOAD.write().await = true; + *iota_state::SHUTDOWN.write().await = true; + *iota_state::RELOAD.write().await = true; success() } diff --git a/web-ui/src/server.rs b/web-ui/src/server.rs index b55a50f..9902fe0 100644 --- a/web-ui/src/server.rs +++ b/web-ui/src/server.rs @@ -1,10 +1,9 @@ -use crate::log; -use crate::server::api::api_config; -use crate::server::web_path_parser; -use crate::util::file_util::load_file_buf; -use crate::{ACTIVE_TASKS, SHUTDOWN}; +use crate::api::api_config; +use crate::web_path_parser; use actix_web::{App, Error, HttpRequest, HttpServer, Responder, dev::ServerHandle, web}; -use actix_web_actors::ws; +use iota_logger::log; +use iota_state::{ACTIVE_TASKS, SHUTDOWN}; +use iota_util::file_util::load_file_buf; use rustls::ServerConfig; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use std::{ @@ -15,13 +14,6 @@ use std::{ time::Duration, }; -async fn ws_handler(req: HttpRequest, stream: web::Payload) -> Result { - let path = req.path().to_string(); - log!("WS connection from {:?}", req.peer_addr()); - let session = WsSession::new(path); - ws::start(session, &req, stream) -} - use tokio::sync::oneshot; pub async fn start(port: u16) -> bool { @@ -36,7 +28,6 @@ pub async fn start(port: u16) -> bool { App::new() .app_data(web::Data::new(true)) .configure(api_config) - .service(web::resource("/ws/{path:.*}").route(web::get().to(ws_handler))) .default_service(web::to(web_path_parser::handle)) }) .bind(("0.0.0.0", port)) @@ -49,7 +40,6 @@ pub async fn start(port: u16) -> bool { App::new() .app_data(web::Data::new(false)) .configure(api_config) - .service(web::resource("/ws/{path:.*}").route(web::get().to(ws_handler))) .default_service(web::to(web_path_parser::handle)) }) .bind(("0.0.0.0", port)) diff --git a/web-ui/src/socket.rs b/web-ui/src/socket.rs new file mode 100644 index 0000000..e69de29 diff --git a/web-ui/src/web_path_parser.rs b/web-ui/src/web_path_parser.rs index a82c8db..2eaf3cf 100755 --- a/web-ui/src/web_path_parser.rs +++ b/web-ui/src/web_path_parser.rs @@ -1,7 +1,7 @@ use actix_web::{HttpRequest, HttpResponse}; use std::path::{Path, PathBuf}; -use crate::util::file_util::load_file_vec; +use iota_util::file_util::load_file_vec; fn codec_for_ext(ext: &str) -> &'static str { match ext { From c8a6d4104e01056cdcdb5608fbb34bde045c1080 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:27:04 +0200 Subject: [PATCH 5/9] ... --- iota-storage/src/util/config_util.rs | 20 ++++++++- iota-util/src/file_util.rs | 9 ---- omikron-connector/src/omikron_connection.rs | 50 ++++++++++----------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/iota-storage/src/util/config_util.rs b/iota-storage/src/util/config_util.rs index 0ad7827..6d4082b 100644 --- a/iota-storage/src/util/config_util.rs +++ b/iota-storage/src/util/config_util.rs @@ -19,11 +19,26 @@ impl ConfigUtil { } pub fn clear(&mut self) { self.config = JsonValue::new_object(); + self.unique = false; } pub fn load(&mut self) { let s = load_file("", "config.json"); - if !s.is_empty() { - self.config = json::parse(&s).unwrap_or(JsonValue::new_object()); + if s.is_empty() { + // File might be missing or empty/being written. + // We don't want to wipe the current config if it already has data. + // But if it's the first load, it will stay empty. + return; + } + + match json::parse(&s) { + Ok(parsed) => { + self.config = parsed; + self.unique = false; + } + Err(e) => { + eprintln!("Failed to parse config.json: {}. Content: '{}'", e, s); + // Keep the current config rather than wiping it. + } } } @@ -55,6 +70,7 @@ impl ConfigUtil { pub fn update(&mut self) { if self.unique { save_file("", "config.json", &self.config.to_string()); + self.unique = false; } } } diff --git a/iota-util/src/file_util.rs b/iota-util/src/file_util.rs index 1326feb..b0cd3a3 100755 --- a/iota-util/src/file_util.rs +++ b/iota-util/src/file_util.rs @@ -9,8 +9,6 @@ use uuid::Uuid; use walkdir::WalkDir; use zip::ZipArchive; - - #[allow(dead_code)] pub fn delete_directory(path: &str) -> bool { let dir = Path::new(&get_directory()).join(path); @@ -96,17 +94,10 @@ pub fn load_file(path: &str, name: &str) -> String { let file_path = dir.join(name); if !dir.exists() { - if let Err(e) = fs::create_dir_all(&dir) { - println!("[IMPORTANT] Couldn't create directories: {}", e); - return String::new(); - } return String::new(); } if !file_path.exists() { - if let Err(e) = File::create(&file_path) { - println!("[IMPORTANT] Couldn't create file: {}", e); - } return String::new(); } diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index def2cc6..48da9fb 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -1,15 +1,15 @@ +use dashmap::DashMap; +use iota_logger::{log, log_cv_in, log_cv_out, log_t}; +use iota_state::{ACTIVE_TASKS, SHUTDOWN}; use iota_storage::users::contact::Contact; use iota_storage::util::chat_files::{MessageState, change_message_state}; use iota_storage::util::chats_util::{get_user, mod_user}; use iota_storage::util::communities_util::CommunitiesUtil; +use iota_storage::util::config_util::CONFIG; +use iota_storage::util::{chat_files, chats_util}; +use iota_util::crypto_helper; use iota_util::crypto_util::{DataFormat, SecurePayload}; use iota_util::file_util::{get_children, load_file, save_file}; -use iota_storage::util::{chat_files, chats_util}; -use iota_storage::util::config_util::CONFIG; -use iota_util::crypto_helper; -use iota_state::{ACTIVE_TASKS, SHUTDOWN}; -use iota_logger::{log, log_cv_in, log_cv_out, log_t}; -use dashmap::DashMap; use json::JsonValue; use std::collections::HashMap; use std::sync::{Arc, LazyLock}; @@ -225,15 +225,15 @@ impl OmikronConnection { *self.sender.write().await = Some(sender_arc.clone()); *self.state.write().await = ConnectionState::Connected { identified: false }; - // Handle registration/identification - self.handle_authentication().await; - // Start read loop let read_self = self.clone(); let read_handle = tokio::spawn(async move { read_self.read_loop(&mut receiver).await; }); + // Handle registration/identification + self.handle_authentication().await; + // Start heartbeat let heartbeat_self = self.clone(); let heartbeat_handle = tokio::spawn(async move { @@ -280,26 +280,26 @@ impl OmikronConnection { let private_key = conf.get_private_key(); drop(conf); - if iota_id == 0 || public_key.is_none() || private_key.is_none() { + if iota_id == 0 { log_t!("iota_register_new"); - let key_pair = crypto_helper::generate_keypair(); - let public_key_base64 = crypto_helper::public_key_to_base64(&key_pair.public); - let _private_key_base64 = crypto_helper::secret_key_to_base64(&key_pair.secret); + let (pub_k, priv_k) = if let (Some(pk), Some(sk)) = (public_key, private_key) { + (pk, sk) + } else { + let key_pair = crypto_helper::generate_keypair(); + let public_key_base64 = crypto_helper::public_key_to_base64(&key_pair.public); + let private_key_base64 = crypto_helper::secret_key_to_base64(&key_pair.secret); - let mut conf_write = CONFIG.write().await; - // NOTE: - // Intentionally not storing the generated private/public keys directly into the - // config file here to avoid persisting sensitive material in plaintext. If you - // want to persist them, uncomment the two lines below and accept the security - // implications (they will be saved by `conf_write.update()`). - // conf_write.change("public_key", DataValue::Str(public_key_base64.clone())); - // conf_write.change("private_key", DataValue::Str(private_key_base64)); - conf_write.update(); - drop(conf_write); + let mut conf_write = CONFIG.write().await; + conf_write.change("public_key", JsonValue::from(public_key_base64.clone())); + conf_write.change("private_key", JsonValue::from(private_key_base64.clone())); + conf_write.update(); + drop(conf_write); + (public_key_base64, private_key_base64) + }; let register_msg = CommunicationValue::new(CommunicationType::register_iota) - .add_data(DataTypes::public_key, DataValue::Str(public_key_base64)); + .add_data(DataTypes::public_key, DataValue::Str(pub_k)); let msg_id = register_msg.get_id(); @@ -311,7 +311,7 @@ impl OmikronConnection { return false; } - let iota_value = cv.get_data(DataTypes::register_id); + let iota_value = cv.get_data(DataTypes::iota_id); let iota_id = iota_value.as_number().unwrap_or(0); if iota_id != 0 { From d7f79d2f6e01f4b4825f0ec90e69992c2d728ceb Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sun, 5 Apr 2026 21:42:02 +0200 Subject: [PATCH 6/9] [Fix] Changed TTP to fetch from git.methanium.net --- Cargo.lock | 28 ++++++++++++++-------------- decentralized/unused-Cargo.toml | 4 ++-- iota-cli/Cargo.toml | 4 ++-- iota-core/Cargo.toml | 4 ++-- iota-logger/Cargo.toml | 2 +- iota-state/Cargo.toml | 2 +- iota-storage/Cargo.toml | 4 ++-- iota-util/Cargo.toml | 4 ++-- omikron-connector/Cargo.toml | 4 ++-- web-server/Cargo.toml | 4 ++-- web-ui/Cargo.toml | 4 ++-- 11 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9dcfc7..5d2a1ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.58" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "jobserver", @@ -1679,9 +1679,9 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -3361,9 +3361,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -3851,9 +3851,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" dependencies = [ "bytes", "libc", @@ -3868,9 +3868,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -4010,7 +4010,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttp-core" version = "0.1.0" -source = "git+https://github.com/Tensamin/TTP.git#e246d1af6a42c71514d0ccc06fef94d71e4ad167" +source = "git+https://git.methanium.net/Tensamin/TTP.git#82b71c1be1fa73aeb0f228c4af364206fda8d712" dependencies = [ "base64", "byteorder", @@ -4022,7 +4022,7 @@ dependencies = [ [[package]] name = "ttp-native" version = "0.1.0" -source = "git+https://github.com/Tensamin/TTP.git#e246d1af6a42c71514d0ccc06fef94d71e4ad167" +source = "git+https://git.methanium.net/Tensamin/TTP.git#82b71c1be1fa73aeb0f228c4af364206fda8d712" dependencies = [ "quinn", "rustls", @@ -4966,9 +4966,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wtransport" diff --git a/decentralized/unused-Cargo.toml b/decentralized/unused-Cargo.toml index 2c9c97c..8af10a1 100644 --- a/decentralized/unused-Cargo.toml +++ b/decentralized/unused-Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } iota-logger = { path = "../iota-logger" } iota-util = { path = "../iota-util" } iota-storage = { path = "../iota-storage" } diff --git a/iota-cli/Cargo.toml b/iota-cli/Cargo.toml index 99e2051..60a0ce1 100644 --- a/iota-cli/Cargo.toml +++ b/iota-cli/Cargo.toml @@ -12,8 +12,8 @@ iota-util = { path = "../iota-util" } omikron-connector = { path = "../omikron-connector" } -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } actix-web = { version = "4", features = ["rustls-0_23"] } actix-web-actors = "4" diff --git a/iota-core/Cargo.toml b/iota-core/Cargo.toml index 5ecc90a..acb6c34 100644 --- a/iota-core/Cargo.toml +++ b/iota-core/Cargo.toml @@ -14,8 +14,8 @@ omikron-connector = { path = "../omikron-connector" } web-server = { path = "../web-server" } web-ui = { path = "../web-ui" } -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } dashmap = "6.1.0" json = "*" diff --git a/iota-logger/Cargo.toml b/iota-logger/Cargo.toml index f03eac3..aa71144 100644 --- a/iota-logger/Cargo.toml +++ b/iota-logger/Cargo.toml @@ -5,6 +5,6 @@ edition = "2024" [dependencies] ratatui = "0.30.0" -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } iota-state = { path = "../iota-state" } iota-util = { path = "../iota-util" } diff --git a/iota-state/Cargo.toml b/iota-state/Cargo.toml index eff1cb7..ce37258 100644 --- a/iota-state/Cargo.toml +++ b/iota-state/Cargo.toml @@ -9,4 +9,4 @@ once_cell = "1.21.3" tokio = { version = "1.50.0", features = ["full"] } json = "*" sysinfo = "0.38.3" -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } diff --git a/iota-storage/Cargo.toml b/iota-storage/Cargo.toml index 6bab29e..2baa309 100644 --- a/iota-storage/Cargo.toml +++ b/iota-storage/Cargo.toml @@ -8,8 +8,8 @@ iota-logger = { path = "../iota-logger" } iota-state = { path = "../iota-state" } iota-util = { path = "../iota-util" } -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } aes-gcm = "0.10.3" base64 = "0.22.1" diff --git a/iota-util/Cargo.toml b/iota-util/Cargo.toml index 77ecde1..9a1d4cb 100644 --- a/iota-util/Cargo.toml +++ b/iota-util/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } json = "*" pnet = "0.35.0" diff --git a/omikron-connector/Cargo.toml b/omikron-connector/Cargo.toml index 41f7d55..5b29a2f 100644 --- a/omikron-connector/Cargo.toml +++ b/omikron-connector/Cargo.toml @@ -8,8 +8,8 @@ iota-logger = { path = "../iota-logger" } iota-state = { path = "../iota-state" } iota-storage = { path = "../iota-storage" } iota-util = { path = "../iota-util" } -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } dashmap = "6.1.0" json = "*" diff --git a/web-server/Cargo.toml b/web-server/Cargo.toml index 0e99c39..b214806 100644 --- a/web-server/Cargo.toml +++ b/web-server/Cargo.toml @@ -5,5 +5,5 @@ version = "0.1.0" edition = "2024" [dependencies] -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } diff --git a/web-ui/Cargo.toml b/web-ui/Cargo.toml index 6734582..16a8974 100644 --- a/web-ui/Cargo.toml +++ b/web-ui/Cargo.toml @@ -9,8 +9,8 @@ iota-storage = { path = "../iota-storage" } iota-state = { path = "../iota-state" } iota-util = { path = "../iota-util" } iota-logger = { path = "../iota-logger" } -ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } -ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +ttp-core = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-core" } +ttp-native = { git = "https://git.methanium.net/Tensamin/TTP.git", package = "ttp-native" } actix-web = { version = "4", features = ["rustls-0_23"] } actix-web-actors = "4" From 17f1653f87ca6bea3a7f669b34b2e03d16427463 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sun, 5 Apr 2026 23:41:57 +0200 Subject: [PATCH 7/9] [Add] New Client identification Logic --- Cargo.lock | 4 +- omikron-connector/src/omikron_connection.rs | 62 +++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d2a1ae..197184f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4010,7 +4010,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttp-core" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#82b71c1be1fa73aeb0f228c4af364206fda8d712" +source = "git+https://git.methanium.net/Tensamin/TTP.git#bacbcb0e38791cf1a38cf5851beb20d5645002ba" dependencies = [ "base64", "byteorder", @@ -4022,7 +4022,7 @@ dependencies = [ [[package]] name = "ttp-native" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#82b71c1be1fa73aeb0f228c4af364206fda8d712" +source = "git+https://git.methanium.net/Tensamin/TTP.git#bacbcb0e38791cf1a38cf5851beb20d5645002ba" dependencies = [ "quinn", "rustls", diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index 48da9fb..88d51c7 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -424,6 +424,68 @@ impl OmikronConnection { return; } + if cv.is_type(CommunicationType::client_connected) { + let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0) as i64; + let session_id = cv.get_data(DataTypes::session_id).as_number().unwrap_or(0) as i64; + + let mut contacts = chats_util::get_users(user_id); + let mut contacts_array = Vec::new(); + + for (i, contact) in contacts.iter().enumerate() { + let mut contact_container = Vec::new(); + contact_container.push((DataTypes::user_id, DataValue::Number(contact.user_id))); + contact_container.push(( + DataTypes::last_message_at, + DataValue::Number(contact.last_message_at.unwrap_or(0)), + )); + + if let Some(ref name) = contact.user_name { + contact_container.push((DataTypes::username, DataValue::Str(name.clone()))); + } + + let amount = if i < 10 { 20 } else { 1 }; + let messages = chat_files::get_messages(user_id, contact.user_id, 0, amount); + + let mut msg_array = Vec::new(); + for m in messages.members() { + let message_time = m["message_time"].as_i64().unwrap_or(0); + let content = m["content"].as_str().unwrap_or("").to_string(); + let sent_by_self = m["sent_by_self"].as_bool().unwrap_or(false); + let height = m["height"].as_i64().unwrap_or(0); + let message_state = m["message_state"].as_str().unwrap_or("").to_string(); + + let mut msg_container = Vec::new(); + msg_container.push((DataTypes::send_time, DataValue::Number(message_time))); + msg_container.push((DataTypes::content, DataValue::Str(content.clone()))); + msg_container.push((DataTypes::message_state, DataValue::Str(message_state))); + msg_container.push((DataTypes::height, DataValue::Number(height))); + msg_container.push((DataTypes::sent_by_self, DataValue::Bool(sent_by_self))); + msg_array.push(DataValue::Container(msg_container)); + + if msg_array.len() == 1 { + let sender_id = if sent_by_self { + user_id + } else { + contact.user_id + }; + let mut last_msg = Vec::new(); + last_msg.push((DataTypes::content, DataValue::Str(content))); + last_msg.push((DataTypes::sender_id, DataValue::Number(sender_id))); + contact_container + .push((DataTypes::last_message, DataValue::Container(last_msg))); + } + } + contact_container.push((DataTypes::messages, DataValue::Array(msg_array))); + contacts_array.push(DataValue::Container(contact_container)); + } + + let resp = CommunicationValue::new(CommunicationType::client_connected) + .with_id(cv.get_id()) + .add_data(DataTypes::contacts, DataValue::Array(contacts_array)); + self.send_message(&resp).await; + return; + } + if cv.is_type(CommunicationType::identification_response) { if let Some(_accepted) = cv.get_data(DataTypes::accepted).as_bool() { let mut state = self.state.write().await; From 1e714d1c2d3de5baa1e4875f36c0165bf18030fc Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:11:24 +0200 Subject: [PATCH 8/9] [Fix] correct ChatpartnerID in Message_state --- omikron-connector/src/omikron_connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index 88d51c7..4e8af77 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -641,7 +641,7 @@ impl OmikronConnection { .with_sender(receiver_id as u64) .add_data( DataTypes::chat_partner_id, - DataValue::Number(sender_id as i64), + DataValue::Number(receiver_id as i64), ) .add_data(DataTypes::send_time, DataValue::Number(timestamp_i64)) .add_data( From d79a625e322437f1ff531140900b40974d9735fd Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:37:01 +0200 Subject: [PATCH 9/9] [Fix] Dockerfile Iota bin was named wrong --- dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerfile b/dockerfile index ee00add..5f07197 100644 --- a/dockerfile +++ b/dockerfile @@ -13,8 +13,8 @@ WORKDIR /app RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* -COPY --from=builder /app/target/release/iota . +COPY --from=builder /app/target/release/iota-core . EXPOSE 1984 -CMD ["./iota"] \ No newline at end of file +CMD ["./iota-core"]