1use crate::codec::{Decoder, Encoder};
2use crate::error::Result;
3use crate::header::RequestHeader;
4
5pub const API_KEY: i16 = 3;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct MetadataRequestV1 {
9 pub correlation_id: i32,
10 pub client_id: Option<String>,
11 pub topics: Option<Vec<String>>,
12}
13
14impl MetadataRequestV1 {
15 pub fn encode(&self) -> Result<Vec<u8>> {
16 let mut encoder = Encoder::new();
17 RequestHeader {
18 api_key: API_KEY,
19 api_version: 1,
20 correlation_id: self.correlation_id,
21 client_id: self.client_id.clone(),
22 }
23 .encode_v1(&mut encoder)?;
24 encoder.write_array(self.topics.as_deref(), |encoder, topic| {
25 encoder.write_string(topic)
26 })?;
27 Ok(encoder.into_bytes())
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct BrokerMetadata {
33 pub node_id: i32,
34 pub host: String,
35 pub port: i32,
36 pub rack: Option<String>,
37}
38
39impl BrokerMetadata {
40 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
41 Ok(Self {
42 node_id: decoder.read_i32()?,
43 host: decoder.read_string()?,
44 port: decoder.read_i32()?,
45 rack: decoder.read_nullable_string()?,
46 })
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct PartitionMetadata {
52 pub error_code: i16,
53 pub partition_index: i32,
54 pub leader_id: i32,
55 pub replica_nodes: Vec<i32>,
56 pub isr_nodes: Vec<i32>,
57}
58
59impl PartitionMetadata {
60 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
61 Ok(Self {
62 error_code: decoder.read_i16()?,
63 partition_index: decoder.read_i32()?,
64 leader_id: decoder.read_i32()?,
65 replica_nodes: decoder
66 .read_array("replica nodes", |decoder| decoder.read_i32())?
67 .unwrap_or_default(),
68 isr_nodes: decoder
69 .read_array("isr nodes", |decoder| decoder.read_i32())?
70 .unwrap_or_default(),
71 })
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct TopicMetadata {
77 pub error_code: i16,
78 pub name: String,
79 pub is_internal: bool,
80 pub partitions: Vec<PartitionMetadata>,
81}
82
83impl TopicMetadata {
84 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
85 Ok(Self {
86 error_code: decoder.read_i16()?,
87 name: decoder.read_string()?,
88 is_internal: decoder.read_bool()?,
89 partitions: decoder
90 .read_array("partitions", PartitionMetadata::decode)?
91 .unwrap_or_default(),
92 })
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct MetadataResponseV1 {
98 pub brokers: Vec<BrokerMetadata>,
99 pub controller_id: i32,
100 pub topics: Vec<TopicMetadata>,
101}
102
103impl MetadataResponseV1 {
104 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
105 Ok(Self {
106 brokers: decoder
107 .read_array("brokers", BrokerMetadata::decode)?
108 .unwrap_or_default(),
109 controller_id: decoder.read_i32()?,
110 topics: decoder
111 .read_array("topics", TopicMetadata::decode)?
112 .unwrap_or_default(),
113 })
114 }
115}
116
117#[cfg(test)]
118#[allow(clippy::unwrap_used)]
119mod tests {
120 use super::{MetadataRequestV1, MetadataResponseV1, API_KEY};
121 use crate::codec::Decoder;
122
123 #[test]
124 fn encodes_metadata_request_v1_for_topics() {
125 let request = MetadataRequestV1 {
126 correlation_id: 9,
127 client_id: Some("kafrust".to_owned()),
128 topics: Some(vec!["orders".to_owned()]),
129 };
130
131 assert_eq!(
132 request.encode().unwrap(),
133 [
134 0, 3, 0, 1, 0, 0, 0, 9, 0, 7, b'k', b'a', b'f', b'r', b'u', b's', b't', 0, 0, 0, 1, 0, 6, b'o', b'r', b'd', b'e', b'r', b's', ]
141 );
142 assert_eq!(API_KEY, 3);
143 }
144
145 #[test]
146 fn encodes_metadata_request_v1_for_all_topics() {
147 let request = MetadataRequestV1 {
148 correlation_id: 9,
149 client_id: None,
150 topics: None,
151 };
152
153 assert_eq!(
154 request.encode().unwrap(),
155 [
156 0, 3, 0, 1, 0, 0, 0, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ]
162 );
163 }
164
165 #[test]
166 fn decodes_metadata_response_v1() {
167 let bytes = [
168 0, 0, 0, 1, 0, 0, 0, 1, 0, 9, b'l', b'o', b'c', b'a', b'l', b'h', b'o', b's', b't', 0, 0, 35, 132, 0xff, 0xff, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 6, b'o', b'r', b'd', b'e', b'r', b's', 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, ];
187
188 let mut decoder = Decoder::new(&bytes);
189 let response = MetadataResponseV1::decode_body(&mut decoder).unwrap();
190
191 assert_eq!(response.controller_id, 1);
192 assert_eq!(response.brokers.len(), 1);
193 assert_eq!(response.brokers[0].host, "localhost");
194 assert_eq!(response.brokers[0].port, 9092);
195 assert_eq!(response.topics.len(), 1);
196 assert_eq!(response.topics[0].name, "orders");
197 assert_eq!(response.topics[0].partitions[0].leader_id, 1);
198 assert_eq!(response.topics[0].partitions[0].replica_nodes, vec![1]);
199 assert_eq!(response.topics[0].partitions[0].isr_nodes, vec![1]);
200 assert!(decoder.is_empty());
201 }
202}