From 8e42d763fe230d4e2d5d7971e210b1e660ea1c3d Mon Sep 17 00:00:00 2001 From: Ondrej Novak Date: Sat, 6 Jun 2026 22:30:28 +0200 Subject: [PATCH] implement value listing --- Cargo.lock | 41 ++++++++++++++++++++++++++++++++++++++++ protocol/Cargo.toml | 1 + protocol/src/message.rs | 35 ++++++++++++++++++++++++++++++++++ protocol/src/protocol.rs | 37 +++++++++++++++++++++++++++--------- 4 files changed, 105 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a16482d..dee2df1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "aligned" version = "0.4.3" @@ -929,6 +938,9 @@ dependencies = [ [[package]] name = "protocol" version = "0.1.0" +dependencies = [ + "regex", +] [[package]] name = "pxfm" @@ -1081,6 +1093,35 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + [[package]] name = "rgb" version = "0.8.53" diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 321b140..2c707ab 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +regex = "1" diff --git a/protocol/src/message.rs b/protocol/src/message.rs index 1784a73..eb66083 100644 --- a/protocol/src/message.rs +++ b/protocol/src/message.rs @@ -4,6 +4,18 @@ pub fn create_request_message(value: &String) -> String { format!("GETVAL {}\n", value) } +pub fn create_list_message() -> String { + format!("LISTVAL\n") +} + +pub fn parse_list_response(lines: Vec) -> Vec { + lines + .iter() + .filter_map(|l| l.split(" ").last()) + .map(|l| l.into()) + .collect() +} + pub fn parse_response_header(header: String) -> Result { let num_values_raw = header .split(" ") @@ -118,4 +130,27 @@ mod tests { assert!(result.is_err()); assert_eq!(result, Err(ProtocolError::EmptyResponse)); } + + #[test] + fn test_parse_list_response() { + let resp = vec![ + "1780776337.692 tp-on/cpu-9/cpu-steal", + "1780776337.692 tp-on/cpu-9/cpu-system", + "1780776337.692 tp-on/cpu-9/cpu-user", + "1780776337.692 tp-on/cpu-9/cpu-wait", + ] + .iter() + .map(|s| s.to_string()) + .collect(); + let result = parse_list_response(resp); + assert_eq!( + result, + vec![ + "tp-on/cpu-9/cpu-steal", + "tp-on/cpu-9/cpu-system", + "tp-on/cpu-9/cpu-user", + "tp-on/cpu-9/cpu-wait", + ] + ); + } } diff --git a/protocol/src/protocol.rs b/protocol/src/protocol.rs index ad1ccb4..4c21d71 100644 --- a/protocol/src/protocol.rs +++ b/protocol/src/protocol.rs @@ -2,7 +2,10 @@ use std::io::{Read, Write}; use std::os::unix::net::UnixStream; use crate::err::ProtocolError; -use crate::message::{create_request_message, parse_response_header, parse_response_message}; +use crate::message::{ + create_list_message, create_request_message, parse_list_response, parse_response_header, + parse_response_message, +}; pub struct Protocol { socket: UnixStream, @@ -34,6 +37,27 @@ impl Protocol { pub fn get(&mut self, path: String, name: String) -> Result { let req = create_request_message(&path); + let lines = self.rpc(&req)?; + + if lines.len() < 1 { + Err(ProtocolError::ValueNotFound(name, vec![])) + } else { + parse_response_message(lines, name) + } + } + + pub fn list(&mut self, path_regex: &Regex) -> Result, ProtocolError> { + let req = create_list_message(); + let lines = self.rpc(&req)?; + let values = parse_list_response(lines); + + Ok(values + .into_iter() + .filter(|v| path_regex.is_match(v)) + .collect()) + } + + fn rpc(&mut self, req: &str) -> Result, ProtocolError> { let raw_req = req.as_bytes(); self.socket .write_all(raw_req) @@ -41,13 +65,8 @@ impl Protocol { let header = self.read_line()?; let num_values = parse_response_header(header)?; - if num_values < 1 { - Err(ProtocolError::ValueNotFound(name, vec![])) - } else { - let lines = (0..num_values) - .map(|_| self.read_line()) - .collect::, ProtocolError>>()?; - parse_response_message(lines, name) - } + (0..num_values) + .map(|_| self.read_line()) + .collect::, ProtocolError>>() } }