cdk_builder/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3use serde_json::Value;
4use std::borrow::Cow;
5use std::cell::RefCell;
6use std::ops::Deref;
7use std::ops::DerefMut;
8use std::process::Stdio;
9use std::rc::Rc;
10use std::sync::atomic::AtomicU64;
11use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
12use tokio::process::{ChildStdin, ChildStdout, Command};
13use tokio::task::JoinHandle;
14
15pub mod ec2;
16
17pub mod s3;
18
19#[derive(Serialize)]
20struct Request<'a> {
21    js: &'a str,
22}
23
24#[derive(Deserialize)]
25struct Response {
26    json: Value,
27}
28
29struct AppInner {
30    stdin: ChildStdin,
31    stdout: ChildStdout,
32    handle: JoinHandle<()>,
33}
34
35#[derive(Clone)]
36pub struct App {
37    inner: Rc<RefCell<AppInner>>,
38    exprs: Rc<RefCell<Vec<String>>>,
39}
40
41impl App {
42    pub async fn new() -> Self {
43        let mut child = Command::new("node")
44            .arg("worker.js")
45            .stdin(Stdio::piped())
46            .stdout(Stdio::piped())
47            .spawn()
48            .expect("Failed to start child process");
49
50        let stdin = child.stdin.take().unwrap();
51        let stdout = child.stdout.take().unwrap();
52
53        let handle = tokio::task::spawn(async move {
54            child.wait().await.unwrap();
55        });
56
57        let me = App {
58            inner: Rc::new(RefCell::new(AppInner {
59                stdin,
60                stdout,
61                handle,
62            })),
63            exprs: Rc::default(),
64        };
65
66        me.request::<i32>(
67            r#"
68                app = new cdk.App();
69                0
70            "#,
71        )
72        .await;
73
74        me
75    }
76
77    pub async fn stack<S: Stack>(&mut self, stack: S) {
78        let mut layer = Layer {
79            app: self.clone(),
80            stack,
81            exprs: Rc::default(),
82            parent_exprs: self.exprs.clone(),
83            expr: None,
84        };
85        S::run(&mut layer);
86    }
87
88    async fn request<T>(&self, js: &str) -> T
89    where
90        T: for<'de> Deserialize<'de>,
91    {
92        let mut me = self.inner.borrow_mut();
93
94        let message = Request { js };
95        let mut bytes = serde_json::to_vec(&message).unwrap();
96        bytes.push(b'\n');
97        me.stdin.write_all(&bytes).await.unwrap();
98
99        let reader = BufReader::new(&mut me.stdout);
100        let mut lines = reader.lines();
101
102        let Ok(Some(line)) = lines.next_line().await else {
103            todo!()
104        };
105
106        let res: Response = serde_json::from_str(&line).unwrap();
107        serde_json::from_value(res.json).unwrap()
108    }
109
110    pub async fn run(&mut self) {
111        let exprs = self.exprs.borrow();
112
113        for expr in &*exprs {
114            self.request::<Value>(expr).await;
115        }
116    }
117}
118
119impl Drop for App {
120    fn drop(&mut self) {
121        self.inner.borrow_mut().handle.abort();
122    }
123}
124
125pub trait Stack: Sized {
126    fn run(me: &mut Layer<Self>);
127
128    fn name(&self) -> Cow<'static, str> {
129        let type_name = std::any::type_name::<Self>();
130        Cow::Borrowed(
131            type_name
132                .split('<')
133                .next()
134                .unwrap_or(type_name)
135                .split("::")
136                .last()
137                .unwrap_or(type_name),
138        )
139    }
140
141    fn setup(me: &mut Layer<Self>) {
142        let _ = me;
143    }
144
145    fn initialize(me: &mut Layer<Self>) {
146        let exprs = me.exprs.borrow().concat();
147        let js = format!(
148            r#"
149                class RustStack extends cdk.Stack {{
150                    constructor(scope, id, props) {{
151                        super(scope, id, props);
152                        {}
153                    }}
154                }}
155
156                new RustStack(app, '{}', {{}});
157
158                0
159            "#,
160            exprs,
161            me.stack.name()
162        );
163        me.parent_exprs.borrow_mut().push(js)
164    }
165
166    fn stack<T: Stack>(self, layer: &Layer<T>) -> Layer<Self> {
167        let mut layer = Layer {
168            app: layer.app.clone(),
169            stack: self,
170            exprs: Rc::default(),
171            parent_exprs: layer.exprs.clone(),
172            expr: None,
173        };
174        Self::setup(&mut layer);
175        layer
176    }
177}
178
179pub struct Layer<T: Stack> {
180    app: App,
181    stack: T,
182    exprs: Rc<RefCell<Vec<String>>>,
183    expr: Option<String>,
184    parent_exprs: Rc<RefCell<Vec<String>>>,
185}
186
187impl<T: Stack> Deref for Layer<T> {
188    type Target = T;
189
190    fn deref(&self) -> &Self::Target {
191        &self.stack
192    }
193}
194
195impl<T: Stack> DerefMut for Layer<T> {
196    fn deref_mut(&mut self) -> &mut Self::Target {
197        &mut self.stack
198    }
199}
200
201impl<T: Stack> Drop for Layer<T> {
202    fn drop(&mut self) {
203        T::initialize(self)
204    }
205}
206
207static COUNT: AtomicU64 = AtomicU64::new(0);