1use std::{env::args, path::PathBuf};
28
29use serde::{Deserialize, Serialize};
30use tokio::{
31 io::{AsyncReadExt, AsyncWriteExt},
32 net::{
33 UnixStream,
34 unix::{OwnedReadHalf, OwnedWriteHalf},
35 },
36};
37use tracing::info;
38
39use crate::prelude::*;
40pub mod error;
41pub mod prelude;
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub enum BuilderEvent {
46 Exit,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub enum BuilderResponse {
53 Ack,
55}
56#[derive(Debug, Clone, Copy)]
57pub enum Action {
58 Build,
59 Run,
60}
61
62impl TryFrom<&str> for Action {
63 type Error = Error;
64
65 fn try_from(value: &str) -> Result<Self> {
66 if value == "build" {
67 return Ok(Action::Build);
68 }
69 if value == "run" {
70 return Ok(Action::Run);
71 }
72 Err(Error::InvalidAction(String::from(value)))
73 }
74}
75
76impl From<Action> for &'static str {
77 fn from(value: Action) -> Self {
78 match value {
79 Action::Build => "build",
80 Action::Run => "run",
81 }
82 }
83}
84
85impl From<Action> for String {
86 fn from(value: Action) -> Self {
87 let value: &str = value.into();
88 Self::from(value)
89 }
90}
91
92pub struct BuilderSdk {
97 board_config_name: String,
99 config_path: String,
101 action: Action,
103}
104
105impl BuilderSdk {
106 pub async fn init<F>(event_callback: F) -> Result<Self>
128 where
129 F: Fn(BuilderEvent) + Send + Sync + 'static,
130 {
131 let args: Vec<String> = std::env::args().into_iter().collect();
132 if args.len() < 5 {
133 return Err(Error::MissingArgs(5, args.len()));
134 }
135
136 let stream = UnixStream::connect(&args[4]).await?;
137 tokio::spawn(async move { BuilderSdk::start_event_loop(stream, event_callback) });
138 let action: Action = TryFrom::<&str>::try_from(&args[1])?;
139
140 Ok(Self {
141 config_path: args[2].clone(),
142 board_config_name: args[3].clone(),
143 action,
144 })
145 }
146 pub fn board_config_name(&self) -> &str {
148 &self.board_config_name
149 }
150 pub fn config_path(&self) -> PathBuf {
152 PathBuf::from(&self.config_path)
153 }
154 pub fn action(&self) -> Action {
156 self.action
157 }
158 fn parse_event(payload: &str) -> Result<BuilderEvent> {
160 Ok(serde_json::from_str(payload)?)
161 }
162 async fn start_event_loop<F>(stream: UnixStream, cb: F) -> Result<()>
164 where
165 F: Fn(BuilderEvent) + Send + Sync + 'static,
166 {
167 let mut payload = String::new();
168 let (mut rx, mut tx) = stream.into_split();
169
170 loop {
171 match rx.read_to_string(&mut payload).await {
172 Ok(0) => break,
173 Ok(n) => {
174 let event = BuilderSdk::parse_event(&payload)?;
175 info!("Received event from builder {:?}", event);
176 cb(event);
177 info!("Acking event to builder");
178 let response = serde_json::to_string(&BuilderResponse::Ack)?;
179 tx.write_all(response.as_bytes()).await;
180 tx.write_all(b"\n").await;
181 tx.flush().await;
182 }
183 Err(e) => return Err(Error::from(e)),
184 }
185 }
186 Ok(())
187 }
188}