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
92#[derive(Debug, Clone)]
97pub struct BuilderSdk {
98 board_name: String,
100 board_config_name: String,
102 config_path: String,
104 action: Action,
106}
107
108impl BuilderSdk {
109 pub async fn init<F>(event_callback: F) -> Result<Self>
131 where
132 F: Fn(&Self, BuilderEvent) + Send + Sync + 'static,
133 {
134 let args: Vec<String> = std::env::args().into_iter().collect();
135 if args.len() < 6 {
136 return Err(Error::MissingArgs(6, args.len()));
137 }
138
139 let action: Action = TryFrom::<&str>::try_from(&args[1])?;
140
141 let stream = UnixStream::connect(&args[5]).await?;
142 let sdk = Self {
143 config_path: args[2].clone(),
144 board_name: args[3].clone(),
145 board_config_name: args[4].clone(),
146 action,
147 };
148 let sdk_loop = sdk.clone();
149
150 tokio::spawn(async move { sdk_loop.start_event_loop(stream, event_callback) });
151 Ok(sdk)
152 }
153 pub fn action(&self) -> Action {
155 self.action
156 }
157 pub fn config_path(&self) -> PathBuf {
159 PathBuf::from(&self.config_path)
160 }
161 pub fn board_name(&self) -> &str {
163 &self.board_name
164 }
165 pub fn board_config_name(&self) -> &str {
167 &self.board_config_name
168 }
169 fn parse_event(payload: &str) -> Result<BuilderEvent> {
171 Ok(serde_json::from_str(payload)?)
172 }
173 async fn start_event_loop<F>(self, stream: UnixStream, cb: F) -> Result<()>
175 where
176 F: Fn(&BuilderSdk, BuilderEvent) + Send + Sync + 'static,
177 {
178 let mut payload = String::new();
179 let (mut rx, mut tx) = stream.into_split();
180
181 loop {
182 match rx.read_to_string(&mut payload).await {
183 Ok(0) => break,
184 Ok(n) => {
185 let event = BuilderSdk::parse_event(&payload)?;
186 info!("Received event from builder {:?}", event);
187 cb(&self, event);
188 info!("Acking event to builder");
189 let response = serde_json::to_string(&BuilderResponse::Ack)?;
190 tx.write_all(response.as_bytes()).await;
191 tx.write_all(b"\n").await;
192 tx.flush().await;
193 }
194 Err(e) => return Err(Error::from(e)),
195 }
196 }
197 Ok(())
198 }
199}