1use super::append::Authority;
4use super::{ENVELOPE_BYTES, Envelope, EnvelopeError, EnvelopeLimits, Opcode, Packet};
5use crate::{
6 GroupId, NodeId,
7 layout::{Fixed, LayoutError, Reader},
8};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct AuthorityHint {
13 pub authority: Authority,
15 pub primary: NodeId,
17}
18
19impl AuthorityHint {
20 pub fn encode(self) -> Result<[u8; 48], NackError> {
22 self.validate()?;
23 let mut bytes = [0; 48];
24 bytes[..16].copy_from_slice(self.authority.group_id.as_bytes());
25 bytes[16..24].copy_from_slice(&self.authority.config_epoch.to_be_bytes());
26 bytes[24..32].copy_from_slice(&self.authority.view.to_be_bytes());
27 bytes[32..].copy_from_slice(self.primary.as_bytes());
28 Ok(bytes)
29 }
30
31 pub fn decode(bytes: &[u8]) -> Result<Self, NackError> {
34 let bytes: &[u8; 48] = bytes.try_into().map_err(|_| NackError::Length)?;
35 let hint = Self {
36 authority: Authority {
37 group_id: GroupId::from_bytes(bytes.array::<0, 16>()),
38 config_epoch: bytes.u64_at::<16>(),
39 view: bytes.u64_at::<24>(),
40 },
41 primary: NodeId::from_bytes(bytes.array::<32, 16>()),
42 };
43 hint.validate()?;
44 Ok(hint)
45 }
46
47 fn validate(self) -> Result<(), NackError> {
48 if self.authority.group_id.as_bytes() == &[0; 16]
49 || self.authority.config_epoch == 0
50 || self.primary.as_bytes() == &[0; 16]
51 {
52 return Err(NackError::Authority);
53 }
54 Ok(())
55 }
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60#[repr(u8)]
61pub enum RetryClass {
62 Permanent = 1,
64 AfterBackoff = 2,
66 AfterReconnect = 3,
68 AfterAuthorityRefresh = 4,
70 UnknownOutcome = 5,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub struct Nack<'a> {
77 pub code: u16,
79 pub retry: RetryClass,
81 pub detail: &'a [u8],
83 pub diagnostic: &'a str,
85}
86
87pub fn encode(
89 envelope: Envelope,
90 nack: Nack<'_>,
91 metadata: &mut Vec<u8>,
92 limits: EnvelopeLimits,
93) -> Result<[u8; ENVELOPE_BYTES], NackError> {
94 command(envelope)?;
95 let size = 11_usize
96 .checked_add(nack.detail.len())
97 .and_then(|n| n.checked_add(nack.diagnostic.len()))
98 .ok_or(NackError::Length)?;
99 let header = envelope.encode_header(size, 0, limits)?;
100 let detail = u32::try_from(nack.detail.len()).map_err(|_| NackError::Length)?;
101 let diagnostic = u32::try_from(nack.diagnostic.len()).map_err(|_| NackError::Length)?;
102 if metadata.capacity() < size {
103 return Err(NackError::Capacity);
104 }
105 metadata.clear();
106 metadata.extend_from_slice(&nack.code.to_be_bytes());
107 metadata.push(nack.retry as u8);
108 metadata.extend_from_slice(&detail.to_be_bytes());
109 metadata.extend_from_slice(nack.detail);
110 metadata.extend_from_slice(&diagnostic.to_be_bytes());
111 metadata.extend_from_slice(nack.diagnostic.as_bytes());
112 Ok(header)
113}
114
115pub fn decode(packet: Packet<'_>, limits: EnvelopeLimits) -> Result<Nack<'_>, NackError> {
117 command(packet.envelope)?;
118 packet
119 .envelope
120 .validate_frames(packet.metadata.len(), packet.payload.len(), limits)?;
121 if !packet.payload.is_empty() {
122 return Err(NackError::Command);
123 }
124 let mut reader = Reader::new(packet.metadata);
125 let code = reader.u16()?;
126 let retry = match reader.u8()? {
127 1 => RetryClass::Permanent,
128 2 => RetryClass::AfterBackoff,
129 3 => RetryClass::AfterReconnect,
130 4 => RetryClass::AfterAuthorityRefresh,
131 5 => RetryClass::UnknownOutcome,
132 _ => return Err(NackError::Command),
133 };
134 let size = reader.u32()? as usize;
135 let detail = reader.take(size)?;
136 let size = reader.u32()? as usize;
137 let diagnostic = std::str::from_utf8(reader.take(size)?).map_err(|_| NackError::Length)?;
138 reader.finish()?;
139 Ok(Nack {
140 code,
141 retry,
142 detail,
143 diagnostic,
144 })
145}
146
147fn command(envelope: Envelope) -> Result<(), NackError> {
148 if envelope.opcode != Opcode::Nack || !envelope.response || envelope.request_id.is_none() {
149 return Err(NackError::Command);
150 }
151 Ok(())
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
156pub enum NackError {
157 #[error("invalid NACK authority hint")]
159 Authority,
160 #[error(transparent)]
162 Envelope(#[from] EnvelopeError),
163 #[error("invalid NACK command")]
165 Command,
166 #[error("invalid NACK field length")]
168 Length,
169 #[error("NACK encode buffer capacity exhausted")]
171 Capacity,
172}
173
174impl From<LayoutError> for NackError {
175 fn from(_: LayoutError) -> Self {
176 Self::Length
177 }
178}