-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
461 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use async_dropper_simple::{AsyncDrop, AsyncDropper}; | ||
use async_trait::async_trait; | ||
use std::sync::Arc; | ||
use tokio::process::Child; | ||
use tokio::sync::RwLock; | ||
|
||
pub type SharedChildWrapper = Arc<RwLock<AsyncDropper<ChildWrapper>>>; | ||
|
||
#[derive(Default)] | ||
pub struct ChildWrapper { | ||
inner: Option<Child>, | ||
} | ||
|
||
impl ChildWrapper { | ||
fn new(child: Child) -> Self { | ||
Self { inner: Some(child) } | ||
} | ||
|
||
pub fn new_shared(child: Child) -> SharedChildWrapper { | ||
Arc::new(RwLock::new(AsyncDropper::new(Self::new(child)))) | ||
} | ||
|
||
pub async fn kill(&mut self) -> anyhow::Result<()> { | ||
if let Some(mut v) = self.inner.take() { | ||
v.kill().await?; | ||
} | ||
Ok(()) | ||
} | ||
/// Check if the child process is running | ||
/// mutable borrow because the process id could be reaped if it exited | ||
pub async fn is_running(&mut self) -> bool { | ||
self.inner | ||
.as_mut() | ||
.map_or(false, |child| matches!(child.try_wait(), Ok(None))) | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl AsyncDrop for ChildWrapper { | ||
async fn async_drop(&mut self) { | ||
let _ = self.kill().await; | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[tokio::test(flavor = "multi_thread")] | ||
async fn test_child() { | ||
let child = tokio::process::Command::new("sleep") | ||
.arg("1") | ||
.spawn() | ||
.unwrap(); | ||
let wrapper = ChildWrapper::new_shared(child); | ||
assert!(wrapper.write().await.is_running().await); | ||
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; | ||
assert!(!wrapper.write().await.is_running().await); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
mod child_wrapper; | ||
pub mod directory; | ||
pub mod octez_baker; | ||
pub mod octez_client; | ||
pub mod octez_node; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
use crate::protocol::Protocol; | ||
|
||
use super::{ | ||
child_wrapper::{ChildWrapper, SharedChildWrapper}, | ||
octez_client::OctezClient, | ||
Task, | ||
}; | ||
use anyhow::{anyhow, Result}; | ||
use async_trait::async_trait; | ||
use octez::{Endpoint, OctezNodeConfig}; | ||
|
||
use std::{fmt::Display, path::PathBuf}; | ||
use tokio::process::Command; | ||
|
||
#[derive(PartialEq, Debug, Clone)] | ||
pub enum BakerBinaryPath { | ||
BuiltIn(Protocol), // The binary exists in $PATH | ||
Custom(PathBuf), // The binary is at the given path | ||
} | ||
|
||
impl Display for BakerBinaryPath { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
BakerBinaryPath::BuiltIn(Protocol::Alpha) => write!(f, "octez-baker-alpha"), | ||
BakerBinaryPath::BuiltIn(Protocol::ParisC) => { | ||
write!(f, "octez-baker-PsParisC") | ||
} | ||
BakerBinaryPath::BuiltIn(Protocol::Quebec) => { | ||
write!(f, "octez-baker-PsQuebec") | ||
} | ||
BakerBinaryPath::Custom(path) => write!(f, "{}", path.to_string_lossy()), | ||
} | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub struct OctezBakerConfig { | ||
binary_path: BakerBinaryPath, | ||
octez_client_base_dir: PathBuf, | ||
octez_node_data_dir: PathBuf, | ||
octez_node_endpoint: Endpoint, | ||
} | ||
|
||
#[derive(Default)] | ||
pub struct OctezBakerConfigBuilder { | ||
binary_path: Option<BakerBinaryPath>, | ||
octez_client_base_dir: Option<PathBuf>, | ||
octez_node_data_dir: Option<PathBuf>, | ||
octez_node_endpoint: Option<Endpoint>, | ||
} | ||
|
||
impl OctezBakerConfigBuilder { | ||
pub fn new() -> Self { | ||
OctezBakerConfigBuilder::default() | ||
} | ||
|
||
pub fn set_binary_path(mut self, binary_path: BakerBinaryPath) -> Self { | ||
self.binary_path = Some(binary_path); | ||
self | ||
} | ||
|
||
pub fn set_octez_client_base_dir(mut self, base_dir: &str) -> Self { | ||
self.octez_client_base_dir = Some(PathBuf::from(base_dir)); | ||
self | ||
} | ||
|
||
pub fn set_octez_node_data_dir(mut self, data_dir: &str) -> Self { | ||
self.octez_node_data_dir = Some(PathBuf::from(data_dir)); | ||
self | ||
} | ||
|
||
pub fn set_octez_node_endpoint(mut self, endpoint: &Endpoint) -> Self { | ||
self.octez_node_endpoint = Some(endpoint.clone()); | ||
self | ||
} | ||
|
||
pub fn with_node_and_client( | ||
mut self, | ||
node_config: &OctezNodeConfig, | ||
client: &OctezClient, | ||
) -> Self { | ||
self.octez_node_data_dir = Some(node_config.data_dir.clone()); | ||
let endpoint = &node_config.rpc_endpoint; | ||
self.octez_node_endpoint = Some(endpoint.clone()); | ||
self.octez_client_base_dir = Some(PathBuf::try_from(client.base_dir()).unwrap()); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<OctezBakerConfig> { | ||
Ok(OctezBakerConfig { | ||
binary_path: self.binary_path.ok_or(anyhow!("binary path not set"))?, | ||
octez_client_base_dir: self | ||
.octez_client_base_dir | ||
.ok_or(anyhow!("octez_client_base_dir not set"))?, | ||
octez_node_data_dir: self | ||
.octez_node_data_dir | ||
.clone() | ||
.ok_or(anyhow!("octez_node_data_dir not set"))?, | ||
octez_node_endpoint: self | ||
.octez_node_endpoint | ||
.ok_or(anyhow!("octez_node_endpoint not set"))?, | ||
}) | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub struct OctezBaker { | ||
inner: SharedChildWrapper, | ||
} | ||
|
||
#[async_trait] | ||
impl Task for OctezBaker { | ||
type Config = OctezBakerConfig; | ||
|
||
async fn spawn(config: Self::Config) -> Result<Self> { | ||
let mut command = Command::new(config.binary_path.to_string()); | ||
command.args([ | ||
"--base-dir", | ||
&config.octez_client_base_dir.to_string_lossy(), | ||
"--endpoint", | ||
&config.octez_node_endpoint.to_string(), | ||
"run", | ||
"remotely", | ||
"--liquidity-baking-toggle-vote", | ||
"pass", | ||
]); | ||
let child = command.spawn()?; | ||
let inner = ChildWrapper::new_shared(child); | ||
Ok(OctezBaker { inner }) | ||
} | ||
|
||
async fn kill(&mut self) -> Result<()> { | ||
let mut lock = self.inner.write().await; | ||
lock.kill().await | ||
} | ||
|
||
async fn health_check(&self) -> Result<bool> { | ||
let mut lock = self.inner.write().await; | ||
Ok(lock.inner_mut().is_running().await) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use http::Uri; | ||
use octez::OctezNodeConfigBuilder; | ||
use tempfile::TempDir; | ||
|
||
use crate::task::octez_client::OctezClientBuilder; | ||
|
||
use super::*; | ||
#[test] | ||
fn test_octez_baker_config_builder() { | ||
let base_dir = TempDir::new().unwrap(); | ||
let data_dir = TempDir::new().unwrap(); | ||
let endpoint = | ||
Endpoint::try_from(Uri::from_static("http://localhost:8732")).unwrap(); | ||
let config: OctezBakerConfig = OctezBakerConfigBuilder::new() | ||
.set_binary_path(BakerBinaryPath::BuiltIn(Protocol::Alpha)) | ||
.set_octez_client_base_dir(base_dir.path().to_str().unwrap()) | ||
.set_octez_node_data_dir(data_dir.path().to_str().unwrap()) | ||
.set_octez_node_endpoint(&endpoint) | ||
.build() | ||
.unwrap(); | ||
assert_eq!( | ||
config.binary_path, | ||
BakerBinaryPath::BuiltIn(Protocol::Alpha) | ||
); | ||
assert_eq!(config.octez_client_base_dir, base_dir.path()); | ||
assert_eq!(config.octez_node_data_dir, data_dir.path()); | ||
assert_eq!(config.octez_node_endpoint, endpoint); | ||
} | ||
|
||
#[test] | ||
fn octez_baker_config_builder_fails_without_binary_path() { | ||
let base_dir = TempDir::new().unwrap(); | ||
let data_dir = TempDir::new().unwrap(); | ||
let endpoint = | ||
Endpoint::try_from(Uri::from_static("http://localhost:8732")).unwrap(); | ||
let config: Result<OctezBakerConfig> = OctezBakerConfigBuilder::new() | ||
.set_octez_client_base_dir(base_dir.path().to_str().unwrap()) | ||
.set_octez_node_data_dir(data_dir.path().to_str().unwrap()) | ||
.set_octez_node_endpoint(&endpoint) | ||
.build(); | ||
assert!(config.is_err_and(|e| e.to_string().contains("binary path not set"))); | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_with_node_config_and_client() { | ||
let node_endpoint = | ||
Endpoint::try_from(Uri::from_static("http://localhost:8732")).unwrap(); | ||
let temp_dir = TempDir::new().unwrap(); | ||
let data_dir: &std::path::Path = temp_dir.path(); | ||
let node_config = OctezNodeConfigBuilder::new() | ||
.set_binary_path("octez-node") | ||
.set_network("sandbox") | ||
.set_rpc_endpoint(&node_endpoint) | ||
.set_data_dir(data_dir.to_str().unwrap()) | ||
.build() | ||
.expect("Failed to build node config"); | ||
|
||
let temp_dir = TempDir::new().unwrap(); | ||
let base_dir: std::path::PathBuf = temp_dir.path().to_path_buf(); | ||
let octez_client = OctezClientBuilder::new() | ||
.set_endpoint(node_endpoint.clone()) | ||
.set_base_dir(base_dir.clone()) | ||
.build() | ||
.expect("Failed to build octez client"); | ||
let config: OctezBakerConfig = OctezBakerConfigBuilder::new() | ||
.set_binary_path(BakerBinaryPath::BuiltIn(Protocol::Alpha)) | ||
.with_node_and_client(&node_config, &octez_client) | ||
.build() | ||
.unwrap(); | ||
assert_eq!( | ||
config.binary_path, | ||
BakerBinaryPath::BuiltIn(Protocol::Alpha) | ||
); | ||
assert_eq!(config.octez_client_base_dir, base_dir); | ||
assert_eq!(config.octez_node_data_dir, data_dir); | ||
assert_eq!(config.octez_node_endpoint, node_endpoint); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.