use crate::addresses::ProxyAddress;
use crate::socks6::options::{MetadataOption, SocksOption};
#[derive(Clone, Debug)]
pub struct SocksChain {
pub index: usize,
pub links: Vec<ProxyAddress>,
}
impl Default for SocksChain {
fn default() -> Self {
Self::new(0, vec![])
}
}
impl SocksChain {
pub fn new(
index: usize,
links: Vec<ProxyAddress>,
) -> Self {
Self { index, links }
}
pub fn current_link(&self) -> &ProxyAddress {
self.links.get(self.index).unwrap()
}
pub fn has_next(&self) -> bool {
self.index + 1 < self.links.len()
}
pub fn next_link(&mut self) -> Option<&ProxyAddress> {
let link = self.links.get(self.index + 1);
if link.is_some() {
self.index += 1;
}
link
}
pub fn detour(
&mut self,
links: &[ProxyAddress],
) {
let links = links.iter().cloned();
if self.links.is_empty() {
self.links.push(ProxyAddress::root());
self.links.extend(links);
} else {
let position = self.index + 1..self.index + 1;
self.links.splice(position, links);
}
}
pub fn as_options(&self) -> Vec<SocksOption> {
let mut chain_options: Vec<SocksOption> = self
.links
.iter()
.enumerate()
.map(|(i, c)| (i as u16, c.to_string()))
.map(|(i, c)| MetadataOption::new(1000 + i, c).wrap())
.collect();
chain_options.push(MetadataOption::new(998, self.index.to_string()).wrap());
chain_options.push(MetadataOption::new(999, self.links.len().to_string()).wrap());
chain_options
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_default_constructor() {
let chain = SocksChain::default();
assert_eq!(chain.index, 0);
assert_eq!(chain.links, vec![]);
}
#[test]
pub fn test_custom_constructor() {
let chain = SocksChain::new(1, vec![ProxyAddress::new(6, String::from("localhost"), 1, None)]);
assert_eq!(chain.index, 1);
assert_eq!(chain.links, vec![ProxyAddress::new(6, String::from("localhost"), 1, None)]);
}
#[test]
#[should_panic]
pub fn test_current_link_method() {
let chain = SocksChain::new(1, vec![ProxyAddress::new(6, String::from("localhost"), 1, None)]);
assert_eq!(chain.current_link(), &ProxyAddress::new(6, String::from("localhost"), 1, None));
}
#[test]
pub fn test_has_next() {
let chain = SocksChain::new(0, vec![ProxyAddress::new(6, String::from("localhost"), 1, None)]);
assert!(!chain.has_next());
}
#[test]
pub fn test_next_link() {
let mut chain = SocksChain::new(0, vec![
ProxyAddress::new(6, String::from("localhost"), 1, None),
ProxyAddress::new(6, String::from("localhost"), 2, None),
]);
assert_eq!(chain.next_link().unwrap().port, 2);
}
#[test]
pub fn test_detour_empty_chain() {
let mut chain = SocksChain::default();
chain.detour(&[ProxyAddress::new(6, String::from("localhost"), 1, None)]);
assert_eq!(chain.index, 0);
assert_eq!(chain.links[0], ProxyAddress::root());
assert_eq!(chain.links[1], ProxyAddress::new(6, String::from("localhost"), 1, None));
}
#[test]
pub fn test_detour_method() {
let mut chain = SocksChain::new(
1,
vec![
ProxyAddress::new(6, String::from("localhost"), 1, None),
ProxyAddress::new(6, String::from("localhost"), 2, None),
ProxyAddress::new(6, String::from("localhost"), 3, None),
],
);
let extra = vec![
ProxyAddress::new(6, String::from("localhost"), 4, None),
ProxyAddress::new(6, String::from("localhost"), 5, None),
];
chain.detour(&extra);
let order: Vec<u16> = chain.links.iter().map(|l| l.port).collect();
assert_eq!(order, vec![1, 2, 4, 5, 3]);
}
}