use crate::{
errors::CatBridgeError,
fsemul::sdio::{
errors::SdioNetworkError,
proto::message::{
SdioControlMessageRequest, SdioControlTelnetChannel, SdioControlTelnetData,
SdioControlTelnetMessage,
},
server::{SDIO_PRINTF_BUFFS, SdioStreamState},
},
mion::proto::control::MionBootType,
net::{
additions::StreamID,
server::requestable::{Body, State},
},
};
use bytes::Bytes;
use std::sync::Arc;
use tokio::sync::{Mutex, oneshot::Sender as OneshotSender};
use tracing::{debug, info};
#[allow(
// TODO(mythra): file issue with clippy, suggestion doesn't work.
clippy::assigning_clones,
)]
pub(super) async fn handle_telnet_message(
State(state): State<SdioStreamState>,
stream_id: StreamID,
Body(request): Body<SdioControlMessageRequest>,
) -> Result<Option<Bytes>, CatBridgeError> {
for message in request.messages_owned() {
match message.channel() {
SdioControlTelnetChannel::CafeOS => {
debug!(
lisa.subsystem = "cos",
"{}",
message.buffer_as_complete_string()
);
}
SdioControlTelnetChannel::DevkitMsg => {
return handle_devkit_msg(
state.active_hook.clone(),
state.boot_type,
&message.buffer_as_complete_string(),
)
.await;
}
SdioControlTelnetChannel::SysConfigTool => {
let Some(mut buff) = SDIO_PRINTF_BUFFS
.get_async(&(stream_id.to_raw(), message.channel()))
.await
else {
return Err(SdioNetworkError::PrintfMissingBuffer(stream_id.to_raw()).into());
};
for item in message.buffer() {
match item {
SdioControlTelnetData::Backspace => {
_ = buff.pop();
}
SdioControlTelnetData::ClearLine => {
*buff = String::new();
}
SdioControlTelnetData::StringData(bytes) => {
buff.push_str(&String::from_utf8_lossy(bytes));
}
}
}
while let Some(idx) = buff.find('\r') {
let (my_line, new_buff) = buff.split_at(idx);
let trimmed_line = my_line.trim();
if !trimmed_line.is_empty()
&& !trimmed_line.starts_with('#')
&& !trimmed_line.starts_with("Note")
&& !trimmed_line
.contains("Please press F12 or the Backtick key to enter command.")
{
info!(lisa.subsystem = "sct", "{}", trimmed_line);
}
*buff = new_buff[1..].to_owned();
}
}
}
}
Ok(None)
}
async fn handle_devkit_msg(
active_marker: Option<Arc<Mutex<Option<OneshotSender<()>>>>>,
boot_type: MionBootType,
msg: &str,
) -> Result<Option<Bytes>, CatBridgeError> {
if msg == "CAFE_BOOT_MODE" {
if let Some(marker_ref) = active_marker {
let mut lock = marker_ref.lock().await;
if let Some(channel) = lock.take() {
channel
.send(())
.map_err(|()| CatBridgeError::ClosedChannel)?;
}
}
return Ok(Some(Bytes::try_from(SdioControlMessageRequest::new(
vec![SdioControlTelnetMessage::new(
match boot_type {
MionBootType::DUAL | MionBootType::PCFS | MionBootType::NAND => {
format!("{boot_type}")
}
MionBootType::Unk(_) => format!("{}", MionBootType::PCFS),
},
SdioControlTelnetChannel::DevkitMsg,
)?],
))?));
}
info!(lisa.subsystem = "dkm", "{}", msg.trim_end());
Ok(None)
}