Introduce iced_sentinel and iced_debug crates
This commit is contained in:
parent
58a7007ac1
commit
dd36893f7a
26 changed files with 543 additions and 567 deletions
80
sentinel/src/client.rs
Normal file
80
sentinel/src/client.rs
Normal 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
105
sentinel/src/lib.rs
Normal 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
25
sentinel/src/timing.rs
Normal 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),
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue