use anyhow::Error;
use fidl::endpoints::ClientEnd;
use fidl_fuchsia_testing_proxy::{TcpProxyControlMarker, TcpProxyControlProxy, TcpProxy_Marker};
use fuchsia_component::client::connect_to_protocol;
use futures::lock::Mutex;
use std::collections::HashMap;
use std::fmt::{self, Debug};
use tracing::info;
#[derive(Debug)]
pub struct ProxyFacade {
internal: Mutex<Option<ProxyFacadeInternal>>,
}
impl ProxyFacade {
pub fn new() -> Self {
Self { internal: Mutex::new(None) }
}
pub async fn open_proxy(&self, target_port: u16, proxy_port: u16) -> Result<u16, Error> {
let mut internal_lock = self.internal.lock().await;
match *internal_lock {
None => {
let mut internal = ProxyFacadeInternal::new()?;
let result = internal.open_proxy(target_port, proxy_port).await;
*internal_lock = Some(internal);
result
}
Some(ref mut internal) => internal.open_proxy(target_port, proxy_port).await,
}
}
pub async fn drop_proxy(&self, target_port: u16) {
if let Some(ref mut internal) = *self.internal.lock().await {
internal.drop_proxy(target_port);
}
}
pub async fn stop_all_proxies(&self) {
if let Some(ref mut internal) = *self.internal.lock().await {
internal.stop_all_proxies();
}
}
}
struct ProxyFacadeInternal {
proxy_control: TcpProxyControlProxy,
open_proxies: HashMap<u16, OpenProxy>,
}
struct OpenProxy {
open_port: u16,
_proxy_handle: ClientEnd<TcpProxy_Marker>,
num_users: u32,
}
impl Debug for ProxyFacadeInternal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("ProxyFacadeInternal {:?}", self.proxy_control))
}
}
impl ProxyFacadeInternal {
fn new() -> Result<Self, Error> {
info!("Launching proxy component as V2");
let proxy_control = connect_to_protocol::<TcpProxyControlMarker>()?;
Ok(Self { proxy_control, open_proxies: HashMap::new() })
}
async fn open_proxy(&mut self, target_port: u16, proxy_port: u16) -> Result<u16, Error> {
match self.open_proxies.get_mut(&target_port) {
Some(proxy) => {
proxy.num_users += 1;
Ok(proxy.open_port)
}
None => {
let (client, server) = fidl::endpoints::create_endpoints::<TcpProxy_Marker>();
let open_port =
self.proxy_control.open_proxy_(target_port, proxy_port, server).await?;
self.open_proxies.insert(
target_port,
OpenProxy { open_port, _proxy_handle: client, num_users: 1 },
);
Ok(open_port)
}
}
}
fn drop_proxy(&mut self, target_port: u16) {
if let Some(mut proxy) = self.open_proxies.remove(&target_port) {
proxy.num_users -= 1;
if proxy.num_users > 0 {
self.open_proxies.insert(target_port, proxy);
}
}
}
fn stop_all_proxies(&mut self) {
self.open_proxies.clear();
}
}