Skip to main content
Glama
instance.rs11.4 kB
use std::result; use async_trait::async_trait; pub mod cyclone; /// A specification sufficient to spawn [`Instance`]s. /// /// Specs hold any behavioral decisions, configuration details, etc. and can be thought of as a /// factory to build multiple Instances. #[async_trait] pub trait Spec { /// The type which implements the [`Instance`] trait and will be generated for each /// [`Self::spawn`]. type Instance: Instance<Error = Self::Error>; /// Error type returned for errors when calling member methods. type Error; /// Performs activities to clean an [Instance] that failed to prepare. async fn clean(&self, id: u32) -> result::Result<(), Self::Error>; /// Performs activities to prepare an [Instance]. async fn prepare(&self, id: u32) -> result::Result<(), Self::Error>; /// Performs setup activities to prepare the host to create [Instance]s. async fn setup(&mut self) -> result::Result<(), Self::Error>; /// Creates and launches an [`Instance`]. /// /// NOTE: the method is non-consuming so that multiple Instances can be spawned from the same /// `Spec`. /// /// # Examples /// /// ```rust /// use std::error::Error; /// use si_pool_noodle::instance::{Instance, Spec, SpecBuilder}; /// # #[derive(Default)] /// # struct Builder { coolness: usize }; /// # impl SpecBuilder for Builder { /// # type Spec = MySpec; /// # type Error = Box<dyn Error + 'static>; /// # fn build(&self) -> Result<Self::Spec, Self::Error> { /// # Ok(Self::Spec { coolness: self.coolness }) /// # } /// # } /// # impl Builder { /// # fn coolness(&mut self, c: usize) -> &mut Self { self.coolness = c; self } /// # } /// # #[async_trait::async_trait] /// # impl Instance for MyInstance { /// # type SpecBuilder = Builder; /// # type Error = SpawnError; /// # async fn ensure_healthy(&mut self) -> Result<(), Self::Error> { Ok(()) } /// # async fn terminate(mut self) -> Result<(), Self::Error> { Ok(()) } /// # } /// /// #[derive(Debug, thiserror::Error, PartialEq)] /// #[error("failed to spawn")] /// struct SpawnError; /// /// #[derive(Debug, PartialEq)] /// struct MyInstance { coolness: usize } /// /// struct MySpec { coolness: usize } /// /// #[async_trait::async_trait] /// impl Spec for MySpec { /// type Instance = MyInstance; /// type Error = SpawnError; /// /// async fn spawn(&self) -> Result<Self::Instance, Self::Error> { /// Ok(Self::Instance { coolness: self.coolness }) /// } /// } /// /// # tokio_test::block_on(async { /// // A successful termination returns `Ok(())` /// let result = MyInstance::spec() /// .coolness(47) /// .build() /// .unwrap() /// .spawn() /// .await; /// assert_eq!(Ok(MyInstance { coolness: 47 }), result); /// # }); /// # Ok::<(), SpawnError>(()) /// ``` async fn spawn(&self, id: u32) -> result::Result<Self::Instance, Self::Error>; } /// A type which implements the [Builder pattern] and builds a [`Spec`]. /// /// [Builder pattern]: /// https://rust-lang.github.io/api-guidelines/type-safety.html#builders-enable-construction-of-complex-values-c-builder pub trait SpecBuilder: Default { /// The type implementing [`Spec`] which this builder builds. type Spec: Spec; /// Error type returned for errors when calling member methods. type Error; /// ```rust /// use std::error::Error; /// use si_pool_noodle::instance::{Instance, Spec, SpecBuilder}; /// # #[derive(Default)] /// # struct MyInstance; /// # #[async_trait::async_trait] /// # impl Instance for MyInstance { /// # type SpecBuilder = Builder; /// # type Error = BuildError; /// # async fn ensure_healthy(&mut self) -> Result<(), Self::Error> { Ok(()) } /// # async fn terminate(mut self) -> Result<(), Self::Error> { Ok(()) } /// # } /// # #[async_trait::async_trait] /// # impl Spec for MySpec { /// # type Instance = MyInstance; /// # type Error = BuildError; /// # async fn spawn(&self) -> Result<Self::Instance, Self::Error> { Ok(Self::Instance {}) } /// # } /// /// #[derive(Debug, thiserror::Error, PartialEq)] /// #[error("failed to build")] /// struct BuildError; /// /// #[derive(Default)] /// struct Builder { /// coolness: usize /// } /// /// impl SpecBuilder for Builder { /// type Spec = MySpec; /// type Error = BuildError; /// /// fn build(&self) -> Result<Self::Spec, Self::Error> { /// Ok(Self::Spec { coolness: self.coolness }) /// } /// } /// /// impl Builder { /// fn coolness(&mut self, c: usize) -> &mut Self { /// self.coolness = c; /// self /// } /// } /// /// #[derive(Debug, PartialEq)] /// struct MySpec { coolness: usize } /// /// # tokio_test::block_on(async { /// // A successful build returns the `Spec` /// let result = Builder::default() /// .coolness(47) /// .build(); /// assert_eq!(Ok(MySpec { coolness: 47 }), result); /// # }); /// # Ok::<(), BuildError>(()) /// ``` fn build(&self) -> result::Result<Self::Spec, Self::Error>; } /// Represents a generic instance of a managed resource. /// /// An Instance can be spawned, queried for its health, and terminated all in a consistent and /// controlled manner. #[async_trait] pub trait Instance { /// A type that implements the [Builder pattern] to build a type implementing [`Spec`]. /// /// [Builder pattern]: /// https://rust-lang.github.io/api-guidelines/type-safety.html#builders-enable-construction-of-complex-values-c-builder type SpecBuilder: SpecBuilder + Default; /// Error type returned for errors when calling member methods. type Error; /// Returns a default [`Self::SpecBuilder`] that will build an Instance. #[must_use] fn spec() -> Self::SpecBuilder { Self::SpecBuilder::default() } /// Returns `()` if instance is healthy, and a [`Self::Error`] if unhealthy. /// /// Callers can use match destructuring to determine the type or cause of the unhealthiness. /// /// # Examples /// /// ```rust /// use std::error::Error; /// use si_pool_noodle::instance::{Instance, Spec, SpecBuilder}; /// # struct MySpec { healthy: bool } /// # #[async_trait::async_trait] /// # impl Spec for MySpec { /// # type Instance = MyInstance; /// # type Error = Unhealthy; /// # async fn spawn(&self) -> Result<Self::Instance, Self::Error> { /// # Ok(Self::Instance { healthy: self.healthy }) /// # } /// # } /// # #[derive(Default)] /// # struct Builder { healthy: bool }; /// # impl SpecBuilder for Builder { /// # type Spec = MySpec; /// # type Error = Box<dyn Error + 'static>; /// # fn build(&self) -> Result<Self::Spec, Self::Error> { /// # Ok(Self::Spec { healthy: self.healthy }) /// # } /// # } /// # impl Builder { /// # fn healthy(&mut self, healthy: bool) -> &mut Self { /// # self.healthy = healthy; /// # self /// # } /// # } /// /// #[derive(Debug, thiserror::Error, PartialEq)] /// #[error("not healthy")] /// struct Unhealthy; /// /// struct MyInstance { healthy: bool } /// /// #[async_trait::async_trait] /// impl Instance for MyInstance { /// type SpecBuilder = Builder; /// type Error = Unhealthy; /// /// async fn ensure_healthy(&mut self) -> Result<(), Self::Error> { /// if self.healthy { /// Ok(()) /// } else { /// Err(Unhealthy) /// } /// } /// /// async fn terminate(mut self) -> Result<(), Self::Error> { Ok(()) } /// } /// /// # tokio_test::block_on(async { /// // Healthy instances return `Ok(())` /// let mut healthy_instance = MyInstance::spec() /// .healthy(true) /// .build() /// .unwrap() /// .spawn() /// .await /// .unwrap(); /// let result = healthy_instance.ensure_healthy().await; /// assert_eq!(Ok(()), result); /// /// // Unhealthy instances return an `Err` which can be destructured to check what might be /// // unhealthy /// let mut unhealthy_instance = MyInstance::spec() /// .healthy(false) /// .build() /// .unwrap() /// .spawn() /// .await /// .unwrap(); /// let result = unhealthy_instance.ensure_healthy().await; /// assert_eq!(Err((Unhealthy)), result); /// # }); /// # Ok::<(), Unhealthy>(()) /// ``` async fn ensure_healthy(&mut self) -> result::Result<(), Self::Error>; /// Terminates the instance and returns `()` on success or a [`Self::Error`] on failure. /// /// # Examples /// /// ```rust /// use std::error::Error; /// use si_pool_noodle::instance::{Instance, Spec, SpecBuilder}; /// # struct MySpec; /// # #[async_trait::async_trait] /// # impl Spec for MySpec { /// # type Instance = MyInstance; /// # type Error = TerminationError; /// # async fn spawn(&self) -> Result<Self::Instance, Self::Error> { /// # Ok(Self::Instance {}) /// # } /// # } /// # #[derive(Default)] /// # struct Builder; /// # impl SpecBuilder for Builder { /// # type Spec = MySpec; /// # type Error = Box<dyn Error + 'static>; /// # fn build(&self) -> Result<Self::Spec, Self::Error> { Ok(Self::Spec {}) } /// # } /// /// #[derive(Debug, thiserror::Error, PartialEq)] /// #[error("failed to terminate")] /// struct TerminationError; /// /// struct MyInstance; /// /// #[async_trait::async_trait] /// impl Instance for MyInstance { /// type SpecBuilder = Builder; /// type Error = TerminationError; /// /// async fn ensure_healthy(&mut self) -> Result<(), Self::Error> { Ok(()) } /// /// async fn terminate(mut self) -> Result<(), Self::Error> { /// Ok(()) /// } /// } /// /// # tokio_test::block_on(async { /// // A successful termination returns `Ok(())` /// let mut instance = MyInstance::spec() /// .build() /// .unwrap() /// .spawn() /// .await /// .unwrap(); /// let result = instance.terminate().await; /// assert_eq!(Ok(()), result); /// # }); /// # Ok::<(), TerminationError>(()) /// ``` async fn terminate(&mut self) -> result::Result<(), Self::Error>; /// Get the id of the underlying child runtime fn id(&self) -> u32; } // async fn spawn<B, E, I, S>(builder: &B) -> Result<impl Instance<Error = E>, E> // where // B: InstanceSpecBuilder<Spec = S, Error = E>, // S: InstanceSpec<Error = E, Instance = I>, // I: Instance<SpecBuilder = B, Error = E>, // { // builder.build()?.spawn().await // }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server