seaplane_cli/ops/
locks.rs1use std::io::Write;
2
3use seaplane::api::locks::v1::{LockInfo, LockInfoInner, LockName as LockNameModel};
4use serde::Serialize;
5use tabwriter::TabWriter;
6
7use crate::{
8 context::Ctx,
9 error::{CliError, Result},
10 ops::EncodedString,
11 printer::{printer, Output},
12};
13
14#[derive(Debug, Default, Clone, Serialize)]
19pub struct LockName {
20 pub name: EncodedString,
21}
22
23impl LockName {
24 pub fn new<S: Into<String>>(name: S) -> Self { Self { name: EncodedString::new(name.into()) } }
27
28 pub fn from_name_unencoded<S: AsRef<[u8]>>(name: S) -> Self {
30 let engine = ::base64::engine::fast_portable::FastPortable::from(
31 &::base64::alphabet::URL_SAFE,
32 ::base64::engine::fast_portable::NO_PAD,
33 );
34 let name = base64::encode_engine(name.as_ref(), &engine);
35 Self { name: EncodedString::new(name) }
36 }
37
38 pub fn to_model(&self) -> LockNameModel { LockNameModel::from_encoded(self.name.to_string()) }
40}
41
42#[derive(Debug, Serialize)]
43pub struct HeldLock {
44 pub lock_id: String,
45 pub sequencer: u32,
46}
47
48impl Output for HeldLock {
49 fn print_json(&self, _ctx: &Ctx) -> Result<()> {
50 cli_println!("{}", serde_json::to_string(self)?);
51 Ok(())
52 }
53
54 fn print_table(&self, ctx: &Ctx) -> Result<()> {
55 let show_headers = !ctx.locks_ctx.get_or_init().no_header;
56 let mut ptr = printer();
57
58 let id_prefix = if show_headers { "LOCK-ID: " } else { "" };
59 let seq_prefix = if show_headers { "SEQUENCER: " } else { "" };
60 writeln!(ptr, "{id_prefix}{}", self.lock_id)?;
61 writeln!(ptr, "{seq_prefix}{}", self.sequencer)?;
62
63 ptr.flush()?;
64
65 Ok(())
66 }
67}
68
69#[derive(Debug, Serialize)]
70pub struct ListedLockInfoInner {
71 pub ttl: u32,
72 #[serde(rename = "client-id")]
73 pub client_id: String,
74 pub ip: String,
75}
76
77impl From<LockInfoInner> for ListedLockInfoInner {
78 fn from(other: LockInfoInner) -> Self {
79 Self { ttl: other.ttl, client_id: other.client_id, ip: other.ip }
80 }
81}
82
83#[derive(Debug, Serialize)]
84pub struct ListedLock {
85 name: EncodedString,
86 id: String,
87 info: ListedLockInfoInner,
88}
89
90impl From<LockInfo> for ListedLock {
91 fn from(other: LockInfo) -> Self {
92 let info = other.info.into();
93 Self {
94 name: EncodedString::new(other.name.encoded().to_owned()),
95 id: other.id.encoded().to_owned(),
96 info,
97 }
98 }
99}
100
101pub fn print_lock_table<I>(headers: bool, chunk: I, ctx: &Ctx) -> Result<()>
102where
103 I: IntoIterator<Item = ListedLock>,
104{
105 let buffer = Vec::new();
106 let mut tw = TabWriter::new(buffer);
107 if headers {
108 writeln!(tw, "LOCK-NAME\tLOCK-ID\tCLIENT-ID\tCLIENT-IP\tTTL")?;
109 }
110
111 let locksctx = ctx.locks_ctx.get_or_init();
112 for l in chunk {
113 if locksctx.decode {
114 tw.write_all(&l.name.decoded()?)?;
117 } else {
118 write!(tw, "{}", l.name)?;
119 };
120
121 writeln!(tw, "\t{}\t{}\t{}\t{}", l.id, l.info.client_id, l.info.ip, l.info.ttl)?;
122 }
123 tw.flush()?;
124
125 let mut ptr = printer();
126 let page = tw
127 .into_inner()
128 .map_err(|_| CliError::bail("IO flush error writing locks"))?;
129 ptr.write_all(&page)?;
130 ptr.flush()?;
131
132 Ok(())
133}