use crate::config::{Config, Credential};
use crate::lys::LysAgent;
use liminal_sdk::{SdkError, lys_pass_credential};
use zeroize::Zeroizing;
enum Proof {
Fixed(Zeroizing<Vec<u8>>),
Lys(LysAgent),
}
pub(super) struct Source {
pub address: String,
pub record_bytes: usize,
pub timeout: std::time::Duration,
proof: Proof,
revoke: Option<super::channel_lifecycle::Revoke>,
}
impl std::fmt::Debug for Source {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ChannelSource")
.field("address", &self.address)
.field("record_bytes", &self.record_bytes)
.finish_non_exhaustive()
}
}
impl Source {
pub fn new(config: &Config) -> Result<Self, String> {
let revoke = super::channel_lifecycle::Revoke::new(config)?;
let proof = match &config.credential {
Credential::Token(token) => {
Proof::Fixed(Zeroizing::new(lys_pass_credential(token.as_str())))
}
Credential::Lys(table) => Proof::Lys(
LysAgent::new(table, config.limits.reply_timeout()).map_err(str::to_owned)?,
),
Credential::Open => Proof::Fixed(Zeroizing::new(Vec::new())),
};
Ok(Self {
address: config.server.clone(),
record_bytes: config.limits.record_bytes,
timeout: config.limits.reply_timeout(),
proof,
revoke,
})
}
pub fn credential(&self) -> Result<Zeroizing<Vec<u8>>, String> {
match &self.proof {
Proof::Fixed(bytes) => Ok(Zeroizing::new(bytes.to_vec())),
Proof::Lys(agent) => agent
.pass()
.map(|pass| Zeroizing::new(lys_pass_credential(&pass)))
.map_err(|error| error.0),
}
}
pub fn revoke(&self) -> Result<(), String> {
self.revoke
.as_ref()
.map_or(Ok(()), super::channel_lifecycle::Revoke::send)
}
}
pub(super) fn words(error: SdkError) -> String {
let detail = match error {
SdkError::Protocol { description } | SdkError::Connection { description } => description,
error => return error.to_string(),
};
for prefix in [
"server rejected subscribe (reason ",
"server ended the subscription (reason ",
"server rejected subscription connection (reason ",
] {
if let Some(rest) = detail.strip_prefix(prefix)
&& let Some((code, words)) = rest.split_once("): ")
&& code.parse::<u16>().is_ok()
{
return words.to_owned();
}
}
detail
}