use std::{
collections::HashMap,
fs::{File, create_dir_all},
io::Write,
path::{Path, PathBuf},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};
use glam::{U16Vec2, Vec2};
use serde::Serialize;
use sqlx::{Pool, Sqlite};
use uuid::Uuid;
use crate::errors::SessionError;
pub static CACHE_ENABLED: AtomicBool = AtomicBool::new(true);
pub fn cache_enabled() -> bool {
CACHE_ENABLED.load(Ordering::Relaxed)
}
pub fn set_cache_enabled(enabled: bool) {
CACHE_ENABLED.store(enabled, Ordering::Relaxed);
}
#[derive(Debug)]
pub struct Session<Capability, Avatar, Land, UdpSocket> {
pub address: String,
pub agent_id: Uuid,
pub session_id: Uuid,
pub socket: Option<Arc<UdpSocket>>,
pub sequence_number: u16,
pub local_ip: std::net::IpAddr,
pub seed_capability_url: String,
pub capability_urls: HashMap<Capability, String>,
pub inventory_data: InventoryData,
pub environment_cache: EnvironmentCache<Land>,
pub avatars: HashMap<Uuid, Avatar>,
pub region_data: RegionData,
pub inventory_db_connection: Pool<Sqlite>,
}
#[derive(Debug, Default)]
pub struct RegionData {
pub water_height: f32,
pub last_time_update: u64,
pub region_coordinates: Vec2,
pub region_id: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ServerState {
Starting,
Running,
Stopping,
Stopped,
}
#[derive(Debug)]
pub struct InventoryData {
pub inventory_root: Uuid,
pub inventory_lib_owner: Uuid,
pub inventory_init: bool,
}
#[derive(Debug)]
pub struct EnvironmentCache<Land> {
pub patch_queue: HashMap<U16Vec2, Land>,
pub patch_cache: HashMap<U16Vec2, Land>,
}
fn create_sub_dir(base: &Path, name: &str) -> Result<PathBuf, SessionError> {
let dir = base.join(name);
create_dir_all(&dir).map_err(|e| SessionError::DirCreation {
dir: dir.clone(),
error: e,
})?;
Ok(dir)
}
pub fn initialize_share_dir() -> Result<PathBuf, SessionError> {
let data_dir = dirs::data_dir().ok_or(SessionError::NotFound {})?;
let share_dir = data_dir.join("benthic");
create_dir_all(&share_dir).map_err(|e| SessionError::DirCreation {
dir: share_dir.clone(),
error: e,
})?;
Ok(share_dir)
}
pub fn create_sub_share_dir(name: &str) -> Result<PathBuf, SessionError> {
let share_dir = initialize_share_dir()?;
create_sub_dir(&share_dir, name)
}
pub fn create_sub_agent_dir(name: &str) -> Result<PathBuf, SessionError> {
let agent_dir = create_sub_share_dir("agent")?;
create_sub_dir(&agent_dir, name)
}
pub fn create_sub_object_dir(name: &str) -> Result<PathBuf, SessionError> {
let land_dir = create_sub_share_dir("object")?;
create_sub_dir(&land_dir, name)
}
pub fn create_sub_land_dir() -> Result<PathBuf, SessionError> {
create_sub_share_dir("land")
}
pub fn create_animation_dir() -> Result<PathBuf, SessionError> {
let share_dir = initialize_share_dir()?;
create_sub_dir(&share_dir, "animations")
}
pub fn create_filtered_animations_dir() -> Result<PathBuf, SessionError> {
let animations_dir = create_animation_dir()?;
create_sub_dir(&animations_dir, "filtered_animations")
}
pub fn create_filtered_animation_dir(animation_id: &Uuid) -> Result<PathBuf, SessionError> {
let filtered_dir = create_filtered_animations_dir()?;
create_sub_dir(&filtered_dir, &animation_id.to_string())
}
pub fn create_animation_agents_dir() -> Result<PathBuf, SessionError> {
let animations_dir = create_animation_dir()?;
create_sub_dir(&animations_dir, "agents")
}
pub fn create_agent_animation_dir(agent_id: &Uuid) -> Result<PathBuf, SessionError> {
let agents_dir = create_animation_agents_dir()?;
create_sub_dir(&agents_dir, &agent_id.to_string())
}
pub enum CacheDir {
Agent(Uuid),
Object(Uuid),
Land,
}
pub fn write_json<T: Serialize>(
data: &T,
filename: &str,
cache_dir: CacheDir,
) -> Result<PathBuf, SessionError> {
let dir = match cache_dir {
CacheDir::Agent(id) => create_sub_agent_dir(&id.to_string())?,
CacheDir::Object(id) => create_sub_object_dir(&id.to_string())?,
CacheDir::Land => create_sub_land_dir()?,
};
let path = dir.join(format!("{filename}.json"));
let json =
serde_json::to_string(data).map_err(|error| SessionError::JsonWriteError { error })?;
let mut file = File::create(&path)?;
file.write_all(json.as_bytes())?;
Ok(path)
}