1use crate::{
9 errors::{CatBridgeError, NetworkError},
10 fsemul::sdio::{
11 SDIO_DATA_STREAMS,
12 data_stream::DataStream,
13 errors::SdioNetworkError,
14 proto::{
15 SDIO_BLOCK_SIZE,
16 message::{
17 SdioControlMessageRequest, SdioControlTelnetChannel, SdioControlTelnetMessage,
18 },
19 read::SdioControlReadRequest,
20 },
21 },
22 net::client::{TCPClient, models::RequestStreamEvent},
23};
24use bytes::Bytes;
25use std::{net::SocketAddr, sync::Arc, time::Duration};
26use tokio::{net::TcpListener, sync::RwLock};
27use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
28
29const DEFAULT_SEND_TIMEOUT: Duration = Duration::from_secs(5 * 60);
31
32#[derive(Debug)]
34pub struct SdioClient {
35 data_listener: Arc<RwLock<TcpListener>>,
37 response_timeout: Duration,
39 underlying_client: TCPClient,
41}
42
43impl SdioClient {
44 pub async fn new(
54 bind_address_control: SocketAddr,
55 bind_address_data: SocketAddr,
56 trace_during_debug: bool,
57 ) -> Result<Self, CatBridgeError> {
58 let mut client = TCPClient::new("sdio", 512_usize, (None, None), trace_during_debug);
59 let data = Arc::new(RwLock::new(
60 TcpListener::bind(bind_address_data)
61 .await
62 .map_err(NetworkError::IO)?,
63 ));
64 client.bind(bind_address_control).await?;
65
66 let cloned_data_start = data.clone();
67 #[cfg(debug_assertions)]
68 let copied_trace: bool = trace_during_debug;
69 client.set_on_stream_begin(move |event: RequestStreamEvent<()>| async move {
70 let sid = event.stream_id();
71 let (connection, server_location) = {
72 let guard = cloned_data_start.write().await;
73 guard.accept().await
74 }
75 .map_err(NetworkError::IO)?;
76 connection.set_nodelay(true).map_err(NetworkError::IO)?;
77 let client_location = connection.local_addr().map_err(NetworkError::IO)?;
78
79 _ = SDIO_DATA_STREAMS
80 .insert_async(
81 sid,
82 DataStream::from_stream(
83 client_location,
84 server_location,
85 connection,
86 #[cfg(debug_assertions)]
87 copied_trace,
88 )?,
89 )
90 .await;
91
92 Ok::<bool, CatBridgeError>(true)
93 })?;
94
95 client.set_on_stream_end(|event: RequestStreamEvent<()>| async move {
96 SDIO_DATA_STREAMS.remove_async(&event.stream_id()).await;
97 Ok(())
98 })?;
99
100 Ok(Self {
101 data_listener: data,
102 response_timeout: DEFAULT_SEND_TIMEOUT,
103 underlying_client: client,
104 })
105 }
106
107 #[must_use]
108 pub const fn get_response_timeout(&self) -> Duration {
109 self.response_timeout
110 }
111
112 pub async fn send_telnet_cafe_os(&self, message: String) -> Result<(), CatBridgeError> {
126 for char_chunk in message.bytes().collect::<Vec<u8>>().chunks(499) {
127 let msg_chunk = unsafe { String::from_utf8_unchecked(char_chunk.to_vec()) };
128 self.underlying_client
129 .send(
130 SdioControlMessageRequest::new(vec![SdioControlTelnetMessage::new(
131 msg_chunk,
132 SdioControlTelnetChannel::CafeOS,
133 )?]),
134 None,
135 )
136 .await?;
137 }
138
139 Ok(())
140 }
141
142 pub async fn send_telnet_dkm(&self, message: String) -> Result<(), CatBridgeError> {
156 for char_chunk in message.bytes().collect::<Vec<u8>>().chunks(499) {
157 let msg_chunk = unsafe { String::from_utf8_unchecked(char_chunk.to_vec()) };
158 self.underlying_client
159 .send(
160 SdioControlMessageRequest::new(vec![SdioControlTelnetMessage::new(
161 msg_chunk,
162 SdioControlTelnetChannel::DevkitMsg,
163 )?]),
164 None,
165 )
166 .await?;
167 }
168
169 Ok(())
170 }
171
172 pub async fn send_telnet_sysconfigtool(&self, message: String) -> Result<(), CatBridgeError> {
186 for char_chunk in message.bytes().collect::<Vec<u8>>().chunks(499) {
187 let msg_chunk = unsafe { String::from_utf8_unchecked(char_chunk.to_vec()) };
188 self.underlying_client
189 .send(
190 SdioControlMessageRequest::new(vec![SdioControlTelnetMessage::new(
191 msg_chunk,
192 SdioControlTelnetChannel::SysConfigTool,
193 )?]),
194 None,
195 )
196 .await?;
197 }
198
199 Ok(())
200 }
201
202 pub async fn send_raw_telnet_message(
217 &self,
218 messages: Vec<SdioControlTelnetMessage>,
219 ) -> Result<(), CatBridgeError> {
220 for message in messages {
221 self.underlying_client
222 .send(SdioControlMessageRequest::new(vec![message]), None)
223 .await?;
224 }
225
226 Ok(())
227 }
228
229 pub async fn read(&self, lba: u32, blocks: u32, channel: u32) -> Result<Bytes, CatBridgeError> {
240 let (primary_stream_id, _req_id, _) = self
242 .underlying_client
243 .send(SdioControlReadRequest::new(lba, blocks, channel)?, None)
244 .await?;
245 let Some(data_stream) = SDIO_DATA_STREAMS.get_async(&primary_stream_id).await else {
246 return Err(SdioNetworkError::DataStreamMissing(primary_stream_id).into());
247 };
248
249 Ok(data_stream
250 .recv(usize::try_from(blocks).unwrap_or(usize::MAX) * SDIO_BLOCK_SIZE)
251 .await?)
252 }
253}
254
255const SDIO_CLIENT_FIELDS: &[NamedField<'static>] = &[
256 NamedField::new("data_listener"),
257 NamedField::new("underlying_client"),
258];
259
260impl Structable for SdioClient {
261 fn definition(&self) -> StructDef<'_> {
262 StructDef::new_static("SdioClient", Fields::Named(SDIO_CLIENT_FIELDS))
263 }
264}
265
266impl Valuable for SdioClient {
267 fn as_value(&self) -> Value<'_> {
268 Value::Structable(self)
269 }
270
271 fn visit(&self, visitor: &mut dyn Visit) {
272 visitor.visit_named_fields(&NamedValues::new(
273 SDIO_CLIENT_FIELDS,
274 &[
275 Valuable::as_value(&format!("{:?}", self.data_listener)),
276 Valuable::as_value(&self.underlying_client),
277 ],
278 ));
279 }
280}