This should prevent some dead locks
This commit is contained in:
parent
577f51dc1b
commit
03b3ff5e15
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -125,9 +125,9 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-compression"
|
name = "async-compression"
|
||||||
version = "0.4.33"
|
version = "0.4.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93c1f86859c1af3d514fa19e8323147ff10ea98684e6c7b307912509f50e67b2"
|
checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compression-codecs",
|
"compression-codecs",
|
||||||
"compression-core",
|
"compression-core",
|
||||||
@ -416,9 +416,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compression-codecs"
|
name = "compression-codecs"
|
||||||
version = "0.4.32"
|
version = "0.4.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "680dc087785c5230f8e8843e2e57ac7c1c90488b6a91b88caa265410568f441b"
|
checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compression-core",
|
"compression-core",
|
||||||
"flate2",
|
"flate2",
|
||||||
@ -426,9 +426,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compression-core"
|
name = "compression-core"
|
||||||
version = "0.4.30"
|
version = "0.4.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a9b614a5787ef0c8802a55766480563cb3a93b435898c422ed2a359cf811582"
|
checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console-api"
|
name = "console-api"
|
||||||
@ -655,13 +655,13 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossfire"
|
name = "crossfire"
|
||||||
version = "2.1.6"
|
version = "2.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6b5ad0a8e719cef020e136986d534068ffd35df287ab1635ff242585c02213e"
|
checksum = "121161e240fcedaef95067636249fd1200e76921a2f0b101dca1648ba6d7ffa5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"futures",
|
"futures-core",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ aes = "0.8"
|
|||||||
cfb8 = "0.8"
|
cfb8 = "0.8"
|
||||||
|
|
||||||
# compression
|
# compression
|
||||||
async-compression = { version = "0.4.33", features = ["tokio", "zlib"] }
|
async-compression = { version = "0.4.34", features = ["tokio", "zlib"] }
|
||||||
|
|
||||||
take_mut = "0.2.2"
|
take_mut = "0.2.2"
|
||||||
bitflags = "2.10.0"
|
bitflags = "2.10.0"
|
||||||
|
|||||||
@ -38,15 +38,15 @@ impl VarInt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
||||||
let mut val = self.0;
|
// Must cast to u32 to prevent infinite loops on negative i32s
|
||||||
loop {
|
let mut val = self.0 as u32;
|
||||||
let b: u8 = val as u8 & 0x7F;
|
|
||||||
|
while val > 0x7F {
|
||||||
|
write.write_u8((val as u8) | 0x80)?;
|
||||||
val >>= 7;
|
val >>= 7;
|
||||||
write.write_u8(if val == 0 { b } else { b | 0x80 })?;
|
|
||||||
if val == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write.write_u8(val as u8)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,17 +201,14 @@ impl<'de> Deserialize<'de> for VarInt {
|
|||||||
|
|
||||||
impl PacketWrite for VarInt {
|
impl PacketWrite for VarInt {
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
let mut val = (self.0 << 1) ^ (self.0 >> 31);
|
let mut val = ((self.0 << 1) ^ (self.0 >> 31)) as u32;
|
||||||
loop {
|
|
||||||
let b: u8 = val as u8 & 0b01111111;
|
while val > 0x7F {
|
||||||
|
((val as u8 & 0x7F) | 0x80).write(writer)?;
|
||||||
val >>= 7;
|
val >>= 7;
|
||||||
if val == 0 {
|
|
||||||
b.write(writer)?;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
(b | 0b10000000).write(writer)?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(val as u8).write(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,27 +27,15 @@ impl VarLong {
|
|||||||
/// The maximum number of bytes a `VarLong` can occupy.
|
/// The maximum number of bytes a `VarLong` can occupy.
|
||||||
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
||||||
|
|
||||||
/// Returns the exact number of bytes this VarLong will write when
|
|
||||||
/// [`Encode::encode`] is called, assuming no error occurs.
|
|
||||||
pub fn written_size(&self) -> usize {
|
|
||||||
match self.0 {
|
|
||||||
0 => 1,
|
|
||||||
n => (31 - n.leading_zeros() as usize) / 7 + 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
||||||
let mut x = self.0;
|
let mut val = self.0 as u64;
|
||||||
loop {
|
|
||||||
let byte = (x & 0x7F) as u8;
|
while val > 0x7F {
|
||||||
x >>= 7;
|
write.write_u8((val as u8) | 0x80)?;
|
||||||
if x == 0 {
|
val >>= 7;
|
||||||
write.write_u8(byte)?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
write.write_u8(byte | 0x80)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write.write_u8(val as u8)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +44,8 @@ impl VarLong {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..Self::MAX_SIZE.get() {
|
for i in 0..Self::MAX_SIZE.get() {
|
||||||
let byte = read.get_u8()?;
|
let byte = read.get_u8()?;
|
||||||
val |= (i64::from(byte) & 0b01111111) << (i * 7);
|
val |= (i64::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarLong(val));
|
return Ok(VarLong(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,15 +146,14 @@ impl<'de> Deserialize<'de> for VarLong {
|
|||||||
|
|
||||||
impl PacketWrite for VarLong {
|
impl PacketWrite for VarLong {
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
let mut value = (self.0 << 1) ^ (self.0 >> 63);
|
let mut val = ((self.0 << 1) ^ (self.0 >> 63)) as u64;
|
||||||
loop {
|
|
||||||
let b: u8 = value as u8 & 127;
|
while val > 0x7F {
|
||||||
value >>= 7;
|
((val as u8 & 0x7F) | 0x80).write(writer)?;
|
||||||
writer.write_all(&if value == 0 { [b] } else { [b | 128] })?;
|
val >>= 7;
|
||||||
if value == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(val as u8).write(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ rand = "=0.10.0-rc.5"
|
|||||||
num_cpus = "1.17.0"
|
num_cpus = "1.17.0"
|
||||||
rustc-hash = "2.1.1"
|
rustc-hash = "2.1.1"
|
||||||
slotmap = "1.0"
|
slotmap = "1.0"
|
||||||
crossfire = "2.1.6"
|
crossfire = "2.1.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { version = "0.7", default-features = false, features = ["html_reports", "async_tokio"] }
|
criterion = { version = "0.7", default-features = false, features = ["html_reports", "async_tokio"] }
|
||||||
|
|||||||
@ -4,8 +4,12 @@ use rustyline_async::Readline;
|
|||||||
use simplelog::{CombinedLogger, Config, SharedLogger, WriteLogger};
|
use simplelog::{CombinedLogger, Config, SharedLogger, WriteLogger};
|
||||||
use std::fmt::format;
|
use std::fmt::format;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufWriter;
|
use std::io::{self, BufWriter};
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
use time::{Duration, OffsetDateTime, UtcOffset};
|
||||||
|
|
||||||
|
const LOG_DIR: &str = "logs";
|
||||||
|
const MAX_ATTEMPTS: u32 = 100;
|
||||||
|
|
||||||
/// A wrapper for our logger to hold the terminal input while no input is expected in order to
|
/// A wrapper for our logger to hold the terminal input while no input is expected in order to
|
||||||
/// properly flush logs to the output while they happen instead of batched
|
/// properly flush logs to the output while they happen instead of batched
|
||||||
@ -34,65 +38,85 @@ impl GzipRollingLogger {
|
|||||||
filename: String,
|
filename: String,
|
||||||
) -> Result<Box<Self>, Box<dyn std::error::Error>> {
|
) -> Result<Box<Self>, Box<dyn std::error::Error>> {
|
||||||
let now = time::OffsetDateTime::now_utc();
|
let now = time::OffsetDateTime::now_utc();
|
||||||
std::fs::create_dir_all("logs")?;
|
std::fs::create_dir_all(LOG_DIR)?;
|
||||||
|
|
||||||
|
let latest_path = PathBuf::from(LOG_DIR).join(&filename);
|
||||||
|
|
||||||
// If latest.log exists, we will gzip it
|
// If latest.log exists, we will gzip it
|
||||||
if Path::new(&format!("logs/{filename}")).exists() {
|
if latest_path.exists() {
|
||||||
let new_filename = Self::new_filename(false);
|
eprintln!(
|
||||||
let mut file = File::open(format!("logs/{filename}"))?;
|
"Found existing log file at '{}', gzipping it now...",
|
||||||
|
latest_path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_gz_path = Self::new_filename(true)?;
|
||||||
|
|
||||||
|
let mut file = File::open(&latest_path)?;
|
||||||
|
|
||||||
let mut encoder = GzEncoder::new(
|
let mut encoder = GzEncoder::new(
|
||||||
BufWriter::new(File::create(&new_filename)?),
|
BufWriter::new(File::create(&new_gz_path)?),
|
||||||
flate2::Compression::best(),
|
flate2::Compression::best(),
|
||||||
);
|
);
|
||||||
std::io::copy(&mut file, &mut encoder)?;
|
|
||||||
|
io::copy(&mut file, &mut encoder)?;
|
||||||
encoder.finish()?;
|
encoder.finish()?;
|
||||||
|
|
||||||
|
std::fs::remove_file(&latest_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let new_logger = WriteLogger::new(log_level, config.clone(), File::create(&latest_path)?);
|
||||||
|
|
||||||
Ok(Box::new(Self {
|
Ok(Box::new(Self {
|
||||||
log_level,
|
log_level,
|
||||||
data: std::sync::Mutex::new(GzipRollingLoggerData {
|
data: std::sync::Mutex::new(GzipRollingLoggerData {
|
||||||
current_day_of_month: now.day(),
|
current_day_of_month: now.day(),
|
||||||
last_rotate_time: now,
|
last_rotate_time: now,
|
||||||
latest_filename: filename.clone(),
|
latest_filename: filename,
|
||||||
latest_logger: *WriteLogger::new(
|
latest_logger: *new_logger,
|
||||||
log_level,
|
|
||||||
config.clone(),
|
|
||||||
File::create(format!("logs/{filename}")).unwrap(),
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
config,
|
config,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_filename(yesterday: bool) -> String {
|
pub fn new_filename(yesterday: bool) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
let mut now = time::OffsetDateTime::now_utc()
|
let local_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
|
||||||
.to_offset(time::UtcOffset::current_local_offset().unwrap_or(time::UtcOffset::UTC));
|
let mut now = OffsetDateTime::now_utc().to_offset(local_offset);
|
||||||
if yesterday {
|
|
||||||
now -= time::Duration::days(1)
|
|
||||||
}
|
|
||||||
let base_filename = format!("{}-{:02}-{:02}", now.year(), now.month() as u8, now.day());
|
|
||||||
|
|
||||||
let mut id = 1;
|
if yesterday {
|
||||||
loop {
|
now -= Duration::days(1);
|
||||||
let filename = format!("logs/{base_filename}-{id}.log.gz");
|
|
||||||
if !Path::new(&filename).exists() {
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
id += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let date_format = format!("{}-{:02}-{:02}", now.year(), now.month() as u8, now.day());
|
||||||
|
|
||||||
|
let log_path = PathBuf::from(LOG_DIR);
|
||||||
|
|
||||||
|
for id in 1..=MAX_ATTEMPTS {
|
||||||
|
let filename = log_path.join(format!("{}-{}.log.gz", date_format, id));
|
||||||
|
|
||||||
|
if !filename.exists() {
|
||||||
|
return Ok(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(format!(
|
||||||
|
"Failed to find a unique log filename for date {} after {} attempts.",
|
||||||
|
date_format, MAX_ATTEMPTS
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotate_log(&self) -> Result<(), Box<dyn std::error::Error>> {
|
fn rotate_log(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let now = time::OffsetDateTime::now_utc();
|
let now = time::OffsetDateTime::now_utc();
|
||||||
let mut data = self.data.lock().unwrap();
|
let mut data = self.data.lock().unwrap();
|
||||||
|
|
||||||
let new_filename = Self::new_filename(true);
|
let new_gz_path = Self::new_filename(true)?;
|
||||||
let mut file = File::open(format!("logs/{}", data.latest_filename))?;
|
let latest_path = PathBuf::from(LOG_DIR).join(&data.latest_filename);
|
||||||
|
let mut file = File::open(&latest_path)?;
|
||||||
let mut encoder = GzEncoder::new(
|
let mut encoder = GzEncoder::new(
|
||||||
BufWriter::new(File::create(format!("logs/{new_filename}"))?),
|
BufWriter::new(File::create(&new_gz_path)?),
|
||||||
flate2::Compression::best(),
|
flate2::Compression::best(),
|
||||||
);
|
);
|
||||||
std::io::copy(&mut file, &mut encoder)?;
|
io::copy(&mut file, &mut encoder)?;
|
||||||
encoder.finish()?;
|
encoder.finish()?;
|
||||||
|
|
||||||
data.current_day_of_month = now.day();
|
data.current_day_of_month = now.day();
|
||||||
@ -100,7 +124,7 @@ impl GzipRollingLogger {
|
|||||||
data.latest_logger = *WriteLogger::new(
|
data.latest_logger = *WriteLogger::new(
|
||||||
self.log_level,
|
self.log_level,
|
||||||
self.config.clone(),
|
self.config.clone(),
|
||||||
File::create(format!("logs/{}", data.latest_filename)).unwrap(),
|
File::create(&latest_path)?,
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -108,21 +132,19 @@ impl GzipRollingLogger {
|
|||||||
|
|
||||||
fn remove_ansi_color_code(s: &str) -> String {
|
fn remove_ansi_color_code(s: &str) -> String {
|
||||||
let mut result = String::with_capacity(s.len());
|
let mut result = String::with_capacity(s.len());
|
||||||
let mut in_escape_sequence = false;
|
let mut it = s.chars();
|
||||||
|
|
||||||
for c in s.chars() {
|
while let Some(c) = it.next() {
|
||||||
if in_escape_sequence {
|
if c == '\x1b' {
|
||||||
if c.is_ascii_alphabetic() {
|
for c_seq in it.by_ref() {
|
||||||
// This broadly covers 'm', 'J', 'H', etc.
|
if c_seq.is_ascii_alphabetic() {
|
||||||
in_escape_sequence = false;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if c == '\x1B' {
|
|
||||||
in_escape_sequence = true;
|
|
||||||
} else {
|
} else {
|
||||||
result.push(c);
|
result.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -159,10 +159,7 @@ impl JavaClient {
|
|||||||
///
|
///
|
||||||
/// * `server`: A reference to the `Server` instance.
|
/// * `server`: A reference to the `Server` instance.
|
||||||
pub async fn process_packets(self: &Arc<Self>, server: &Arc<Server>) {
|
pub async fn process_packets(self: &Arc<Self>, server: &Arc<Server>) {
|
||||||
loop {
|
while let Some(packet) = self.get_packet().await {
|
||||||
let packet = self.get_packet().await;
|
|
||||||
let Some(packet) = packet else { break };
|
|
||||||
|
|
||||||
if let Err(error) = self.handle_packet(server, &packet).await {
|
if let Err(error) = self.handle_packet(server, &packet).await {
|
||||||
let text = format!("Error while reading incoming packet {error}");
|
let text = format!("Error while reading incoming packet {error}");
|
||||||
log::error!(
|
log::error!(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user