use crate::errors::{Error, Result};
use crate::Host;
use std::iter::Peekable;
use std::str::Chars;
pub struct PeersParser<'a> {
s: Peekable<Chars<'a>>,
}
impl<'a> PeersParser<'a> {
pub fn new(s: &'a str) -> Self {
PeersParser {
s: s.chars().peekable(),
}
}
pub fn parse(&mut self) -> Result<(u64, Vec<Host>)> {
let mut hosts = vec![];
let gen = self.read_generation()?;
self.expect(",")?;
let default_port = self.read_port()?;
while self.peek() == Some(&',') {
self.next_char();
hosts.append(&mut self.parse_hosts(default_port)?);
}
Ok((gen, hosts))
}
pub fn parse_hosts(&mut self, default_port: u16) -> Result<Vec<Host>> {
let mut hosts = Vec::new();
self.expect("[")?;
if self.peek_is_one_of("]") {
self.expect("]")?;
return Ok(hosts);
}
let _node_name = self.read_until(",");
self.expect(",")?;
let tls_name = self.read_until(",");
while self.peek_is_one_of(",") {
self.expect(",")?;
self.expect("[")?;
if !self.peek_is_one_of("]") {
let mut host = self.read_hosts(&tls_name, default_port)?;
hosts.append(&mut host);
}
self.expect("]")?;
}
self.expect("]")?;
Ok(hosts)
}
pub fn read_generation(&mut self) -> Result<u64> {
let gen = self.read_until(",");
if gen.is_empty() {
return Err(Error::ParsePeersError("generation not specified".into()));
}
gen.parse::<u64>()
.map_err(|_| Error::ParsePeersError(format!("expected generation but found {gen}")))
}
pub fn read_port(&mut self) -> Result<u16> {
let port = self.read_until("],");
if port.is_empty() {
return Err(Error::ParsePeersError("port not specified".into()));
}
port.parse::<u16>()
.map_err(|_| Error::ParsePeersError(format!("expected port but found {port}")))
}
pub fn read_hosts(&mut self, tls_name: &str, default_port: u16) -> Result<Vec<Host>> {
let mut hosts = Vec::new();
loop {
let (addr, port) = self.read_addr_tuple()?;
hosts.push(Host::new_tls(&addr, tls_name, port.unwrap_or(default_port)));
match self.peek() {
Some(&',') => self.expect(",")?,
_ => break,
}
}
Ok(hosts)
}
fn read_addr_tuple(&mut self) -> Result<(String, Option<u16>)> {
let addr = self.read_addr_part()?;
let port = match self.peek() {
Some(&':') => {
self.expect(":")?;
Some(self.read_port()?)
}
_ => None,
};
Ok((addr, port))
}
fn read_addr_part(&mut self) -> Result<String> {
let addr = match self.peek() {
Some(&'[') => {
self.expect("[")?;
let res = self.read_until("]");
self.expect("]")?;
res
}
_ => self.read_until(":,]"),
};
if addr.is_empty() {
return Err(Error::ParsePeersError(
"Empty address string for peer".into(),
));
}
Ok(addr)
}
pub fn read_until(&mut self, until: &str) -> String {
let mut substr = String::new();
loop {
match self.peek() {
Some(&c) if !until.contains(c) => {
substr.push(c);
self.next_char();
}
_ => {
return substr;
}
}
}
}
fn peek(&mut self) -> Option<&char> {
self.s.peek()
}
fn peek_is_one_of(&mut self, sc: &str) -> bool {
if let Some(c) = self.s.peek() {
return sc.contains(*c);
}
false
}
fn expect(&mut self, sc: &str) -> Result<()> {
if let Some(c) = self.s.next() {
if !sc.contains(c) {
return Err(Error::InvalidArgument(format!(
"Expected one of `{sc}` but found {c:?}"
)));
}
return Ok(());
}
Err(Error::InvalidArgument(format!(
"Expected one of `{sc}` but EOF"
)))
}
fn next_char(&mut self) -> Option<char> {
self.s.next()
}
}
#[cfg(test)]
mod tests {
use super::{Host, PeersParser};
#[test]
fn parse_peers() {
let (gen, hosts) = PeersParser::new("1234567,3000,[n1,t1,[192.168.4.10,192.168.3.10]],[n2,t2,[[2018::0002],[2018::0001]:4000]],[n3,t3,[foo1.aerocluster.com,foo2.aerocluster.new:3100]],[n4,t4,[foo2.aerocluster.com:5000]]")
.parse()
.expect("Error parsing peer_string");
assert_eq!(gen, 1234567);
assert_eq!(
hosts,
vec![
Host::new_tls("192.168.4.10", "t1", 3000),
Host::new_tls("192.168.3.10", "t1", 3000),
Host::new_tls("2018::0002", "t2", 3000),
Host::new_tls("2018::0001", "t2", 4000),
Host::new_tls("foo1.aerocluster.com", "t3", 3000),
Host::new_tls("foo2.aerocluster.new", "t3", 3100),
Host::new_tls("foo2.aerocluster.com", "t4", 5000),
]
);
let (gen, hosts) = PeersParser::new("12,3010,[n1,t1,[192.168.4.10,192.168.3.10:3100]],[n2,t2,[[2018::0001]]],[n3,t3,[foo1.aerocluster.com:3100]],[n4,t4,[]]")
.parse()
.expect("Error parsing peer_string");
assert_eq!(gen, 12);
assert_eq!(
hosts,
vec![
Host::new_tls("192.168.4.10", "t1", 3010),
Host::new_tls("192.168.3.10", "t1", 3100),
Host::new_tls("2018::0001", "t2", 3010),
Host::new_tls("foo1.aerocluster.com", "t3", 3100),
]
);
let (gen, hosts) = PeersParser::new(
"7,3000,[[BB924A0A129825A,,[127.0.0.1:3109]],[BB9A14D609EE096,,[127.0.0.1:3110]],[BB9A14D609EE099,t1,[127.0.0.1]]]",
)
.parse()
.expect("Error parsing peer_string");
assert_eq!(gen, 7);
assert_eq!(
hosts,
vec![
Host::new("127.0.0.1", 3109),
Host::new("127.0.0.1", 3110),
Host::new_tls("127.0.0.1", "t1", 3000)
]
);
let (gen, hosts) = PeersParser::new("0,3000,[]")
.parse()
.expect("Error parsing peer_string");
assert_eq!(gen, 0);
assert_eq!(hosts, vec![]);
}
#[test]
fn read_addr_part() {
assert_eq!(
"foo".to_string(),
PeersParser::new("foo:bar").read_addr_part().unwrap()
);
assert_eq!(
"foo".to_string(),
PeersParser::new("foo,bar").read_addr_part().unwrap()
);
assert_eq!(
"foo".to_string(),
PeersParser::new("foo").read_addr_part().unwrap()
);
assert_eq!(
"foo.com".to_string(),
PeersParser::new("foo.com").read_addr_part().unwrap()
);
assert!(PeersParser::new("").read_addr_part().is_err());
assert!(PeersParser::new(",").read_addr_part().is_err());
assert!(PeersParser::new(":").read_addr_part().is_err());
}
#[test]
fn read_addr_tuple() {
assert_eq!(
("foo".to_string(), None),
PeersParser::new("foo").read_addr_tuple().unwrap()
);
assert_eq!(
("foo".to_string(), Some(3000)),
PeersParser::new("foo:3000,").read_addr_tuple().unwrap()
);
assert_eq!(
("foo.com".to_string(), Some(3000)),
PeersParser::new("foo.com:3000,").read_addr_tuple().unwrap()
);
assert_eq!(
("::1".to_string(), Some(3000)),
PeersParser::new("[::1]:3000,").read_addr_tuple().unwrap()
);
assert!(PeersParser::new("").read_addr_tuple().is_err());
assert!(PeersParser::new(",").read_addr_tuple().is_err());
assert!(PeersParser::new(":").read_addr_tuple().is_err());
assert!(PeersParser::new("foo:").read_addr_tuple().is_err());
}
}