use std::io::Write;
use seaplane::api::locks::v1::{LockInfo, LockInfoInner, LockName as LockNameModel};
use serde::Serialize;
use tabwriter::TabWriter;
use crate::{
context::Ctx,
error::{CliError, Result},
ops::EncodedString,
printer::{printer, Output},
};
#[derive(Debug, Default, Clone, Serialize)]
pub struct LockName {
pub name: EncodedString,
}
impl LockName {
pub fn new<S: Into<String>>(name: S) -> Self { Self { name: EncodedString::new(name.into()) } }
pub fn from_name_unencoded<S: AsRef<[u8]>>(name: S) -> Self {
let engine = ::base64::engine::fast_portable::FastPortable::from(
&::base64::alphabet::URL_SAFE,
::base64::engine::fast_portable::NO_PAD,
);
let name = base64::encode_engine(name.as_ref(), &engine);
Self { name: EncodedString::new(name) }
}
pub fn to_model(&self) -> LockNameModel { LockNameModel::from_encoded(self.name.to_string()) }
}
#[derive(Debug, Serialize)]
pub struct HeldLock {
pub lock_id: String,
pub sequencer: u32,
}
impl Output for HeldLock {
fn print_json(&self, _ctx: &Ctx) -> Result<()> {
cli_println!("{}", serde_json::to_string(self)?);
Ok(())
}
fn print_table(&self, ctx: &Ctx) -> Result<()> {
let show_headers = !ctx.locks_ctx.get_or_init().no_header;
let mut ptr = printer();
let id_prefix = if show_headers { "LOCK-ID: " } else { "" };
let seq_prefix = if show_headers { "SEQUENCER: " } else { "" };
writeln!(ptr, "{id_prefix}{}", self.lock_id)?;
writeln!(ptr, "{seq_prefix}{}", self.sequencer)?;
ptr.flush()?;
Ok(())
}
}
#[derive(Debug, Serialize)]
pub struct ListedLockInfoInner {
pub ttl: u32,
#[serde(rename = "client-id")]
pub client_id: String,
pub ip: String,
}
impl From<LockInfoInner> for ListedLockInfoInner {
fn from(other: LockInfoInner) -> Self {
Self { ttl: other.ttl, client_id: other.client_id, ip: other.ip }
}
}
#[derive(Debug, Serialize)]
pub struct ListedLock {
name: EncodedString,
id: String,
info: ListedLockInfoInner,
}
impl From<LockInfo> for ListedLock {
fn from(other: LockInfo) -> Self {
let info = other.info.into();
Self {
name: EncodedString::new(other.name.encoded().to_owned()),
id: other.id.encoded().to_owned(),
info,
}
}
}
pub fn print_lock_table<I>(headers: bool, chunk: I, ctx: &Ctx) -> Result<()>
where
I: IntoIterator<Item = ListedLock>,
{
let buffer = Vec::new();
let mut tw = TabWriter::new(buffer);
if headers {
writeln!(tw, "LOCK-NAME\tLOCK-ID\tCLIENT-ID\tCLIENT-IP\tTTL")?;
}
let locksctx = ctx.locks_ctx.get_or_init();
for l in chunk {
if locksctx.decode {
tw.write_all(&l.name.decoded()?)?;
} else {
write!(tw, "{}", l.name)?;
};
writeln!(tw, "\t{}\t{}\t{}\t{}", l.id, l.info.client_id, l.info.ip, l.info.ttl)?;
}
tw.flush()?;
let mut ptr = printer();
let page = tw
.into_inner()
.map_err(|_| CliError::bail("IO flush error writing locks"))?;
ptr.write_all(&page)?;
ptr.flush()?;
Ok(())
}