-
Notifications
You must be signed in to change notification settings - Fork 457
Description
Describe the feature
When wstunnel is used as a library and a tunnel fails, the user should get a Response::Err rather than a Response::Ok.
Describe the reason for such feature
- ergonomics
- being able to retry with slightly different connection parameters on failure
Currently wstunnel calls tracing::error! on most errors and then swallows the error rather than returning them to the original caller.
Describe alternatives you've considered
diff --git a/src/lib.rs b/src/lib.rs
index e05fa16..3201a88 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,25 +38,19 @@ use tokio::task::JoinSet;
use tracing::{error, info};
use url::Url;
-pub async fn run_client(args: Client, executor: impl TokioExecutor) -> anyhow::Result<()> {
- let tunnels = create_client_tunnels(args, executor.clone()).await?;
-
- // Start all tunnels
- let (tx, rx) = oneshot::channel();
- executor.spawn(async move {
- let _ = JoinSet::from_iter(tunnels).join_all().await;
- let _ = tx.send(());
- });
+pub async fn run_client(args: Client, executor: impl TokioExecutor) -> Vec<anyhow::Result<()>> {
+ let tunnels = match create_client_tunnels(args, executor.clone()).await {
+ Ok(tunnels) => tunnels,
+ Err(err) => return vec![Err(err)], // FIXME: this is probably unacceptable
+ };
- // wait for all tunnels to finish
- rx.await?;
- Ok(())
+ JoinSet::from_iter(tunnels).join_all().await
}
async fn create_client_tunnels(
args: Client,
executor: impl TokioExecutor,
-) -> anyhow::Result<Vec<BoxFuture<'static, ()>>> {
+) -> anyhow::Result<Vec<BoxFuture<'static, anyhow::Result<()>>>> {
let (tls_certificate, tls_key) = if let (Some(cert), Some(key)) =
(args.tls_certificate.as_ref(), args.tls_private_key.as_ref())
{
@@ -159,7 +153,8 @@ async fn create_client_tunnels(
info!("Starting wstunnel client v{}", env!("CARGO_PKG_VERSION"),);
// Keep track of all spawned tunnels
- let mut tunnels: Vec<BoxFuture<()>> = Vec::with_capacity(args.remote_to_local.len() + args.local_to_remote.len());
+ let mut tunnels: Vec<BoxFuture<anyhow::Result<()>>> =
+ Vec::with_capacity(args.remote_to_local.len() + args.local_to_remote.len());
macro_rules! spawn_tunnel {
( $($s:stmt);* ) => {
tunnels.push(Box::pin(async move {
@@ -188,9 +183,7 @@ async fn create_client_tunnels(
host,
port,
};
- if let Err(err) = client.run_reverse_tunnel(remote, tcp_connector).await {
- error!("{:?}", err);
- }
+ client.run_reverse_tunnel(remote, tcp_connector).await
}
}
and so on.
A similar "print an swallow the error pattern is at https://github.com/erebe/wstunnel/blob/main/src/tunnel/client/client.rs#L127C54-L127C56
but I haven't quite figured out how to fix it yet, because of the spawn. But unlike the leak (#433), I'm fairly confident I can figure it out.
This task would likely be easier if wstunnel exported a "create a single tunnel" API. We create multiple wstunnel's with a single tunnel in each instantiation. Would you like a MR that created such an API?
I'm again willing to do the work here. And I am more confident on doing so than I was with the socket leak! However, some guidance on how you'd like the API to look would be appreciated.
Thanks.