Introduce iced_sentinel and iced_debug crates

This commit is contained in:
Héctor Ramón Jiménez 2024-02-26 07:00:51 +01:00
parent 58a7007ac1
commit dd36893f7a
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
26 changed files with 543 additions and 567 deletions

80
sentinel/src/client.rs Normal file
View file

@ -0,0 +1,80 @@
use crate::{Input, Report, SOCKET_ADDRESS};
use tokio::io::{self, AsyncWriteExt};
use tokio::net;
use tokio::sync::mpsc;
use tokio::time;
#[derive(Debug, Clone)]
pub struct Client {
sender: mpsc::Sender<Input>,
}
impl Client {
pub fn report(&mut self, report: Report) {
let _ = self.sender.try_send(Input::Reported(report));
}
}
#[must_use]
pub fn connect() -> Client {
let (sender, receiver) = mpsc::channel(1_000);
std::thread::spawn(move || run(receiver));
Client { sender }
}
#[tokio::main]
async fn run(mut receiver: mpsc::Receiver<Input>) {
let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))
.expect("Parse package version");
loop {
match _connect().await {
Ok(mut stream) => {
let _ = send(&mut stream, Input::Connected(version)).await;
while let Some(input) = receiver.recv().await {
if send(&mut stream, input).await.is_err() {
break;
}
}
break;
}
Err(_) => {
time::sleep(time::Duration::from_secs(2)).await;
}
}
}
}
async fn _connect() -> Result<io::BufStream<net::TcpStream>, io::Error> {
log::debug!("Attempting to connect sentinel to server...");
let stream = net::TcpStream::connect(SOCKET_ADDRESS).await?;
stream.set_nodelay(true)?;
stream.writable().await?;
Ok(io::BufStream::new(stream))
}
async fn send(
stream: &mut io::BufStream<net::TcpStream>,
input: Input,
) -> Result<(), io::Error> {
stream
.write_all(
format!(
"{}\n",
serde_json::to_string(&input).expect("Serialize input message")
)
.as_bytes(),
)
.await?;
stream.flush().await?;
Ok(())
}

105
sentinel/src/lib.rs Normal file
View file

@ -0,0 +1,105 @@
pub use iced_core as core;
pub mod client;
pub mod timing;
use crate::timing::Timing;
use futures::future;
use futures::stream::{self, Stream, StreamExt};
use semver::Version;
use serde::{Deserialize, Serialize};
use tokio::io::{self, AsyncBufReadExt, BufStream};
use tokio::net;
pub const SOCKET_ADDRESS: &str = "127.0.0.1:9167";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Input {
Connected(Version),
Reported(Report),
}
#[derive(Debug, Clone)]
pub enum Event {
Connected(Version),
Disconnected,
Reported(Report),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Report {
Timing(Timing),
}
pub fn run() -> impl Stream<Item = Event> {
enum State {
Disconnected,
Connected(BufStream<net::TcpStream>),
}
stream::unfold(State::Disconnected, |state| async {
match state {
State::Disconnected => match connect().await {
Ok(stream) => {
let stream = BufStream::new(stream);
Some((None, State::Connected(stream)))
}
Err(_error) => Some((None, State::Disconnected)),
},
State::Connected(stream) => match receive(stream).await {
Ok((_, Event::Disconnected)) | Err(_) => {
Some((Some(Event::Disconnected), State::Disconnected))
}
Ok((stream, message)) => {
Some((Some(message), State::Connected(stream)))
}
},
}
})
.filter_map(future::ready)
}
async fn connect() -> Result<net::TcpStream, io::Error> {
let listener = net::TcpListener::bind(SOCKET_ADDRESS).await?;
let (stream, _) = listener.accept().await?;
stream.set_nodelay(true)?;
stream.readable().await?;
Ok(stream)
}
async fn receive(
mut stream: BufStream<net::TcpStream>,
) -> Result<(BufStream<net::TcpStream>, Event), io::Error> {
let mut input = String::new();
loop {
match stream.read_line(&mut input).await? {
0 => return Ok((stream, Event::Disconnected)),
n => {
match serde_json::from_str(&input[..n]) {
Ok(input) => {
return Ok((
stream,
match dbg!(input) {
Input::Connected(version) => {
Event::Connected(version)
}
Input::Reported(report) => {
Event::Reported(report)
}
},
))
}
Err(_) => {
// TODO: Log decoding error
}
}
}
}
}
}

25
sentinel/src/timing.rs Normal file
View file

@ -0,0 +1,25 @@
use crate::core::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct Timing {
pub stage: Stage,
pub duration: Duration,
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub enum Stage {
Boot,
Update,
View,
Layout,
Interact,
Draw,
Render,
Custom(String),
}