Maintain OrderState within Order type
This commit is contained in:
parent
652c4815ec
commit
a2d4129201
|
@ -34,19 +34,20 @@ async fn main() -> anyhow::Result<()> {
|
||||||
// process multiple orders in parallel for a single account.
|
// process multiple orders in parallel for a single account.
|
||||||
|
|
||||||
let identifier = Identifier::Dns(opts.name);
|
let identifier = Identifier::Dns(opts.name);
|
||||||
let (mut order, state) = account
|
let mut order = account
|
||||||
.new_order(&NewOrder {
|
.new_order(&NewOrder {
|
||||||
identifiers: &[identifier],
|
identifiers: &[identifier],
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let state = order.state();
|
||||||
info!("order state: {:#?}", state);
|
info!("order state: {:#?}", state);
|
||||||
assert!(matches!(state.status, OrderStatus::Pending));
|
assert!(matches!(state.status, OrderStatus::Pending));
|
||||||
|
|
||||||
// Pick the desired challenge type and prepare the response.
|
// Pick the desired challenge type and prepare the response.
|
||||||
|
|
||||||
let authorizations = order.authorizations(&state.authorizations).await.unwrap();
|
let authorizations = order.authorizations().await.unwrap();
|
||||||
let mut challenges = Vec::with_capacity(authorizations.len());
|
let mut challenges = Vec::with_capacity(authorizations.len());
|
||||||
for authz in &authorizations {
|
for authz in &authorizations {
|
||||||
match authz.status {
|
match authz.status {
|
||||||
|
@ -87,12 +88,12 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let mut tries = 1u8;
|
let mut tries = 1u8;
|
||||||
let mut delay = Duration::from_millis(250);
|
let mut delay = Duration::from_millis(250);
|
||||||
let state = loop {
|
loop {
|
||||||
sleep(delay).await;
|
sleep(delay).await;
|
||||||
let state = order.state().await.unwrap();
|
let state = order.refresh().await.unwrap();
|
||||||
if let OrderStatus::Ready | OrderStatus::Invalid = state.status {
|
if let OrderStatus::Ready | OrderStatus::Invalid = state.status {
|
||||||
info!("order state: {:#?}", state);
|
info!("order state: {:#?}", state);
|
||||||
break state;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
delay *= 2;
|
delay *= 2;
|
||||||
|
@ -104,10 +105,14 @@ async fn main() -> anyhow::Result<()> {
|
||||||
return Err(anyhow::anyhow!("order is not ready"));
|
return Err(anyhow::anyhow!("order is not ready"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if state.status == OrderStatus::Invalid {
|
let state = order.state();
|
||||||
return Err(anyhow::anyhow!("order is invalid"));
|
if state.status != OrderStatus::Ready {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"unexpected order status: {:?}",
|
||||||
|
state.status
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut names = Vec::with_capacity(challenges.len());
|
let mut names = Vec::with_capacity(challenges.len());
|
||||||
|
@ -125,7 +130,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
// Finalize the order and print certificate chain, private key and account credentials.
|
// Finalize the order and print certificate chain, private key and account credentials.
|
||||||
|
|
||||||
let cert_chain_pem = order.finalize(&csr, &state.finalize).await.unwrap();
|
let cert_chain_pem = order.finalize(&csr).await.unwrap();
|
||||||
info!("certficate chain:\n\n{}", cert_chain_pem,);
|
info!("certficate chain:\n\n{}", cert_chain_pem,);
|
||||||
info!("private key:\n\n{}", cert.serialize_private_key_pem());
|
info!("private key:\n\n{}", cert.serialize_private_key_pem());
|
||||||
info!(
|
info!(
|
||||||
|
|
63
src/lib.rs
63
src/lib.rs
|
@ -36,7 +36,8 @@ use types::{
|
||||||
pub struct Order {
|
pub struct Order {
|
||||||
account: Arc<AccountInner>,
|
account: Arc<AccountInner>,
|
||||||
nonce: Option<String>,
|
nonce: Option<String>,
|
||||||
order_url: String,
|
url: String,
|
||||||
|
state: OrderState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Order {
|
impl Order {
|
||||||
|
@ -55,12 +56,9 @@ impl Order {
|
||||||
/// After the challenges have been set up, check the [`Order::state()`] to see
|
/// After the challenges have been set up, check the [`Order::state()`] to see
|
||||||
/// if the order is ready to be finalized (or becomes invalid). Once it is
|
/// if the order is ready to be finalized (or becomes invalid). Once it is
|
||||||
/// ready, call `Order::finalize()` to get the certificate.
|
/// ready, call `Order::finalize()` to get the certificate.
|
||||||
pub async fn authorizations(
|
pub async fn authorizations(&mut self) -> Result<Vec<Authorization>, Error> {
|
||||||
&mut self,
|
let mut authorizations = Vec::with_capacity(self.state.authorizations.len());
|
||||||
authz_urls: &[String],
|
for url in &self.state.authorizations {
|
||||||
) -> Result<Vec<Authorization>, Error> {
|
|
||||||
let mut authorizations = Vec::with_capacity(authz_urls.len());
|
|
||||||
for url in authz_urls {
|
|
||||||
authorizations.push(self.account.get(&mut self.nonce, url).await?);
|
authorizations.push(self.account.get(&mut self.nonce, url).await?);
|
||||||
}
|
}
|
||||||
Ok(authorizations)
|
Ok(authorizations)
|
||||||
|
@ -77,15 +75,15 @@ impl Order {
|
||||||
/// Request a certificate from the given Certificate Signing Request (CSR)
|
/// Request a certificate from the given Certificate Signing Request (CSR)
|
||||||
///
|
///
|
||||||
/// Creating a CSR is outside of the scope of instant-acme. Make sure you pass in a
|
/// Creating a CSR is outside of the scope of instant-acme. Make sure you pass in a
|
||||||
/// DER representation of the CSR in `csr_der` and the [`OrderState::finalize`] URL
|
/// DER representation of the CSR in `csr_der`. The resulting `String` will contain the
|
||||||
/// in `finalize_url`. The resulting `String` will contain the PEM-encoded certificate chain.
|
/// PEM-encoded certificate chain.
|
||||||
pub async fn finalize(&mut self, csr_der: &[u8], finalize_url: &str) -> Result<String, Error> {
|
pub async fn finalize(&mut self, csr_der: &[u8]) -> Result<String, Error> {
|
||||||
let rsp = self
|
let rsp = self
|
||||||
.account
|
.account
|
||||||
.post(
|
.post(
|
||||||
Some(&FinalizeRequest::new(csr_der)),
|
Some(&FinalizeRequest::new(csr_der)),
|
||||||
self.nonce.take(),
|
self.nonce.take(),
|
||||||
finalize_url,
|
&self.state.finalize,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -129,9 +127,28 @@ impl Order {
|
||||||
self.account.get(&mut self.nonce, challenge_url).await
|
self.account.get(&mut self.nonce, challenge_url).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current state of the order
|
/// Refresh the current state of the order
|
||||||
pub async fn state(&mut self) -> Result<OrderState, Error> {
|
pub async fn refresh(&mut self) -> Result<&OrderState, Error> {
|
||||||
self.account.get(&mut self.nonce, &self.order_url).await
|
let rsp = self
|
||||||
|
.account
|
||||||
|
.post(None::<&Empty>, self.nonce.take(), &self.url)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.nonce = nonce_from_response(&rsp);
|
||||||
|
self.state = Problem::check::<OrderState>(rsp).await?;
|
||||||
|
Ok(&self.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the last known state of the order
|
||||||
|
///
|
||||||
|
/// Call `refresh()` to get the latest state from the server.
|
||||||
|
pub fn state(&mut self) -> &OrderState {
|
||||||
|
&self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the URL of the order
|
||||||
|
pub fn url(&self) -> &str {
|
||||||
|
&self.url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +202,8 @@ impl Account {
|
||||||
|
|
||||||
/// Create a new order based on the given [`NewOrder`]
|
/// Create a new order based on the given [`NewOrder`]
|
||||||
///
|
///
|
||||||
/// Returns both an [`Order`] instance and the initial [`OrderState`].
|
/// Returns an [`Order`] instance. Use the [`Order::state()`] method to inspect its state.
|
||||||
pub async fn new_order<'a>(
|
pub async fn new_order<'a>(&'a self, order: &NewOrder<'_>) -> Result<Order, Error> {
|
||||||
&'a self,
|
|
||||||
order: &NewOrder<'_>,
|
|
||||||
) -> Result<(Order, OrderState), Error> {
|
|
||||||
let rsp = self
|
let rsp = self
|
||||||
.inner
|
.inner
|
||||||
.post(Some(order), None, &self.inner.client.urls.new_order)
|
.post(Some(order), None, &self.inner.client.urls.new_order)
|
||||||
|
@ -202,15 +216,12 @@ impl Account {
|
||||||
.and_then(|hv| hv.to_str().ok())
|
.and_then(|hv| hv.to_str().ok())
|
||||||
.map(|s| s.to_owned());
|
.map(|s| s.to_owned());
|
||||||
|
|
||||||
let status = Problem::check(rsp).await?;
|
Ok(Order {
|
||||||
Ok((
|
|
||||||
Order {
|
|
||||||
account: self.inner.clone(),
|
account: self.inner.clone(),
|
||||||
nonce,
|
nonce,
|
||||||
order_url: order_url.ok_or("no order URL found")?,
|
url: order_url.ok_or("no order URL found")?,
|
||||||
},
|
state: Problem::check::<OrderState>(rsp).await?,
|
||||||
status,
|
})
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the account's credentials, which can be serialized
|
/// Get the account's credentials, which can be serialized
|
||||||
|
|
Loading…
Reference in New Issue