Skip to content

Commit 75545fc

Browse files
committed
add semantic parsing of show protocols all command
1 parent b1e08ad commit 75545fc

File tree

4 files changed

+359
-3
lines changed

4 files changed

+359
-3
lines changed

src/connection.rs

+70-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use tokio::net::UnixStream;
77

88
use crate::{
99
Error, Interface, InterfaceAddress, InterfaceProperties, InterfaceSummary, Message, Protocol,
10-
Result, ShowInterfacesMessage,
10+
ProtocolDetail, Result, ShowInterfacesMessage, ShowProtocolDetailsMessage,
1111
};
1212

1313
/// An active connection, on which requests can be executed, and responses
@@ -195,7 +195,7 @@ impl Connection {
195195
}
196196

197197
/// Sends a `show protocols [<pattern>]` request and returns the parsed response as a
198-
/// list of [InterfaceSummary] entries, one each for an interface.
198+
/// list of [InterfaceSummary] entries, one for each protocol.
199199
///
200200
/// If `pattern` is specified, results of only those protocols is returned, which
201201
/// match the pattern.
@@ -223,6 +223,74 @@ impl Connection {
223223
Err(Error::ParseError(messages))
224224
}
225225

226+
/// Sends a `show protocols all [<pattern>]` request and returns the parsed response as a
227+
/// list of [ShowProtocolDetailsMessage] entries, one for each protocol instance.
228+
///
229+
/// If `pattern` is specified, results of only those protocols is returned, which
230+
/// match the pattern.
231+
pub async fn show_protocols_details(
232+
&mut self,
233+
pattern: Option<&str>,
234+
) -> Result<Vec<ShowProtocolDetailsMessage>> {
235+
let cmd = if let Some(pattern) = pattern {
236+
format!("show protocols all \"{}\"", pattern)
237+
} else {
238+
"show protocols all".into()
239+
};
240+
let mut result = vec![];
241+
let messages = self.send_request(&cmd).await?;
242+
243+
// we expect messages to show up as a series of doublets: 1002 and 1006
244+
if let Some(mut idx) = messages
245+
.iter()
246+
.position(|x| matches!(x, Message::ProtocolList(_)))
247+
{
248+
while idx < messages.len() {
249+
// each iteration here means fully going through the pair of 1002 and 1006
250+
251+
if let Some(protocol) = Protocol::from_enum(&messages[idx]) {
252+
// move index to the next message
253+
idx += 1;
254+
// if we have a valid 1002 ...
255+
if let Some(protocol) = protocol.first() {
256+
// ... check for 1006
257+
if idx == messages.len()
258+
|| !matches!(messages[idx], Message::ProtocolDetails(_))
259+
{
260+
// if we're already at the end, or if there's no 1006 after the 1002 we saw
261+
// just a step before, we push the current 1002 without any 1006, and continue
262+
result.push(ShowProtocolDetailsMessage {
263+
protocol: protocol.clone(),
264+
detail: None,
265+
});
266+
continue;
267+
}
268+
// looks like we have a valid 1006, so let's process it
269+
if let Some(detail) = ProtocolDetail::from_enum(&messages[idx]) {
270+
// looks like we got a valid 1006
271+
idx += 1;
272+
result.push(ShowProtocolDetailsMessage {
273+
protocol: protocol.clone(),
274+
detail: Some(detail),
275+
});
276+
} else {
277+
log::error!("conn: failed to parse 1006 message");
278+
return Err(Error::ParseError(messages));
279+
}
280+
}
281+
} else {
282+
log::error!("conn: failed to parse 1002 message: {:?}", messages[idx]);
283+
return Err(Error::ParseError(messages));
284+
}
285+
}
286+
287+
Ok(result)
288+
} else {
289+
// No 1002 entries, so empty result
290+
Ok(Vec::new())
291+
}
292+
}
293+
226294
/// Reads a full [Message] from the server, and returns it
227295
async fn next_message(&mut self) -> Result<Message> {
228296
// if we have pending messages, return the first one

src/models/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,11 @@ pub struct ShowInterfacesMessage {
1313
pub properties: InterfaceProperties,
1414
pub addresses: Vec<InterfaceAddress>,
1515
}
16+
17+
/// A composite entry in the `show protocols all` command. Represents
18+
/// the details of a protocol instance.
19+
#[derive(Debug)]
20+
pub struct ShowProtocolDetailsMessage {
21+
pub protocol: Protocol,
22+
pub detail: Option<ProtocolDetail>,
23+
}

src/models/protocol.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::Message;
88
/// Details related to this are captured in a separate struct [ProtocolDetail],
99
/// and routing statistics are maintained inside various [Channel]s through the
1010
/// [ProtocolDetail::channels] field.
11-
#[derive(Debug)]
11+
#[derive(Debug, Clone)]
1212
pub struct Protocol {
1313
/// Name of this protocol instance
1414
pub name: String,

0 commit comments

Comments
 (0)