use std::io::{stdout, Write};
use std::sync::mpsc::{Receiver, Sender};
use log::Level;
pub struct Console {
messages: Receiver<ConsoleMessage>,
sender: Sender<ConsoleMessage>,
}
pub struct ConsoleLogger(Sender<ConsoleMessage>);
pub enum ConsoleMessage {
RuntimeLog {
message: String,
level: Level,
file: String,
line: u32,
},
ScriptLog {
message: String,
level: Level,
file: String,
line: u32,
},
FrameTime {
timestamp: i64,
},
ScopeStart {
scope_name: String,
timestamp: i64,
},
ScopeEnd {
timestamp: i64,
},
}
impl Console {
pub async fn new(port: u16) -> Result<Self, std::io::Error> {
let (sender, reciever) = std::sync::mpsc::channel();
Ok(Self {
messages: reciever,
sender,
})
}
fn sender(&self) -> Sender<ConsoleMessage> {
self.sender.clone()
}
pub fn logger(&self) -> ConsoleLogger {
ConsoleLogger(self.sender())
}
pub fn flush(&self) -> std::io::Result<()> {
let mut stdout = stdout().lock();
while let Ok(message) = self.messages.try_recv() {
let message = match message {
ConsoleMessage::RuntimeLog {
message,
level,
file,
line,
} => {
let message = message.replace('\n', "\\n");
format!("runtimelog {level} {file}:{line} {message}\n")
}
ConsoleMessage::ScriptLog {
message,
level,
file,
line,
} => {
let message = message.replace('\n', "\\n");
format!("scriptlog {level} {file}:{line} {message}\n")
}
ConsoleMessage::FrameTime {
timestamp: unix_timestamp,
} => {
format!("frametime {unix_timestamp}")
}
ConsoleMessage::ScopeStart {
scope_name,
timestamp: unix_timestamp,
} => {
format!("scopestart {scope_name} {unix_timestamp}")
}
ConsoleMessage::ScopeEnd {
timestamp: unix_timestamp,
} => {
format!("scopeend {unix_timestamp}")
}
};
stdout.write_all(message.as_bytes())?;
stdout.write_all(b"\n")?;
}
stdout.flush()?;
Ok(())
}
}
impl ConsoleLogger {
pub fn send(&self, message: ConsoleMessage) {
_ = self.0.send(message);
}
}
impl log::Log for ConsoleLogger {
fn enabled(&self, _: &log::Metadata) -> bool {
true
}
fn log(&self, record: &log::Record) {
let _ = self.0.send(ConsoleMessage::RuntimeLog {
message: record.args().to_string(),
level: record.level(),
file: record.file().map(str::to_string).unwrap_or_default(),
line: record.line().unwrap_or_default(),
});
}
fn flush(&self) {}
}
|