use super::super::RailError;
use super::{Live, Source};
fn expired_admission(error: &RailError) -> bool {
let RailError::Refused(message) = error else {
return false;
};
message.starts_with("connection error: server rejected")
&& message.ends_with(": lys pass admission refused: pass_expired")
}
impl Live {
pub(super) fn admit<T>(
&self,
connect: impl FnMut(&[u8]) -> Result<T, RailError>,
) -> Result<T, RailError> {
Self::admit_with(
connect,
|| {
let Source::Lys(agent) = &self.source else {
return Ok(false);
};
agent
.forget_expired_pass()
.map_err(|error| RailError::Refused(error.0))
},
|| self.credential(),
)
}
fn admit_with<T>(
mut connect: impl FnMut(&[u8]) -> Result<T, RailError>,
renew: impl FnOnce() -> Result<bool, RailError>,
credential: impl Fn() -> Result<Vec<u8>, RailError>,
) -> Result<T, RailError> {
let answer = connect(&credential()?);
if let Err(error) = &answer
&& expired_admission(error)
&& renew()?
{
return connect(&credential()?);
}
answer
}
}
#[cfg(test)]
mod tests {
use super::{Live, RailError};
use std::cell::Cell;
#[test]
fn an_expired_admission_asks_once_more_and_keeps_a_second_refusal() {
let calls = Cell::new(0);
let renewals = Cell::new(0);
let error = RailError::Refused("connection error: server rejected connection (reason 6): lys pass admission refused: pass_expired".to_owned());
let result: Result<(), _> = Live::admit_with(
|_| {
calls.set(calls.get() + 1);
Err(error.clone())
},
|| {
renewals.set(renewals.get() + 1);
Ok(true)
},
|| Ok(Vec::new()),
);
assert_eq!(result, Err(error));
assert_eq!(calls.get(), 2);
assert_eq!(renewals.get(), 1);
}
#[test]
fn an_application_refusal_and_an_unproven_pass_are_never_repeated() {
for text in [
"conversation 1: pass_expired",
"connection error: server rejected connection (reason 6): lys pass admission refused: signature_refused",
] {
let calls = Cell::new(0);
let renewals = Cell::new(0);
let result: Result<(), _> = Live::admit_with(
|_| {
calls.set(calls.get() + 1);
Err(RailError::Refused(text.to_owned()))
},
|| {
renewals.set(renewals.get() + 1);
Err(RailError::Refused("this refusal cannot renew".to_owned()))
},
|| Ok(Vec::new()),
);
assert_eq!(result, Err(RailError::Refused(text.to_owned())));
assert_eq!(calls.get(), 1);
assert_eq!(renewals.get(), 0);
}
}
}