Config save and load start

This commit is contained in:
2025-12-09 00:56:09 +01:00
parent 7782e71990
commit 6dea63f818
6 changed files with 108 additions and 11 deletions

1
Cargo.lock generated
View File

@@ -1342,6 +1342,7 @@ checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [ dependencies = [
"getrandom 0.3.4", "getrandom 0.3.4",
"js-sys", "js-sys",
"serde_core",
"wasm-bindgen", "wasm-bindgen",
] ]

View File

@@ -33,4 +33,4 @@ thiserror = { version = "2.0.17", optional = true }
tokio = { version = "1.48.0", features = ["process", "rt-multi-thread", "macros", "io-std", "io-util"], optional = true } tokio = { version = "1.48.0", features = ["process", "rt-multi-thread", "macros", "io-std", "io-util"], optional = true }
tokio-stream = { version = "0.1.17", features = ["full", "io-util", "signal", "tokio-util"], optional = true } tokio-stream = { version = "0.1.17", features = ["full", "io-util", "signal", "tokio-util"], optional = true }
tokio-util = { version = "0.7.17", features = ["full"], optional = true } tokio-util = { version = "0.7.17", features = ["full"], optional = true }
uuid = { version = "1.19.0", features = ["v4"], optional = true } uuid = { version = "1.19.0", features = ["serde", "v4"], optional = true }

View File

@@ -3,18 +3,19 @@ use std::{
str::FromStr, str::FromStr,
}; };
use serde::{Deserialize, Serialize};
use tokio::sync::watch; use tokio::sync::watch;
use crate::error::VersionError; use crate::error::VersionError;
/// Identifies the type of Minecraft distribution supported by the configuration. /// Identifies the type of Minecraft distribution supported by the configuration.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum MinecraftType { pub enum MinecraftType {
Vanilla, Vanilla,
} }
/// Semantic release version parsed from strings like `1.20.4`. /// Semantic release version parsed from strings like `1.20.4`.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Version { pub struct Version {
pub major: u32, pub major: u32,
pub minor: u32, pub minor: u32,
@@ -22,7 +23,7 @@ pub struct Version {
} }
/// Snapshot version parsed from strings like `23w13b`. /// Snapshot version parsed from strings like `23w13b`.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Snapshot { pub struct Snapshot {
pub year: u32, pub year: u32,
pub week: u32, pub week: u32,
@@ -30,7 +31,7 @@ pub struct Snapshot {
} }
/// Enum covering both release and snapshot Minecraft version formats. /// Enum covering both release and snapshot Minecraft version formats.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum MinecraftVersion { pub enum MinecraftVersion {
Release(Version), Release(Version),
Snapshot(Snapshot), Snapshot(Snapshot),

View File

@@ -96,6 +96,9 @@ pub enum ServerError {
NoEULA, NoEULA,
#[error("Failed to write eula.txt")] #[error("Failed to write eula.txt")]
WriteEULAFailed, WriteEULAFailed,
#[error("File io error")]
FileIO,
} }
#[cfg(feature = "events")] #[cfg(feature = "events")]

View File

@@ -20,6 +20,7 @@ use crate::{
stream::{EventPayload, InternalEvent}, stream::{EventPayload, InternalEvent},
}, },
error::{HandleError, ServerError, SubscribeError}, error::{HandleError, ServerError, SubscribeError},
server::domain::MineGuardConfig,
}; };
use super::{InstanceData, InstanceStatus}; use super::{InstanceData, InstanceStatus};
@@ -44,6 +45,14 @@ pub struct InstanceHandle {
} }
impl InstanceHandle { impl InstanceHandle {
pub fn new_with_config(config: MineGuardConfig) -> Result<Self, HandleError> {
InstanceHandle::new_with_params(
config.server_dir,
config.jar_path,
config.mc_version,
config.mc_type,
)
}
pub fn new_with_params( pub fn new_with_params(
root_dir: PathBuf, root_dir: PathBuf,
jar_path: PathBuf, jar_path: PathBuf,

View File

@@ -1,7 +1,9 @@
use std::{ops::RangeInclusive, path::PathBuf, str::FromStr}; use std::{ops::RangeInclusive, path::PathBuf, str::FromStr};
use serde::{Deserialize, Serialize};
use serde_json::json;
use tokio::{ use tokio::{
fs::{File, create_dir}, fs::{File, create_dir, read, read_dir},
io::{self, AsyncWriteExt}, io::{self, AsyncWriteExt},
sync::{RwLock, watch}, sync::{RwLock, watch},
}; };
@@ -9,21 +11,23 @@ use tokio_stream::wrappers::BroadcastStream;
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
config::{MinecraftType, MinecraftVersion, StreamSource, Version, stream::InstanceEvent}, config::{self, MinecraftType, MinecraftVersion, StreamSource, Version, stream::InstanceEvent},
error::{CreationError, ServerError, SubscribeError}, error::{CreationError, ServerError, SubscribeError},
instance::InstanceHandle, instance::InstanceHandle,
manifests::vanilla::{VanillaManifestV2, VanillaManifestV2Version, VanillaReleaseManifest}, manifests::vanilla::{VanillaManifestV2, VanillaManifestV2Version, VanillaReleaseManifest},
server, server,
}; };
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MineGuardConfig { pub struct MineGuardConfig {
uuid: Uuid, uuid: Uuid,
server_dir: PathBuf, pub server_dir: PathBuf,
jar_path: PathBuf, pub jar_path: PathBuf,
mc_version: MinecraftVersion, pub mc_version: MinecraftVersion,
mc_type: MinecraftType, pub mc_type: MinecraftType,
} }
#[derive(Debug)]
pub struct MineGuardServer { pub struct MineGuardServer {
pub handle: RwLock<InstanceHandle>, pub handle: RwLock<InstanceHandle>,
pub config: RwLock<MineGuardConfig>, pub config: RwLock<MineGuardConfig>,
@@ -42,6 +46,15 @@ impl MineGuardConfig {
} }
impl MineGuardServer { impl MineGuardServer {
async fn load_cfg_handle(
config: MineGuardConfig,
handle: InstanceHandle,
) -> Result<Self, CreationError> {
Ok(Self {
config: RwLock::new(config),
handle: RwLock::new(handle),
})
}
pub async fn create( pub async fn create(
mc_version: MinecraftVersion, mc_version: MinecraftVersion,
mc_type: MinecraftType, mc_type: MinecraftType,
@@ -62,6 +75,11 @@ impl MineGuardServer {
.await .await
.map_err(|_| CreationError::DirectoryError)?; .map_err(|_| CreationError::DirectoryError)?;
let internal_dir = server_root.join(".mineguard");
create_dir(internal_dir)
.await
.map_err(|_| CreationError::DirectoryError)?;
let mut url = String::new(); let mut url = String::new();
if mc_type == MinecraftType::Vanilla { if mc_type == MinecraftType::Vanilla {
@@ -162,4 +180,69 @@ impl MineGuardServer {
Ok(()) Ok(())
} }
pub async fn write_config(&self) -> Result<(), ServerError> {
let config_r = self.config.read().await;
let root_path = config_r.server_dir.clone();
let config_clone = config_r.clone();
drop(config_r);
let config_path = root_path.join(".mineguard/config.json");
let json = serde_json::to_vec_pretty(&config_clone).map_err(|_| ServerError::FileIO)?;
File::create(config_path)
.await
.map_err(|_| ServerError::FileIO)?
.write_all(&json)
.await
.map_err(|_| ServerError::FileIO)?;
Ok(())
}
pub async fn load(path: &PathBuf) -> Result<Self, CreationError> {
let config_path = path.join(".mineguard/config.json");
let data = read(config_path)
.await
.map_err(|_| CreationError::DirectoryError)?;
let config: MineGuardConfig =
serde_json::from_slice(&data).map_err(|_| CreationError::CreationError)?;
let handle = InstanceHandle::new_with_config(config.clone())
.map_err(|_| CreationError::CreationError)?;
MineGuardServer::load_cfg_handle(config, handle).await
}
pub async fn load_all(path: PathBuf) -> Result<Vec<Self>, CreationError> {
let mut dirs = Vec::new();
let mut entries = read_dir(path)
.await
.map_err(|_| CreationError::DirectoryError)?;
while let Some(entry) = entries
.next_entry()
.await
.map_err(|_| CreationError::DirectoryError)?
{
let meta = entry
.metadata()
.await
.map_err(|_| CreationError::DirectoryError)?;
if meta.is_dir() {
dirs.push(entry.path());
}
}
let mut servers: Vec<Self> = Vec::new();
for v in dirs {
println!("{}", v.to_str().unwrap());
servers.push(Self::load(&v).await?);
}
Ok(servers)
}
} }