use orcs_app::{PrintResult, SharedPrinterSlot};
use parking_lot::Mutex;
use std::io::{self, Write};
use std::sync::Arc;
#[derive(Clone)]
pub struct TracingMakeWriter {
slot: SharedPrinterSlot,
log_file: Option<Arc<Mutex<std::fs::File>>>,
}
impl TracingMakeWriter {
pub fn new(slot: &SharedPrinterSlot, log_file: Option<Arc<Mutex<std::fs::File>>>) -> Self {
Self {
slot: slot.clone(),
log_file,
}
}
}
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for TracingMakeWriter {
type Writer = TracingWriter;
fn make_writer(&'a self) -> Self::Writer {
TracingWriter {
slot: self.slot.clone(),
log_file: self.log_file.as_ref().map(Arc::clone),
buf: Vec::with_capacity(256),
}
}
}
pub struct TracingWriter {
slot: SharedPrinterSlot,
log_file: Option<Arc<Mutex<std::fs::File>>>,
buf: Vec<u8>,
}
impl Write for TracingWriter {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
self.buf.extend_from_slice(data);
Ok(data.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Drop for TracingWriter {
fn drop(&mut self) {
if self.buf.is_empty() {
return;
}
{
let msg = String::from_utf8_lossy(&self.buf).into_owned();
match self.slot.try_print(msg) {
PrintResult::Sent => {}
PrintResult::NoPrinter => {
let _ = io::stdout().write_all(&self.buf);
let _ = io::stdout().flush();
}
PrintResult::Dropped => {
}
}
}
if let Some(ref file_mutex) = self.log_file {
let clean = strip_ansi(&self.buf);
let mut file = file_mutex.lock();
let _ = file.write_all(&clean);
let _ = file.flush();
}
}
}
fn strip_ansi(input: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(input.len());
let mut i = 0;
while i < input.len() {
if input[i] == 0x1b && i + 1 < input.len() && input[i + 1] == b'[' {
i += 2;
while i < input.len() && !(0x40..=0x7E).contains(&input[i]) {
i += 1;
}
if i < input.len() {
i += 1; }
} else {
out.push(input[i]);
i += 1;
}
}
out
}