2020-07-13 15:00:53 +08:00
|
|
|
use futures::{future::poll_fn, task::Poll};
|
|
|
|
use libasync::{smoltcp::TcpStream, task};
|
|
|
|
use libboard_zynq::smoltcp;
|
2020-07-15 16:05:00 +08:00
|
|
|
use core::cell::RefCell;
|
|
|
|
use alloc::rc::Rc;
|
|
|
|
use log::{self, info, warn, LevelFilter};
|
2020-07-13 15:00:53 +08:00
|
|
|
|
|
|
|
use crate::logger::{BufferLogger, LogBufferRef};
|
|
|
|
use crate::proto_async;
|
|
|
|
use crate::proto_mgmt::*;
|
|
|
|
|
2020-07-15 16:05:00 +08:00
|
|
|
|
|
|
|
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
|
|
|
where
|
|
|
|
F: Fn(&LogBufferRef) -> bool,
|
|
|
|
{
|
2020-07-13 15:00:53 +08:00
|
|
|
poll_fn(|ctx| {
|
|
|
|
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
|
|
|
match logger.buffer() {
|
2020-07-15 17:04:16 +08:00
|
|
|
Some(buffer) if f(&buffer) => Poll::Ready(buffer),
|
2020-07-13 15:00:53 +08:00
|
|
|
_ => {
|
|
|
|
ctx.waker().wake_by_ref();
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2020-07-15 16:05:00 +08:00
|
|
|
async fn get_logger_buffer() -> LogBufferRef<'static> {
|
|
|
|
get_logger_buffer_pred(|_| true).await
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) -> Result<(), Error> {
|
2020-07-13 15:00:53 +08:00
|
|
|
Request::read_magic(stream).await?;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let req = Request::read_from(stream).await;
|
|
|
|
if let Err(Error::Io(smoltcp::Error::Illegal)) = req {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
match req? {
|
|
|
|
Request::GetLog => {
|
|
|
|
let mut buffer = get_logger_buffer().await;
|
|
|
|
Reply::LogContent(buffer.extract()).write_to(stream).await?;
|
|
|
|
}
|
|
|
|
Request::ClearLog => {
|
|
|
|
let mut buffer = get_logger_buffer().await;
|
|
|
|
buffer.clear();
|
|
|
|
Reply::Success.write_to(stream).await?;
|
|
|
|
}
|
2020-07-15 16:05:00 +08:00
|
|
|
Request::PullLog => {
|
|
|
|
let id = {
|
|
|
|
let mut guard = pull_id.borrow_mut();
|
|
|
|
*guard += 1;
|
|
|
|
*guard
|
|
|
|
};
|
|
|
|
loop {
|
|
|
|
let mut buffer = get_logger_buffer_pred(|b| !b.is_empty()).await;
|
|
|
|
let bytes = buffer.extract().as_bytes();
|
|
|
|
if id != *pull_id.borrow() {
|
|
|
|
// another connection attempts to pull the log...
|
|
|
|
// abort this connection...
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
proto_async::write_chunk(stream, bytes).await?;
|
|
|
|
if log::max_level() == LevelFilter::Trace {
|
|
|
|
// Hold exclusive access over the logger until we get positive
|
|
|
|
// acknowledgement; otherwise we get an infinite loop of network
|
|
|
|
// trace messages being transmitted and causing more network
|
|
|
|
// trace messages to be emitted.
|
|
|
|
//
|
|
|
|
// Any messages unrelated to this management socket that arrive
|
|
|
|
// while it is flushed are lost, but such is life.
|
|
|
|
stream.flush().await?;
|
|
|
|
}
|
|
|
|
buffer.clear();
|
2020-07-13 15:00:53 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
Request::SetLogFilter(lvl) => {
|
|
|
|
info!("Changing log level to {}", lvl);
|
|
|
|
log::set_max_level(lvl);
|
|
|
|
Reply::Success.write_to(stream).await?;
|
|
|
|
}
|
|
|
|
Request::SetUartLogFilter(lvl) => {
|
|
|
|
info!("Changing UART log level to {}", lvl);
|
|
|
|
unsafe {
|
|
|
|
BufferLogger::get_logger()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.set_uart_log_level(lvl);
|
|
|
|
}
|
|
|
|
Reply::Success.write_to(stream).await?;
|
2020-07-15 16:05:00 +08:00
|
|
|
}
|
2020-07-13 15:00:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn start() {
|
|
|
|
task::spawn(async move {
|
2020-07-15 16:05:00 +08:00
|
|
|
let pull_id = Rc::new(RefCell::new(0u32));
|
2020-07-13 15:00:53 +08:00
|
|
|
loop {
|
|
|
|
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
2020-07-15 16:05:00 +08:00
|
|
|
let pull_id = pull_id.clone();
|
2020-07-13 15:00:53 +08:00
|
|
|
task::spawn(async move {
|
2020-07-20 19:09:56 +08:00
|
|
|
info!("received connection");
|
2020-07-15 16:05:00 +08:00
|
|
|
let _ = handle_connection(&mut stream, pull_id)
|
2020-07-13 15:00:53 +08:00
|
|
|
.await
|
|
|
|
.map_err(|e| warn!("connection terminated: {:?}", e));
|
|
|
|
let _ = stream.flush().await;
|
|
|
|
let _ = stream.abort().await;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|