blob: 0dee96c7fdd20e29f56a84451a5daf23f939a531 [file]
use compio::{fs::create_dir_all, runtime::Runtime};
use iggy_common::{
IggyError,
defaults::{
DEFAULT_ROOT_PASSWORD, DEFAULT_ROOT_USERNAME, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH,
MIN_PASSWORD_LENGTH, MIN_USERNAME_LENGTH,
},
};
use tracing::info;
use crate::{
IGGY_ROOT_PASSWORD_ENV, IGGY_ROOT_USERNAME_ENV,
configs::{config_provider::ConfigProviderKind, server::ServerConfig, system::SystemConfig},
io::fs_utils,
server_error::ServerError,
shard::transmission::{
connector::{ShardConnector, StopSender},
frame::ShardFrame,
},
streaming::{
persistence::persister::{FilePersister, FileWithSyncPersister, PersisterKind},
users::user::User,
utils::file::overwrite,
},
};
use std::{collections::HashSet, env, ops::Range, path::Path, sync::Arc};
pub fn create_shard_connections(
shards_set: Range<usize>,
) -> (Vec<ShardConnector<ShardFrame>>, Vec<(u16, StopSender)>) {
let shards_count = shards_set.len();
let connectors: Vec<ShardConnector<ShardFrame>> = shards_set
.into_iter()
.map(|id| ShardConnector::new(id as u16, shards_count))
.collect();
let shutdown_handles = connectors
.iter()
.map(|conn| (conn.id, conn.stop_sender.clone()))
.collect();
(connectors, shutdown_handles)
}
pub async fn load_config(
config_provider: &ConfigProviderKind,
) -> Result<ServerConfig, ServerError> {
let config = ServerConfig::load(config_provider).await?;
Ok(config)
}
pub async fn create_directories(config: &SystemConfig) -> Result<(), IggyError> {
let system_path = config.get_system_path();
if !Path::new(&system_path).exists() && create_dir_all(&system_path).await.is_err() {
return Err(IggyError::CannotCreateBaseDirectory(system_path));
}
let state_path = config.get_state_path();
if !Path::new(&state_path).exists() && create_dir_all(&state_path).await.is_err() {
return Err(IggyError::CannotCreateStateDirectory(state_path));
}
let state_log = config.get_state_messages_file_path();
if !Path::new(&state_log).exists() && (overwrite(&state_log).await).is_err() {
return Err(IggyError::CannotCreateStateDirectory(state_log));
}
let streams_path = config.get_streams_path();
if !Path::new(&streams_path).exists() && create_dir_all(&streams_path).await.is_err() {
return Err(IggyError::CannotCreateStreamsDirectory(streams_path));
}
let runtime_path = config.get_runtime_path();
if Path::new(&runtime_path).exists() && fs_utils::remove_dir_all(&runtime_path).await.is_err() {
return Err(IggyError::CannotRemoveRuntimeDirectory(runtime_path));
}
if create_dir_all(&runtime_path).await.is_err() {
return Err(IggyError::CannotCreateRuntimeDirectory(runtime_path));
}
info!(
"Initializing system, data will be stored at: {}",
config.get_system_path()
);
Ok(())
}
pub fn create_root_user() -> User {
info!("Creating root user...");
let username = env::var(IGGY_ROOT_USERNAME_ENV);
let password = env::var(IGGY_ROOT_PASSWORD_ENV);
if (username.is_ok() && password.is_err()) || (username.is_err() && password.is_ok()) {
panic!(
"When providing the custom root user credentials, both username and password must be set."
);
}
if username.is_ok() && password.is_ok() {
info!("Using the custom root user credentials.");
} else {
info!("Using the default root user credentials.");
}
let username = username.unwrap_or(DEFAULT_ROOT_USERNAME.to_string());
let password = password.unwrap_or(DEFAULT_ROOT_PASSWORD.to_string());
if username.is_empty() || password.is_empty() {
panic!("Root user credentials are not set.");
}
if username.len() < MIN_USERNAME_LENGTH {
panic!("Root username is too short.");
}
if username.len() > MAX_USERNAME_LENGTH {
panic!("Root username is too long.");
}
if password.len() < MIN_PASSWORD_LENGTH {
panic!("Root password is too short.");
}
if password.len() > MAX_PASSWORD_LENGTH {
panic!("Root password is too long.");
}
let user = User::root(&username, &password);
user
}
pub fn create_shard_executor(cpu_set: HashSet<usize>) -> Runtime {
// TODO: The event intererval tick, could be configured based on the fact
// How many clients we expect to have connected.
// This roughly estimates the number of tasks we will create.
let mut proactor = compio::driver::ProactorBuilder::new();
proactor
.capacity(4096)
.coop_taskrun(true)
.taskrun_flag(false); // TODO: Try enabling this.
// FIXME(hubcio): Only set thread_pool_limit(0) on non-macOS platforms
// This causes a freeze on macOS with compio fs operations
// see https://github.com/compio-rs/compio/issues/446
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
proactor.thread_pool_limit(0);
compio::runtime::RuntimeBuilder::new()
.with_proactor(proactor.to_owned())
.event_interval(1024)
.thread_affinity(cpu_set)
.build()
.unwrap()
}
pub fn resolve_persister(enforce_fsync: bool) -> Arc<PersisterKind> {
match enforce_fsync {
true => Arc::new(PersisterKind::FileWithSync(FileWithSyncPersister)),
false => Arc::new(PersisterKind::File(FilePersister)),
}
}