Initial auto create impl

This commit is contained in:
2025-12-07 20:31:05 +01:00
parent 6b2757a52f
commit 668870b92e
6 changed files with 167 additions and 20 deletions

12
Cargo.lock generated
View File

@@ -20,6 +20,17 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "atomic-waker" name = "atomic-waker"
version = "1.1.2" version = "1.1.2"
@@ -618,6 +629,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
name = "mineguard" name = "mineguard"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"chrono", "chrono",
"regex", "regex",
"reqwest", "reqwest",

View File

@@ -21,6 +21,7 @@ mc-vanilla = ["dep:serde", "dep:serde_json", "dep:reqwest"]
# Add new feature groups here; attach their optional dependencies to the relevant feature list. # Add new feature groups here; attach their optional dependencies to the relevant feature list.
[dependencies] [dependencies]
async-trait = "0.1.89"
chrono = {version = "0.4.42", optional = true} chrono = {version = "0.4.42", optional = true}
regex = {version = "1.12.2", optional = true} regex = {version = "1.12.2", optional = true}
reqwest = { version = "0.12.24", optional = true, features = ["json"] } reqwest = { version = "0.12.24", optional = true, features = ["json"] }

View File

@@ -107,6 +107,15 @@ pub enum CreationError {
#[error("Invalid directory")] #[error("Invalid directory")]
DirectoryError, DirectoryError,
#[error("Failed to parse manifest")]
ManifestError,
#[error("Version does not exist")]
VersionError,
#[error("Network Error")]
NetworkError,
} }
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]
pub enum ManifestError { pub enum ManifestError {

View File

@@ -41,24 +41,26 @@ pub struct InstanceHandle {
impl InstanceHandle { impl InstanceHandle {
pub fn new_with_params( pub fn new_with_params(
root_dir: &str, root_dir: PathBuf,
jar_path: &str, jar_path: PathBuf,
mc_version: &str, mc_version: MinecraftVersion,
mc_type: MinecraftType, mc_type: MinecraftType,
) -> Result<Self, HandleError> { ) -> Result<Self, HandleError> {
let parsed_version: MinecraftVersion = mc_version let parsed_version: MinecraftVersion = mc_version;
.parse()
.map_err(|_| HandleError::InvalidVersion(mc_version.to_string()))?;
let root: PathBuf = root_dir.into(); let root: PathBuf = root_dir.clone().into();
if !root.exists() || !root.is_dir() { if !root.exists() || !root.is_dir() {
return Err(HandleError::InvalidDirectory(root_dir.to_string())); return Err(HandleError::InvalidDirectory(
root_dir.to_str().unwrap().to_string(),
));
} }
let path: PathBuf = jar_path.into(); let path: PathBuf = jar_path.clone().into();
let conc = root.join(path.clone()); let conc = root.join(path.clone());
if !path.is_relative() || !conc.is_file() { if !path.is_relative() || !conc.is_file() {
return Err(HandleError::InvalidPathJAR(jar_path.to_string())); return Err(HandleError::InvalidPathJAR(
jar_path.to_str().unwrap().to_string(),
));
} }
let data = InstanceData { let data = InstanceData {

View File

@@ -1,5 +1,6 @@
#![cfg(feature = "mc-vanilla")] #![cfg(feature = "mc-vanilla")]
use async_trait::async_trait;
use reqwest::Client; use reqwest::Client;
use serde::Deserialize; use serde::Deserialize;
@@ -12,13 +13,13 @@ pub struct VanillaManifestV2 {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
struct VanillaManifestV2Latest { pub struct VanillaManifestV2Latest {
release: String, release: String,
snapshot: String, snapshot: String,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
struct VanillaManifestV2Version { pub struct VanillaManifestV2Version {
id: String, id: String,
#[serde(rename = "type")] #[serde(rename = "type")]
mc_type: String, mc_type: String,
@@ -28,7 +29,52 @@ struct VanillaManifestV2Version {
release_time: String, release_time: String,
sha1: String, sha1: String,
#[serde(rename = "complianceLevel")] #[serde(rename = "complianceLevel")]
compliance_level: String, compliance_level: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct VanillaReleaseManifest {
downloads: VanillaReleaseManifestDownloads,
}
#[derive(Debug, Clone, Deserialize)]
pub struct VanillaReleaseManifestDownloads {
client: VanillaReleaseManifestDownloadsItem,
client_mappings: VanillaReleaseManifestDownloadsItem,
server: VanillaReleaseManifestDownloadsItem,
server_mappings: VanillaReleaseManifestDownloadsItem,
}
#[derive(Debug, Clone, Deserialize)]
pub struct VanillaReleaseManifestDownloadsItem {
sha1: String,
size: u32,
url: String,
}
impl VanillaReleaseManifest {
pub async fn load(version: VanillaManifestV2Version) -> Result<Self, ManifestError> {
let client = Client::new();
let manifest: VanillaReleaseManifest = client
.get(&version.url)
.send()
.await
.map_err(|_| ManifestError::LoadUrlError)?
.error_for_status()
.map_err(|_| ManifestError::LoadUrlError)?
.json()
.await
.map_err(|e| {
eprintln!("{}", e);
ManifestError::JsonParseError
})?;
Ok(manifest)
}
pub fn server_url(&self) -> String {
self.downloads.server.url.clone()
}
} }
impl VanillaManifestV2 { impl VanillaManifestV2 {
@@ -44,7 +90,10 @@ impl VanillaManifestV2 {
.map_err(|_| ManifestError::LoadUrlError)? .map_err(|_| ManifestError::LoadUrlError)?
.json() .json()
.await .await
.map_err(|_| ManifestError::JsonParseError)?; .map_err(|e| {
eprintln!("{}", e);
ManifestError::JsonParseError
})?;
Ok(manifest) Ok(manifest)
} }

View File

@@ -1,12 +1,18 @@
use std::{path::PathBuf, str::FromStr}; use std::{ops::RangeInclusive, path::PathBuf, str::FromStr};
use tokio::sync::RwLock; use tokio::{
fs::{File, create_dir},
io::{self, AsyncWriteExt},
sync::RwLock,
};
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
config::{MinecraftType, MinecraftVersion, Version}, config::{MinecraftType, MinecraftVersion, Version},
error::CreationError, error::CreationError,
instance::InstanceHandle, instance::InstanceHandle,
manifests::vanilla::{VanillaManifestV2, VanillaManifestV2Version, VanillaReleaseManifest},
server,
}; };
pub struct MineGuardConfig { pub struct MineGuardConfig {
@@ -18,8 +24,8 @@ pub struct MineGuardConfig {
} }
pub struct MineGuardServer { pub struct MineGuardServer {
handle: RwLock<InstanceHandle>, pub handle: RwLock<InstanceHandle>,
config: RwLock<MineGuardConfig>, pub config: RwLock<MineGuardConfig>,
} }
impl MineGuardConfig { impl MineGuardConfig {
@@ -35,7 +41,7 @@ impl MineGuardConfig {
} }
impl MineGuardServer { impl MineGuardServer {
pub fn create( pub async fn create(
mc_version: MinecraftVersion, mc_version: MinecraftVersion,
mc_type: MinecraftType, mc_type: MinecraftType,
directory: PathBuf, directory: PathBuf,
@@ -44,6 +50,74 @@ impl MineGuardServer {
return Err(CreationError::DirectoryError); return Err(CreationError::DirectoryError);
} }
todo!() let uuid = Uuid::new_v4();
let server_root = directory.join(uuid.to_string());
let jar_path_rel =
PathBuf::from_str("server.jar").map_err(|_| CreationError::DirectoryError)?;
let jar_path_full = server_root.join(jar_path_rel.clone());
create_dir(server_root.clone())
.await
.map_err(|_| CreationError::DirectoryError)?;
let mut url = String::new();
if mc_type == MinecraftType::Vanilla {
let vanilla_manifest = VanillaManifestV2::load()
.await
.map_err(|_| CreationError::ManifestError)?;
let find_ver = match vanilla_manifest
.find(mc_version.clone())
.map_err(|_| CreationError::ManifestError)?
{
Some(val) => val,
None => return Err(CreationError::VersionError),
};
let release_manifest = VanillaReleaseManifest::load(find_ver)
.await
.map_err(|_| CreationError::ManifestError)?;
url = release_manifest.server_url();
}
let resp = reqwest::get(url)
.await
.map_err(|_| CreationError::NetworkError)?;
let mut body = resp
.bytes()
.await
.map_err(|_| CreationError::NetworkError)?;
let mut out = File::create(jar_path_full)
.await
.map_err(|_| CreationError::DirectoryError)?;
out.write_all_buf(&mut body)
.await
.map_err(|_| CreationError::DirectoryError)?;
let config = MineGuardConfig {
uuid: uuid,
server_dir: server_root,
jar_path: jar_path_rel,
mc_version: mc_version,
mc_type: mc_type,
};
let handle = InstanceHandle::new_with_params(
config.server_dir.clone(),
config.jar_path.clone(),
config.mc_version.clone(),
config.mc_type.clone(),
)
.map_err(|_| CreationError::CreationError)?;
let server = MineGuardServer {
config: RwLock::new(config),
handle: RwLock::new(handle),
};
Ok(server)
} }
} }