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:
parent
70b75a0ac5
commit
698589806a
@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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| {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user