1use minitel_stum::Minitel;
2
3use std::{collections::VecDeque, io::Error, net::TcpStream};
4
5use minitel_stum::{MinitelRead, MinitelWrite};
6use std::io::{ErrorKind, Result};
7use tungstenite::{Utf8Bytes, WebSocket};
8
9pub type WSMinitel = Minitel<WSPort<TcpStream>>;
11
12pub fn ws_minitel(socket: WebSocket<TcpStream>) -> WSMinitel {
14 WSMinitel::new(WSPort::new(socket))
15}
16
17pub struct WSPort<Stream: std::io::Read + std::io::Write> {
18 ws: WebSocket<Stream>,
19 buffer: VecDeque<u8>,
20}
21
22impl<Stream: std::io::Read + std::io::Write> WSPort<Stream> {
23 pub fn new(ws: WebSocket<Stream>) -> Self {
24 Self {
25 ws,
26 buffer: VecDeque::new(),
27 }
28 }
29}
30
31impl<Stream: std::io::Read + std::io::Write> From<WebSocket<Stream>> for WSPort<Stream> {
32 fn from(ws: WebSocket<Stream>) -> Self {
33 Self::new(ws)
34 }
35}
36
37impl<Stream: std::io::Read + std::io::Write> MinitelRead for WSPort<Stream> {
38 fn read(&mut self, data: &mut [u8]) -> Result<()> {
39 while self.buffer.len() < data.len() {
42 let message = self.ws.read().map_err(map_err)?;
43 if let tungstenite::Message::Text(data) = message {
44 self.buffer.extend(data.as_bytes());
45 }
46 }
47 for byte in data.iter_mut() {
48 *byte = self.buffer.pop_front().unwrap();
49 }
50 Ok(())
51 }
52}
53
54impl<Stream: std::io::Read + std::io::Write> MinitelWrite for WSPort<Stream> {
55 fn send(&mut self, data: &[u8]) -> Result<()> {
56 let text = Utf8Bytes::try_from(data.to_vec())
58 .map_err(|_| std::io::Error::new(ErrorKind::InvalidData, "Invalid UTF-8 data"))?;
59 self.ws
60 .send(tungstenite::Message::text(text))
61 .map_err(map_err)
62 }
63
64 fn flush(&mut self) -> Result<()> {
65 self.ws.flush().map_err(map_err)?;
66 self.buffer.clear();
67 Ok(())
68 }
69}
70
71fn map_err(e: tungstenite::Error) -> std::io::Error {
72 match e {
73 tungstenite::Error::ConnectionClosed => ErrorKind::ConnectionReset.into(),
74 tungstenite::Error::AlreadyClosed => ErrorKind::NotConnected.into(),
75 tungstenite::Error::Io(error) => error,
76 tungstenite::Error::Tls(tls_error) => Error::new(ErrorKind::Other, tls_error),
77 tungstenite::Error::Capacity(capacity_error) => {
78 Error::new(ErrorKind::InvalidData, capacity_error)
79 }
80 tungstenite::Error::Protocol(protocol_error) => {
81 Error::new(ErrorKind::InvalidData, protocol_error)
82 }
83 tungstenite::Error::WriteBufferFull(_) => Error::new(ErrorKind::Other, "Write buffer full"),
84 tungstenite::Error::Utf8 => Error::new(ErrorKind::InvalidData, "Invalid UTF-8 data"),
85 tungstenite::Error::AttackAttempt => Error::new(ErrorKind::Other, "Attack attempt"),
86 tungstenite::Error::Url(url_error) => Error::new(ErrorKind::InvalidData, url_error),
87 tungstenite::Error::Http(_) => Error::new(ErrorKind::InvalidData, "HTTP error"),
88 tungstenite::Error::HttpFormat(error) => Error::new(ErrorKind::InvalidData, error),
89 }
90}