use time::OffsetDateTime;
use crate::ports::{
HostDeliveryFilter, HostDeliveryLedgerPort, HostDeliveryPageLimit, HostDeliveryTargetFilter,
LeasedDelivery,
};
use crate::value_objects::{
DurationMs, HostDeliveryId, HostDeliveryLease, HostDeliveryPolicy, HostDeliveryStateKind,
HostDeliveryTarget,
};
use super::host_delivery_fixtures::{call, ceremony, failure, incarnation, record};
use super::ConformanceFailure;
const LEASE_MS: u64 = 30_000;
pub(super) async fn enqueue(
property: &'static str,
ledger: &dyn HostDeliveryLedgerPort,
item_suffix: &str,
target: HostDeliveryTarget,
) -> Result<HostDeliveryId, ConformanceFailure> {
let offered = record(property, item_suffix, target, HostDeliveryPolicy::default())?;
let id = offered.id().clone();
call(property, ledger.enqueue(offered).await)?;
Ok(id)
}
pub(super) async fn lease_all(
property: &'static str,
ledger: &dyn HostDeliveryLedgerPort,
target: &HostDeliveryTarget,
owner_suffix: &str,
now: OffsetDateTime,
) -> Result<Vec<LeasedDelivery>, ConformanceFailure> {
let filter = HostDeliveryFilter::to(
HostDeliveryTargetFilter::any_of([target.clone()])
.map_err(|error| failure(property, error.to_string()))?,
)
.in_ceremony(ceremony(property)?);
call(
property,
ledger
.lease(
&filter,
&incarnation(property, owner_suffix)?,
now,
DurationMs::from_millis(LEASE_MS),
HostDeliveryPageLimit::default(),
)
.await,
)
}
pub(super) async fn lease_one(
property: &'static str,
ledger: &dyn HostDeliveryLedgerPort,
target: &HostDeliveryTarget,
owner_suffix: &str,
now: OffsetDateTime,
) -> Result<Option<HostDeliveryLease>, ConformanceFailure> {
Ok(lease_all(property, ledger, target, owner_suffix, now)
.await?
.into_iter()
.next()
.map(|leased| leased.into_parts().0))
}
pub(super) async fn state_of(
property: &'static str,
ledger: &dyn HostDeliveryLedgerPort,
target: &HostDeliveryTarget,
item_suffix: &str,
) -> Result<HostDeliveryStateKind, ConformanceFailure> {
let offered = record(
property,
item_suffix,
target.clone(),
HostDeliveryPolicy::default(),
)?;
let found = call(property, ledger.get(offered.id()).await)?
.ok_or_else(|| failure(property, "a delivery that was enqueued cannot be read back"))?;
Ok(found.state().kind())
}
pub(super) async fn require_lease(
property: &'static str,
ledger: &dyn HostDeliveryLedgerPort,
target: &HostDeliveryTarget,
owner_suffix: &str,
now: OffsetDateTime,
) -> Result<HostDeliveryLease, ConformanceFailure> {
lease_one(property, ledger, target, owner_suffix, now)
.await?
.ok_or_else(|| failure(property, "a queued delivery could not be leased"))
}