fix: don't crash when failed to lock session.lock

fix: https://github.com/Pumpkin-MC/Pumpkin/issues/1212
fix: https://github.com/Pumpkin-MC/Pumpkin/issues/1194
This commit is contained in:
Alexander Medvedev 2025-12-05 16:57:41 +01:00
parent 70b75a0ac5
commit 698589806a
3 changed files with 23 additions and 8 deletions

View File

@ -1,6 +1,10 @@
use super::{LevelLocker, LockError};
use std::{fs::File, io::Write, path::Path};
use std::{
fs::{File, TryLockError},
io::Write,
path::Path,
};
pub struct AnvilLevelLocker {
_locked_file: File,
@ -23,8 +27,12 @@ impl LevelLocker<Self> for AnvilLevelLocker {
// im not joking, mojang writes a snowman into the lock file
file.write_all(SNOWMAN)
.map_err(|_| LockError::FailedWrite)?;
file.try_lock()
.map_err(|_| LockError::AlreadyLocked(SESSION_LOCK_FILE_NAME.to_string()))?;
file.try_lock().map_err(|e| match e {
TryLockError::WouldBlock => {
LockError::AlreadyLocked(SESSION_LOCK_FILE_NAME.to_string())
}
TryLockError::Error(io_err) => LockError::Error(io_err),
})?;
Ok(Self { _locked_file: file })
}
}

View File

@ -13,6 +13,8 @@ pub trait LevelLocker<T>: Send + Sync {
pub enum LockError {
#[error("Oh no, Level is already locked by {0}")]
AlreadyLocked(String),
#[error("{0}")]
Error(std::io::Error),
#[error("Failed to write into lock file")]
FailedWrite,
}

View File

@ -102,7 +102,7 @@ pub struct Server {
world_info_writer: Arc<dyn WorldInfoWriter>,
// Gets unlocked when dropped
// TODO: Make this a trait
_locker: Arc<AnvilLevelLocker>,
_locker: Arc<Option<AnvilLevelLocker>>,
}
impl Server {
@ -138,10 +138,15 @@ impl Server {
fs::copy(dat_path, backup_path).unwrap();
}
}
// if we fail to lock, lets crash ???. maybe not the best solution when we have a large server with many worlds and one is locked.
// So TODO
let locker = AnvilLevelLocker::lock(&world_path).expect("Failed to lock level");
let locker = match AnvilLevelLocker::lock(&world_path) {
Ok(l) => Some(l),
Err(err) => {
log::warn!(
"Could not lock the level file. Data corruption is possible if the world is accessed by multiple processes simultaneously. Error: {err}"
);
None
}
};
let player_data_path = world_path.join("playerdata");
let level_info = level_info.unwrap_or_else(|err| {