[Clean]
This commit is contained in:
parent
e8faca34e2
commit
0990ccd526
16 changed files with 139 additions and 393 deletions
|
|
@ -12,10 +12,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::anonymous_clients::anonymous_manager::generate_username;
|
use crate::anonymous_clients::anonymous_manager::generate_username;
|
||||||
use crate::calls::call_manager;
|
use crate::calls::call_manager;
|
||||||
use crate::data::{
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
|
||||||
user::User,
|
|
||||||
};
|
|
||||||
use crate::omega::omega_connection::{WAITING_TASKS, get_omega_connection};
|
use crate::omega::omega_connection::{WAITING_TASKS, get_omega_connection};
|
||||||
use crate::rho::rho_manager;
|
use crate::rho::rho_manager;
|
||||||
use crate::util::logger::PrintType;
|
use crate::util::logger::PrintType;
|
||||||
|
|
@ -352,7 +349,7 @@ impl AnonymousClientConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error_no_call_id)
|
self.send_error_response(&cv.get_id(), CommunicationType::error_no_call_id)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -370,7 +367,7 @@ impl AnonymousClientConnection {
|
||||||
// Find target RhoConnection
|
// Find target RhoConnection
|
||||||
let target_rho = match rho_manager::get_rho_con_for_user(receiver_id).await {
|
let target_rho = match rho_manager::get_rho_con_for_user(receiver_id).await {
|
||||||
Some(rho) => rho,
|
Some(rho) => rho,
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -407,7 +404,7 @@ impl AnonymousClientConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -521,15 +518,12 @@ impl AnonymousClientConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if interested in a user and send notification
|
/// Check if interested in a user and send notification
|
||||||
pub async fn are_you_interested(self: Arc<Self>, user: &User) {
|
pub async fn are_you_interested(self: Arc<Self>, user_id: i64) {
|
||||||
let interested_guard = self.clone().get_interested_users().await;
|
let interested_guard = self.clone().get_interested_users().await;
|
||||||
if interested_guard.contains(&user.user_id) {
|
if interested_guard.contains(&user_id) {
|
||||||
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
||||||
.add_data_str(DataTypes::user_id, user.user_id.to_string())
|
.add_data_str(DataTypes::user_id, user_id.to_string())
|
||||||
.add_data_str(
|
.add_data_str(DataTypes::user_state, format!("online"));
|
||||||
DataTypes::user_state,
|
|
||||||
format!("{:?}", user.status.to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.send_message(¬ification).await;
|
self.send_message(¬ification).await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,11 @@
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use livekit::Room;
|
|
||||||
use livekit_api::services::room::RoomClient;
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{env, str::FromStr, sync::Arc, time::Duration};
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::calls::{call_group::CallGroup, caller::Caller};
|
||||||
calls::{call_group::CallGroup, caller::Caller},
|
|
||||||
log, log_err,
|
|
||||||
util::logger::PrintType,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CALL_GROUPS: Lazy<DashMap<Uuid, Arc<CallGroup>>> = Lazy::new(|| DashMap::new());
|
pub static CALL_GROUPS: Lazy<DashMap<Uuid, Arc<CallGroup>>> = Lazy::new(|| DashMap::new());
|
||||||
|
|
||||||
pub async fn get_call_invites(user_id: i64) -> Vec<Arc<Caller>> {
|
pub async fn get_call_invites(user_id: i64) -> Vec<Arc<Caller>> {
|
||||||
let mut callers = Vec::new();
|
let mut callers = Vec::new();
|
||||||
|
|
@ -101,59 +95,3 @@ pub async fn add_invite(call_id: Uuid, inviter_id: i64, invitee_id: i64) -> bool
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn garbage_collect_calls() {
|
|
||||||
tokio::spawn(async move {
|
|
||||||
loop {
|
|
||||||
clean_calls().await;
|
|
||||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
pub async fn clean_calls() {
|
|
||||||
let api_key = match env::var("LIVEKIT_API_KEY") {
|
|
||||||
Ok(key) => key,
|
|
||||||
Err(_) => {
|
|
||||||
log_err!(PrintType::General, "LIVEKIT_API_KEY not set!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let api_secret = match env::var("LIVEKIT_API_SECRET") {
|
|
||||||
Ok(secret) => secret,
|
|
||||||
Err(_) => {
|
|
||||||
log_err!(PrintType::General, "LIVEKIT_API_SECRET not set!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let room_service = RoomClient::with_api_key("https:call.tensamin.net", &api_key, &api_secret);
|
|
||||||
let rooms = room_service.list_rooms(Vec::new()).await.unwrap();
|
|
||||||
let mut call_ids: Vec<Uuid> = Vec::new();
|
|
||||||
let mut no_users: Vec<Uuid> = Vec::new();
|
|
||||||
for room in rooms {
|
|
||||||
if let Ok(id) = Uuid::from_str(&room.name) {
|
|
||||||
if room.num_participants == 0 {
|
|
||||||
no_users.push(id);
|
|
||||||
}
|
|
||||||
call_ids.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let size_pre = CALL_GROUPS.len();
|
|
||||||
for (id, _) in CALL_GROUPS.clone().into_iter() {
|
|
||||||
if !call_ids.contains(&id) {
|
|
||||||
CALL_GROUPS.remove(&id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (_, cg) in CALL_GROUPS.clone().into_iter() {
|
|
||||||
*cg.show.write().await = !no_users.contains(&cg.call_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let size_post = CALL_GROUPS.len();
|
|
||||||
if size_pre - size_post != 0 {
|
|
||||||
log!(
|
|
||||||
PrintType::Call,
|
|
||||||
"Cleaned {} calls, {} remaining",
|
|
||||||
size_pre - size_post,
|
|
||||||
size_post
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,29 @@
|
||||||
use livekit_api::access_token;
|
use livekit_api::{
|
||||||
|
access_token::{self},
|
||||||
|
services::room::RoomClient,
|
||||||
|
};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Duration;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub fn create_token(
|
use crate::{calls::call_manager::CALL_GROUPS, log, log_err, util::logger::PrintType};
|
||||||
user_id: i64,
|
|
||||||
call_id: Uuid,
|
pub fn create_token(user_id: i64, call_id: Uuid, has_admin: bool) -> Result<String, ()> {
|
||||||
has_admin: bool,
|
let api_key = match env::var("LIVEKIT_API_KEY") {
|
||||||
) -> Result<String, access_token::AccessTokenError> {
|
Ok(key) => key,
|
||||||
let api_key = env::var("LIVEKIT_API_KEY").expect("LIVEKIT_API_KEY is not set");
|
Err(_) => {
|
||||||
let api_secret = env::var("LIVEKIT_API_SECRET").expect("LIVEKIT_API_SECRET is not set");
|
log_err!(PrintType::General, "LIVEKIT_API_KEY not set!");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let api_secret = match env::var("LIVEKIT_API_SECRET") {
|
||||||
|
Ok(secret) => secret,
|
||||||
|
Err(_) => {
|
||||||
|
log_err!(PrintType::General, "LIVEKIT_API_SECRET not set!");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
|
let token = access_token::AccessToken::with_api_key(&api_key, &api_secret)
|
||||||
.with_identity(&user_id.to_string())
|
.with_identity(&user_id.to_string())
|
||||||
|
|
@ -21,5 +36,72 @@ pub fn create_token(
|
||||||
})
|
})
|
||||||
.with_metadata(&format!("{{\"isAdmin\":{}}}", has_admin))
|
.with_metadata(&format!("{{\"isAdmin\":{}}}", has_admin))
|
||||||
.to_jwt();
|
.to_jwt();
|
||||||
return token;
|
if let Ok(token) = token {
|
||||||
|
Ok(token)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn garbage_collect_calls() {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let api_key = match env::var("LIVEKIT_API_KEY") {
|
||||||
|
Ok(key) => key,
|
||||||
|
Err(_) => {
|
||||||
|
log_err!(PrintType::General, "LIVEKIT_API_KEY not set!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let api_secret = match env::var("LIVEKIT_API_SECRET") {
|
||||||
|
Ok(secret) => secret,
|
||||||
|
Err(_) => {
|
||||||
|
log_err!(PrintType::General, "LIVEKIT_API_SECRET not set!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let hostname = match env::var("LIVEKI_HOSTNAME") {
|
||||||
|
Ok(secret) => secret,
|
||||||
|
Err(_) => {
|
||||||
|
log_err!(PrintType::General, "LIVEKI_HOSTNAME not set!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let room_service = RoomClient::with_api_key(&hostname, &api_key, &api_secret);
|
||||||
|
clean_calls(room_service).await;
|
||||||
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pub async fn clean_calls(room_service: RoomClient) {
|
||||||
|
let rooms = room_service.list_rooms(Vec::new()).await.unwrap();
|
||||||
|
let mut call_ids: Vec<Uuid> = Vec::new();
|
||||||
|
let mut no_users: Vec<Uuid> = Vec::new();
|
||||||
|
for room in rooms {
|
||||||
|
if let Ok(id) = Uuid::from_str(&room.name) {
|
||||||
|
if room.num_participants == 0 {
|
||||||
|
no_users.push(id);
|
||||||
|
}
|
||||||
|
call_ids.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let size_pre = CALL_GROUPS.len();
|
||||||
|
for (id, _) in CALL_GROUPS.clone().into_iter() {
|
||||||
|
if !call_ids.contains(&id) {
|
||||||
|
CALL_GROUPS.remove(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (_, cg) in CALL_GROUPS.clone().into_iter() {
|
||||||
|
*cg.show.write().await = !no_users.contains(&cg.call_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_post = CALL_GROUPS.len();
|
||||||
|
if size_pre - size_post != 0 {
|
||||||
|
log!(
|
||||||
|
PrintType::Call,
|
||||||
|
"Cleaned {} calls, {} remaining",
|
||||||
|
size_pre - size_post,
|
||||||
|
size_post
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ impl Caller {
|
||||||
pub fn has_admin(&self) -> bool {
|
pub fn has_admin(&self) -> bool {
|
||||||
self.has_admin
|
self.has_admin
|
||||||
}
|
}
|
||||||
pub async fn is_timeout(&self) -> bool {
|
pub async fn is_timeouted(&self) -> bool {
|
||||||
*self.timeout.read().await
|
*self.timeout.read().await
|
||||||
> SystemTime::now()
|
> SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,5 @@
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct User {
|
|
||||||
pub iota_id: i64,
|
|
||||||
pub user_id: i64,
|
|
||||||
pub status: UserStatus,
|
|
||||||
}
|
|
||||||
impl User {
|
|
||||||
pub fn new(iota_id: i64, user_id: i64, status: UserStatus) -> Self {
|
|
||||||
User {
|
|
||||||
iota_id,
|
|
||||||
user_id,
|
|
||||||
status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
pub enum UserStatus {
|
pub enum UserStatus {
|
||||||
online,
|
online,
|
||||||
do_not_disturb,
|
do_not_disturb,
|
||||||
|
|
|
||||||
15
src/main.rs
15
src/main.rs
|
|
@ -18,11 +18,10 @@ use crate::{
|
||||||
anonymous_clients::{
|
anonymous_clients::{
|
||||||
anonymous_client_connection::AnonymousClientConnection, anonymous_manager,
|
anonymous_client_connection::AnonymousClientConnection, anonymous_manager,
|
||||||
},
|
},
|
||||||
calls::call_manager::garbage_collect_calls,
|
calls::call_util::garbage_collect_calls,
|
||||||
omega::omega_connection::OmegaConnection,
|
omega::omega_connection::OmegaConnection,
|
||||||
rho::{client_connection::ClientConnection, iota_connection::IotaConnection},
|
rho::{client_connection::ClientConnection, iota_connection::IotaConnection},
|
||||||
util::{
|
util::{
|
||||||
config_util::CONFIG,
|
|
||||||
crypto_helper::{load_public_key, load_secret_key},
|
crypto_helper::{load_public_key, load_secret_key},
|
||||||
logger::{PrintType, startup},
|
logger::{PrintType, startup},
|
||||||
},
|
},
|
||||||
|
|
@ -44,7 +43,11 @@ async fn main() {
|
||||||
Arc::new(OmegaConnection::new()).connect();
|
Arc::new(OmegaConnection::new()).connect();
|
||||||
});
|
});
|
||||||
startup();
|
startup();
|
||||||
let address = format!("{}:{}", &CONFIG.read().await.ip, &CONFIG.read().await.port);
|
let address = format!(
|
||||||
|
"{}:{}",
|
||||||
|
env::var("IP").unwrap_or("0.0.0.0".to_string()),
|
||||||
|
env::var("PORT").unwrap_or("959".to_string())
|
||||||
|
);
|
||||||
let listener = TcpListener::bind(&address).await.unwrap();
|
let listener = TcpListener::bind(&address).await.unwrap();
|
||||||
|
|
||||||
log!(
|
log!(
|
||||||
|
|
@ -97,7 +100,7 @@ async fn main() {
|
||||||
client_conn.handle_close().await;
|
client_conn.handle_close().await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
log_in!(PrintType::Client, "Client stream ended");
|
log_in!(PrintType::Client, "Client stream ended");
|
||||||
client_conn.handle_close().await;
|
client_conn.handle_close().await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -139,7 +142,7 @@ async fn main() {
|
||||||
client_conn.handle_close().await;
|
client_conn.handle_close().await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
log_in!(PrintType::Client, "Anonymous Client stream ended");
|
log_in!(PrintType::Client, "Anonymous Client stream ended");
|
||||||
anonymous_manager::remove_anonymous_user(
|
anonymous_manager::remove_anonymous_user(
|
||||||
client_conn.get_user_id().await,
|
client_conn.get_user_id().await,
|
||||||
|
|
@ -176,7 +179,7 @@ async fn main() {
|
||||||
iota_conn.handle_close().await;
|
iota_conn.handle_close().await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
// Stream ended
|
// Stream ended
|
||||||
log_in!(PrintType::Iota, "Iota stream ended");
|
log_in!(PrintType::Iota, "Iota stream ended");
|
||||||
iota_conn.handle_close().await;
|
iota_conn.handle_close().await;
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,19 @@ use tokio::{
|
||||||
use tokio_native_tls::TlsStream;
|
use tokio_native_tls::TlsStream;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::log_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{
|
data::{
|
||||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||||
user::UserStatus,
|
user::UserStatus,
|
||||||
},
|
},
|
||||||
get_private_key, log, log_in, log_out,
|
get_private_key, log, log_in, log_out,
|
||||||
rho::rho_manager::{self, RHO_CONNECTIONS},
|
rho::rho_manager::{self, RHO_CONNECTIONS, connection_count},
|
||||||
util::crypto_helper::{decrypt_b64, secret_key_to_base64},
|
util::{
|
||||||
util::logger::PrintType,
|
crypto_helper::{decrypt_b64, secret_key_to_base64},
|
||||||
|
logger::PrintType,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use crate::{log_err, util::crypto_helper::load_public_key};
|
|
||||||
|
|
||||||
pub static WAITING_TASKS: Lazy<
|
pub static WAITING_TASKS: Lazy<
|
||||||
DashMap<Uuid, Box<dyn Fn(Arc<OmegaConnection>, CommunicationValue) -> bool + Send + Sync>>,
|
DashMap<Uuid, Box<dyn Fn(Arc<OmegaConnection>, CommunicationValue) -> bool + Send + Sync>>,
|
||||||
|
|
@ -159,8 +161,6 @@ impl OmegaConnection {
|
||||||
.to_string()
|
.to_string()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let server_pub_key_obj = load_public_key(server_pub_key).unwrap();
|
|
||||||
|
|
||||||
let decrypted_challenge = decrypt_b64(
|
let decrypted_challenge = decrypt_b64(
|
||||||
&secret_key_to_base64(&get_private_key()),
|
&secret_key_to_base64(&get_private_key()),
|
||||||
server_pub_key,
|
server_pub_key,
|
||||||
|
|
@ -222,7 +222,8 @@ impl OmegaConnection {
|
||||||
|
|
||||||
let sync_msg = CommunicationValue::new(CommunicationType::sync_client_iota_status)
|
let sync_msg = CommunicationValue::new(CommunicationType::sync_client_iota_status)
|
||||||
.add_data(DataTypes::iota_ids, JsonValue::Array(connected_iota_ids))
|
.add_data(DataTypes::iota_ids, JsonValue::Array(connected_iota_ids))
|
||||||
.add_data(DataTypes::user_ids, JsonValue::Array(connected_user_ids));
|
.add_data(DataTypes::user_ids, JsonValue::Array(connected_user_ids))
|
||||||
|
.add_data(DataTypes::rho_connections, JsonValue::from(connection_count().await));
|
||||||
|
|
||||||
selfc.send_message(&sync_msg).await;
|
selfc.send_message(&sync_msg).await;
|
||||||
});
|
});
|
||||||
|
|
@ -340,12 +341,6 @@ impl OmegaConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect_iota(iota_id: i64, _user_ids: Vec<i64>) {
|
|
||||||
let cv = CommunicationValue::new(CommunicationType::iota_connected)
|
|
||||||
.add_data(DataTypes::iota_id, JsonValue::from(iota_id));
|
|
||||||
OmegaConnection::send_global(cv).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn close_iota(iota_id: i64) {
|
pub async fn close_iota(iota_id: i64) {
|
||||||
let cv = CommunicationValue::new(CommunicationType::iota_disconnected)
|
let cv = CommunicationValue::new(CommunicationType::iota_disconnected)
|
||||||
.add_data(DataTypes::iota_id, JsonValue::from(iota_id));
|
.add_data(DataTypes::iota_id, JsonValue::from(iota_id));
|
||||||
|
|
@ -459,7 +454,7 @@ impl OmegaConnection {
|
||||||
|
|
||||||
match tokio::time::timeout(timeout, rx.recv()).await {
|
match tokio::time::timeout(timeout, rx.recv()).await {
|
||||||
Ok(Some(response_cv)) => Ok(response_cv),
|
Ok(Some(response_cv)) => Ok(response_cv),
|
||||||
Ok(None) => Err("Failed to receive response, channel was closed.".to_string()),
|
Ok(_) => Err("Failed to receive response, channel was closed.".to_string()),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
WAITING_TASKS.remove(&msg_id);
|
WAITING_TASKS.remove(&msg_id);
|
||||||
Err(format!(
|
Err(format!(
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,9 @@ use crate::util::crypto_helper::{load_public_key, public_key_to_base64};
|
||||||
use crate::util::crypto_util::{DataFormat, SecurePayload};
|
use crate::util::crypto_util::{DataFormat, SecurePayload};
|
||||||
use crate::util::logger::PrintType;
|
use crate::util::logger::PrintType;
|
||||||
use crate::{
|
use crate::{
|
||||||
// calls::call_manager::CallManager,
|
|
||||||
data::{
|
data::{
|
||||||
communication::{CommunicationType, CommunicationValue, DataTypes},
|
communication::{CommunicationType, CommunicationValue, DataTypes},
|
||||||
user::{User, UserStatus},
|
user::UserStatus,
|
||||||
},
|
},
|
||||||
omega::omega_connection::OmegaConnection,
|
omega::omega_connection::OmegaConnection,
|
||||||
};
|
};
|
||||||
|
|
@ -163,7 +162,7 @@ impl ClientConnection {
|
||||||
|
|
||||||
let pub_key = match load_public_key(base64_pub) {
|
let pub_key = match load_public_key(base64_pub) {
|
||||||
Some(pk) => pk,
|
Some(pk) => pk,
|
||||||
None => {
|
_ => {
|
||||||
self.clone()
|
self.clone()
|
||||||
.send_error_response(
|
.send_error_response(
|
||||||
&cv.get_id(),
|
&cv.get_id(),
|
||||||
|
|
@ -227,7 +226,7 @@ impl ClientConnection {
|
||||||
|
|
||||||
let rho_connection = match rho_manager::get_rho_con_for_user(user_id).await {
|
let rho_connection = match rho_manager::get_rho_con_for_user(user_id).await {
|
||||||
Some(rho) => rho,
|
Some(rho) => rho,
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(
|
self.send_error_response(
|
||||||
&cv.get_id(),
|
&cv.get_id(),
|
||||||
CommunicationType::error_no_iota,
|
CommunicationType::error_no_iota,
|
||||||
|
|
@ -432,7 +431,7 @@ impl ClientConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error_no_call_id)
|
self.send_error_response(&cv.get_id(), CommunicationType::error_no_call_id)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -450,7 +449,7 @@ impl ClientConnection {
|
||||||
// Find target RhoConnection
|
// Find target RhoConnection
|
||||||
let target_rho = match rho_manager::get_rho_con_for_user(receiver_id).await {
|
let target_rho = match rho_manager::get_rho_con_for_user(receiver_id).await {
|
||||||
Some(rho) => rho,
|
Some(rho) => rho,
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -487,7 +486,7 @@ impl ClientConnection {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
self.send_error_response(&cv.get_id(), CommunicationType::error)
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
|
|
@ -697,15 +696,12 @@ impl ClientConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if interested in a user and send notification
|
/// Check if interested in a user and send notification
|
||||||
pub async fn are_you_interested(self: Arc<Self>, user: &User) {
|
pub async fn are_you_interested(self: Arc<Self>, user_id: i64) {
|
||||||
let interested_guard = self.clone().get_interested_users().await;
|
let interested_guard = self.clone().get_interested_users().await;
|
||||||
if interested_guard.contains(&user.user_id) {
|
if interested_guard.contains(&user_id) {
|
||||||
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
let notification = CommunicationValue::new(CommunicationType::client_changed)
|
||||||
.add_data_str(DataTypes::user_id, user.user_id.to_string())
|
.add_data_str(DataTypes::user_id, user_id.to_string())
|
||||||
.add_data_str(
|
.add_data_str(DataTypes::user_state, format!("online"));
|
||||||
DataTypes::user_state,
|
|
||||||
format!("{:?}", user.status.to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.send_message(¬ification).await;
|
self.send_message(¬ification).await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ impl IotaConnection {
|
||||||
|
|
||||||
let pub_key = match load_public_key(base64_pub) {
|
let pub_key = match load_public_key(base64_pub) {
|
||||||
Some(pk) => pk,
|
Some(pk) => pk,
|
||||||
None => {
|
_ => {
|
||||||
self.send_error_response(
|
self.send_error_response(
|
||||||
&cv.get_id(),
|
&cv.get_id(),
|
||||||
CommunicationType::error_invalid_public_key,
|
CommunicationType::error_invalid_public_key,
|
||||||
|
|
@ -594,6 +594,7 @@ impl IotaConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn await_response(
|
pub async fn await_response(
|
||||||
&self,
|
&self,
|
||||||
cv: &CommunicationValue,
|
cv: &CommunicationValue,
|
||||||
|
|
@ -626,7 +627,7 @@ impl IotaConnection {
|
||||||
|
|
||||||
match tokio::time::timeout(timeout, rx.recv()).await {
|
match tokio::time::timeout(timeout, rx.recv()).await {
|
||||||
Ok(Some(response_cv)) => Ok(response_cv),
|
Ok(Some(response_cv)) => Ok(response_cv),
|
||||||
Ok(None) => Err("Failed to receive response, channel was closed.".to_string()),
|
Ok(_) => Err("Failed to receive response, channel was closed.".to_string()),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.waiting_tasks.remove(&msg_id);
|
self.waiting_tasks.remove(&msg_id);
|
||||||
Err(format!(
|
Err(format!(
|
||||||
|
|
|
||||||
|
|
@ -147,10 +147,10 @@ impl RhoConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if clients are interested in a user
|
/// Check if clients are interested in a user
|
||||||
pub async fn are_they_interested(&self, user: &crate::data::user::User) {
|
pub async fn are_they_interested(&self, user_id: i64) {
|
||||||
let connections = self.client_connections.read().await;
|
let connections = self.client_connections.read().await;
|
||||||
for connection in connections.iter() {
|
for connection in connections.iter() {
|
||||||
connection.clone().are_you_interested(user).await;
|
connection.clone().are_you_interested(user_id).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,6 @@ pub async fn get_rho_by_iota(iota_id: i64) -> Option<Arc<RhoConnection>> {
|
||||||
connections.get(&iota_id).map(Arc::clone)
|
connections.get(&iota_id).map(Arc::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all active RhoConnections
|
|
||||||
pub async fn get_all_connections() -> Vec<Arc<RhoConnection>> {
|
|
||||||
let connections = RHO_CONNECTIONS.read().await;
|
|
||||||
connections.values().map(Arc::clone).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the count of active connections
|
/// Get the count of active connections
|
||||||
pub async fn connection_count() -> usize {
|
pub async fn connection_count() -> usize {
|
||||||
let connections = RHO_CONNECTIONS.read().await;
|
let connections = RHO_CONNECTIONS.read().await;
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
use crate::util::file_util::load_file;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use uuid::Uuid;
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Config {
|
|
||||||
pub omega_server: String,
|
|
||||||
pub auth_server: String,
|
|
||||||
pub omikron_id: Uuid,
|
|
||||||
pub keep_people_stored_for: i32,
|
|
||||||
pub max_data: u64,
|
|
||||||
pub ip: String,
|
|
||||||
pub port: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
omega_server: "omega.tensamin.net".into(),
|
|
||||||
auth_server: "auth.tensamin.net".into(),
|
|
||||||
omikron_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap_or_default(),
|
|
||||||
keep_people_stored_for: 90,
|
|
||||||
max_data: 1000 * 1000 * 1000 * 8,
|
|
||||||
ip: "0.0.0.0".into(),
|
|
||||||
port: 959,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| RwLock::new(Config::load()));
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn load() -> Self {
|
|
||||||
let content = load_file("", "config.json");
|
|
||||||
if content.trim().is_empty() {
|
|
||||||
return Config::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let json = json::parse(&content).unwrap();
|
|
||||||
Self {
|
|
||||||
omega_server: json["omega_server"]
|
|
||||||
.as_str()
|
|
||||||
.unwrap_or("omega.tensamin.net")
|
|
||||||
.into(),
|
|
||||||
auth_server: json["auth_server"]
|
|
||||||
.as_str()
|
|
||||||
.unwrap_or("auth.tensamin.net")
|
|
||||||
.into(),
|
|
||||||
omikron_id: Uuid::parse_str(json["omikron_id"].as_str().unwrap_or_default())
|
|
||||||
.unwrap_or_default(),
|
|
||||||
keep_people_stored_for: json["keep_people_stored_for"].as_i64().unwrap_or(90) as i32,
|
|
||||||
max_data: json["max_data"].as_u64().unwrap_or(8000000000),
|
|
||||||
ip: json["ip"].as_str().unwrap_or("0.0.0.0").into(),
|
|
||||||
port: json["port"].as_u64().unwrap_or(959) as u16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -25,11 +25,8 @@ pub enum DataFormat {
|
||||||
Hex,
|
Hex,
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main Class Structure ---
|
|
||||||
pub struct SecurePayload {
|
pub struct SecurePayload {
|
||||||
/// The internal canonical representation is always raw bytes.
|
|
||||||
inner_data: Vec<u8>,
|
inner_data: Vec<u8>,
|
||||||
/// The private key of the user associated with this payload instance.
|
|
||||||
private_key: Secret,
|
private_key: Secret,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,22 +106,14 @@ impl SecurePayload {
|
||||||
let peer_pub = public_key.into();
|
let peer_pub = public_key.into();
|
||||||
let shared_secret = self.private_key.as_diffie_hellman(&peer_pub).unwrap();
|
let shared_secret = self.private_key.as_diffie_hellman(&peer_pub).unwrap();
|
||||||
|
|
||||||
println!(
|
|
||||||
"Encryption Shared Secret (Hex): {}",
|
|
||||||
hex::encode(shared_secret.as_bytes())
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. Key & Nonce Derivation (HKDF)
|
|
||||||
// We derive 32 bytes for the key and 12 bytes for a deterministic nonce.
|
|
||||||
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
||||||
let mut okm = [0u8; 44]; // 32 (Key) + 12 (Nonce)
|
let mut okm = [0u8; 44];
|
||||||
hkdf.expand(b"x448-aes-gcm-no-overhead", &mut okm)
|
hkdf.expand(b"x448-aes-gcm-no-overhead", &mut okm)
|
||||||
.map_err(|_| SecurePayloadError::EncryptionError)?;
|
.map_err(|_| SecurePayloadError::EncryptionError)?;
|
||||||
|
|
||||||
let key = &okm[..32];
|
let key = &okm[..32];
|
||||||
let nonce_bytes = &okm[32..];
|
let nonce_bytes = &okm[32..];
|
||||||
|
|
||||||
// 4. Encrypt with AES-256-GCM
|
|
||||||
let cipher = Aes256Gcm::new(key.into());
|
let cipher = Aes256Gcm::new(key.into());
|
||||||
let nonce = Nonce::from_slice(nonce_bytes);
|
let nonce = Nonce::from_slice(nonce_bytes);
|
||||||
|
|
||||||
|
|
@ -138,7 +127,6 @@ impl SecurePayload {
|
||||||
)
|
)
|
||||||
.map_err(|_| SecurePayloadError::EncryptionError)?;
|
.map_err(|_| SecurePayloadError::EncryptionError)?;
|
||||||
|
|
||||||
// 5. Result is ONLY the ciphertext. No key or nonce is packed.
|
|
||||||
Ok(SecurePayload {
|
Ok(SecurePayload {
|
||||||
inner_data: ciphertext,
|
inner_data: ciphertext,
|
||||||
private_key: Secret::from_bytes(self.private_key.as_bytes()).unwrap(),
|
private_key: Secret::from_bytes(self.private_key.as_bytes()).unwrap(),
|
||||||
|
|
@ -160,17 +148,9 @@ impl SecurePayload {
|
||||||
&self,
|
&self,
|
||||||
peer_public_key_bytes: &[u8; 56],
|
peer_public_key_bytes: &[u8; 56],
|
||||||
) -> Result<SecurePayload, SecurePayloadError> {
|
) -> Result<SecurePayload, SecurePayloadError> {
|
||||||
// 1. Perform Exchange
|
|
||||||
let peer_pub = PublicKey::from_bytes(peer_public_key_bytes).unwrap();
|
let peer_pub = PublicKey::from_bytes(peer_public_key_bytes).unwrap();
|
||||||
let shared_secret = self.private_key.as_diffie_hellman(&peer_pub).unwrap();
|
let shared_secret = self.private_key.as_diffie_hellman(&peer_pub).unwrap();
|
||||||
|
|
||||||
// LOGGING: Shared Secret
|
|
||||||
println!(
|
|
||||||
"Decryption Shared Secret (Hex): {}",
|
|
||||||
hex::encode(shared_secret.as_bytes())
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. Key & Nonce Derivation (Must match encryption exactly)
|
|
||||||
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
||||||
let mut okm = [0u8; 44];
|
let mut okm = [0u8; 44];
|
||||||
hkdf.expand(b"x448-aes-gcm-no-overhead", &mut okm)
|
hkdf.expand(b"x448-aes-gcm-no-overhead", &mut okm)
|
||||||
|
|
@ -179,7 +159,6 @@ impl SecurePayload {
|
||||||
let key = &okm[..32];
|
let key = &okm[..32];
|
||||||
let nonce_bytes = &okm[32..];
|
let nonce_bytes = &okm[32..];
|
||||||
|
|
||||||
// 3. Decrypt with AES-256-GCM
|
|
||||||
let cipher = Aes256Gcm::new(key.into());
|
let cipher = Aes256Gcm::new(key.into());
|
||||||
let nonce = Nonce::from_slice(nonce_bytes);
|
let nonce = Nonce::from_slice(nonce_bytes);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::fs::{self, File};
|
|
||||||
use std::io::Read;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use sysinfo::System;
|
|
||||||
use uuid::Uuid;
|
|
||||||
use walkdir::WalkDir;
|
|
||||||
|
|
||||||
pub fn delete_file(path: &str, name: &str) -> bool {
|
|
||||||
let dir = Path::new(&get_directory()).join(path);
|
|
||||||
let file = dir.join(name);
|
|
||||||
if !file.exists() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fs::remove_file(file).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_directory(path: &str) -> bool {
|
|
||||||
let dir = Path::new(&get_directory()).join(path);
|
|
||||||
delete_dir_recursive(&dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_dir_recursive(directory: &Path) -> bool {
|
|
||||||
if !directory.exists() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if let Err(e) = fs::remove_dir_all(directory) {
|
|
||||||
println!(
|
|
||||||
"[IMPORTANT] Couldn't delete directory {}: {}",
|
|
||||||
directory.display(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_user_directory(user_id: Uuid) {
|
|
||||||
let user_dir = Path::new(&get_directory())
|
|
||||||
.join("users")
|
|
||||||
.join(user_id.to_string());
|
|
||||||
let _ = delete_dir_recursive(&user_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_file(path: &str, name: &str) -> String {
|
|
||||||
let dir = Path::new(&get_directory()).join(path);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut content = String::new();
|
|
||||||
if let Ok(mut f) = File::open(&file_path) {
|
|
||||||
let _ = f.read_to_string(&mut content);
|
|
||||||
}
|
|
||||||
content
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_file(path: &str, name: &str, value: &str) {
|
|
||||||
let dir = Path::new(&get_directory()).join(path);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = fs::write(&file_path, value) {
|
|
||||||
println!(
|
|
||||||
"[IMPORTANT] Couldn't write file {}: {}",
|
|
||||||
file_path.display(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_children(path: &str) -> Vec<String> {
|
|
||||||
let dir = Path::new(&get_directory()).join(path);
|
|
||||||
let mut children = Vec::new();
|
|
||||||
if let Ok(entries) = fs::read_dir(&dir) {
|
|
||||||
for entry in entries {
|
|
||||||
if let Ok(entry) = entry {
|
|
||||||
children.push(entry.file_name().to_string_lossy().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
children
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_directory() -> String {
|
|
||||||
let exe = std::env::current_exe().unwrap_or_else(|_| PathBuf::from("."));
|
|
||||||
exe.parent()
|
|
||||||
.unwrap_or(Path::new("."))
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn used_space() -> u64 {
|
|
||||||
get_directory_size(&PathBuf::from(get_directory()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_directory_size(directory: &Path) -> u64 {
|
|
||||||
let mut size = 0;
|
|
||||||
for entry in WalkDir::new(directory).into_iter().filter_map(|e| e.ok()) {
|
|
||||||
let path = entry.path();
|
|
||||||
if path.is_file() {
|
|
||||||
if let Ok(metadata) = path.metadata() {
|
|
||||||
size += path.file_name().unwrap_or(OsStr::new("")).len() as u64;
|
|
||||||
size += metadata.len();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_designed_storage(user_id: Uuid) -> String {
|
|
||||||
let user_dir = Path::new(&get_directory())
|
|
||||||
.join("users")
|
|
||||||
.join(user_id.to_string());
|
|
||||||
design_byte(get_directory_size(&user_dir))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn design_byte(bytes: u64) -> String {
|
|
||||||
let mut hr_size = format!("{:.2}B", bytes as f64);
|
|
||||||
let k = bytes as f64 / 1024.0;
|
|
||||||
let m = k / 1024.0;
|
|
||||||
let g = m / 1024.0;
|
|
||||||
let t = g / 1024.0;
|
|
||||||
|
|
||||||
if t >= 1.0 {
|
|
||||||
hr_size = format!("{:.2}TB", t);
|
|
||||||
} else if g >= 1.0 {
|
|
||||||
hr_size = format!("{:.2}GB", g);
|
|
||||||
} else if m >= 1.0 {
|
|
||||||
hr_size = format!("{:.2}MB", m);
|
|
||||||
} else if k >= 1.0 {
|
|
||||||
hr_size = format!("{:.2}KB", k);
|
|
||||||
}
|
|
||||||
hr_size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_used_ram() -> String {
|
|
||||||
let mut sys = System::new_all();
|
|
||||||
sys.refresh_all();
|
|
||||||
let used = sys.used_memory() * 1024; // kB to bytes
|
|
||||||
let total = sys.total_memory() * 1024;
|
|
||||||
format!("{}/{}", design_byte(used), design_byte(total))
|
|
||||||
}
|
|
||||||
|
|
@ -56,7 +56,7 @@ pub fn startup() {
|
||||||
let ts = fixed_box(&msg.timestamp_ms.to_string(), 13);
|
let ts = fixed_box(&msg.timestamp_ms.to_string(), 13);
|
||||||
let sender = match msg.sender {
|
let sender = match msg.sender {
|
||||||
Some(id) => fixed_box(&id.to_string(), 19),
|
Some(id) => fixed_box(&id.to_string(), 19),
|
||||||
None => fixed_box("", 19),
|
_ => fixed_box("", 19),
|
||||||
};
|
};
|
||||||
|
|
||||||
let line = format!("{} {} {} {}", ts, sender, msg.prefix, msg.message);
|
let line = format!("{} {} {} {}", ts, sender, msg.prefix, msg.message);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
pub mod config_util;
|
|
||||||
pub mod crypto_helper;
|
pub mod crypto_helper;
|
||||||
pub mod crypto_util;
|
pub mod crypto_util;
|
||||||
pub mod file_util;
|
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue