use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; use tokio::runtime::Handle; use crate::get_talos_path; fn deserialize_schematic<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let name: String = Deserialize::deserialize(deserializer)?; let path = get_talos_path().join("schematics").join(name); let content = std::fs::read_to_string(path).unwrap().trim().to_owned(); let client = reqwest::ClientBuilder::new() .user_agent(format!( "{}/{}", std::env!("CARGO_PKG_NAME"), std::env!("CARGO_PKG_VERSION") )) .build() .unwrap(); #[derive(Debug, Deserialize)] struct Response { id: String, } // We can't use async directly inside a custom deserializer, and using the blocking client also // does not work as it will try to start tokio inside of tokio. // So we have do this to work around it. let response = tokio::task::block_in_place(|| { Handle::current().block_on(async { let res = client .post("https://factory.talos.dev/schematics") .body(content) .send() .await .map_err(serde::de::Error::custom)?; let response: Response = serde_json::from_str(&res.text().await.map_err(serde::de::Error::custom)?) .map_err(serde::de::Error::custom)?; Ok(response) }) })?; Ok(response.id) } #[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)] pub(crate) struct Schematic(#[serde(deserialize_with = "deserialize_schematic")] String); impl std::fmt::Display for Schematic { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0) } }