Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/src/bin/code/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ async fn main() -> Result<(), std::convert::Infallible> {
Some(args::TunnelSubcommand::Unregister) => tunnels::unregister(context).await,
Some(args::TunnelSubcommand::Kill) => tunnels::kill(context).await,
Some(args::TunnelSubcommand::Restart) => tunnels::restart(context).await,
Some(args::TunnelSubcommand::Status) => tunnels::status(context).await,
Some(args::TunnelSubcommand::Rename(rename_args)) => {
tunnels::rename(context, rename_args).await
}
Expand Down
3 changes: 3 additions & 0 deletions cli/src/commands/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,9 @@ pub enum TunnelSubcommand {
/// Restarts any running tunnel on the system.
Restart,

/// Gets whether there is a tunnel running on the current machineiou.
Status,

/// Rename the name of this machine associated with port forwarding service.
Rename(TunnelRenameArgs),

Expand Down
54 changes: 31 additions & 23 deletions cli/src/commands/tunnels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,19 @@ pub async fn unregister(ctx: CommandContext) -> Result<i32, AnyError> {
Ok(0)
}

async fn do_single_rpc_call(
ctx: CommandContext,
async fn do_single_rpc_call<
P: serde::Serialize,
R: serde::de::DeserializeOwned + Send + 'static,
>(
ctx: &CommandContext,
method: &'static str,
params: impl serde::Serialize,
) -> Result<i32, AnyError> {
params: P,
) -> Result<R, AnyError> {
let client = match connect_as_client(&ctx.paths.tunnel_lockfile()).await {
Ok(p) => p,
Err(CodeError::SingletonLockfileOpenFailed(_))
| Err(CodeError::SingletonLockedProcessExited(_)) => {
error!(ctx.log, "No tunnel is running");
return Ok(1);
return Err(CodeError::NoRunningTunnel.into());
}
Err(e) => return Err(e.into()),
};
Expand All @@ -236,33 +238,42 @@ async fn do_single_rpc_call(
.unwrap();
});

let r = caller.call::<_, _, ()>(method, params).await.unwrap();
let r = caller.call(method, params).await.unwrap();
rpc.abort();

if let Err(r) = r {
error!(ctx.log, "RPC call failed: {:?}", r);
return Ok(1);
}

Ok(0)
r.map_err(|err| CodeError::TunnelRpcCallFailed(err).into())
}

pub async fn restart(ctx: CommandContext) -> Result<i32, AnyError> {
do_single_rpc_call(
ctx,
do_single_rpc_call::<_, ()>(
&ctx,
protocol::singleton::METHOD_RESTART,
protocol::EmptyObject {},
)
.await
.map(|_| 0)
}

pub async fn kill(ctx: CommandContext) -> Result<i32, AnyError> {
do_single_rpc_call(
ctx,
do_single_rpc_call::<_, ()>(
&ctx,
protocol::singleton::METHOD_SHUTDOWN,
protocol::EmptyObject {},
)
.await
.map(|_| 0)
}

pub async fn status(ctx: CommandContext) -> Result<i32, AnyError> {
let status: protocol::singleton::Status = do_single_rpc_call(
&ctx,
protocol::singleton::METHOD_STATUS,
protocol::EmptyObject {},
)
.await?;

ctx.log.result(serde_json::to_string(&status).unwrap());

Ok(0)
}

/// Removes unused servers.
Expand Down Expand Up @@ -377,11 +388,8 @@ async fn serve_with_csa(
let tunnel = if let Some(d) = gateway_args.tunnel.clone().into() {
dt.start_existing_tunnel(d).await
} else {
dt.start_new_launcher_tunnel(
gateway_args.name.as_deref(),
gateway_args.random_name,
)
.await
dt.start_new_launcher_tunnel(gateway_args.name.as_deref(), gateway_args.random_name)
.await
}?;

csa.connection_token = Some(get_connection_token(&tunnel));
Expand Down
6 changes: 6 additions & 0 deletions cli/src/tunnels/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ pub mod singleton {

pub const METHOD_RESTART: &str = "restart";
pub const METHOD_SHUTDOWN: &str = "shutdown";
pub const METHOD_STATUS: &str = "status";
pub const METHOD_LOG: &str = "log";

#[derive(Serialize)]
Expand All @@ -179,4 +180,9 @@ pub mod singleton {
pub prefix: String,
pub message: String,
}

#[derive(Serialize, Deserialize)]
pub struct Status {
pub ok: bool,
}
}
7 changes: 7 additions & 0 deletions cli/src/tunnels/singleton_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ pub fn make_singleton_server(
},
);

rpc.register_sync(
protocol::singleton::METHOD_STATUS,
|_: protocol::EmptyObject, _| {
Ok(protocol::singleton::Status { ok: true }) // mostly placeholder
},
);

rpc.register_sync(
protocol::singleton::METHOD_SHUTDOWN,
|_: protocol::EmptyObject, ctx| {
Expand Down
18 changes: 11 additions & 7 deletions cli/src/util/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
use crate::constants::{
use crate::{constants::{
APPLICATION_NAME, CONTROL_PORT, DOCUMENTATION_URL, QUALITYLESS_PRODUCT_NAME,
};
}, rpc::ResponseError};
use std::fmt::Display;
use thiserror::Error;

Expand Down Expand Up @@ -479,16 +479,20 @@ macro_rules! makeAnyError {
/// Note: other error should be migrated to this type gradually
#[derive(Error, Debug)]
pub enum CodeError {
#[error("could not connect to socket/pipe")]
#[error("could not connect to socket/pipe: {0:?}")]
AsyncPipeFailed(std::io::Error),
#[error("could not listen on socket/pipe")]
#[error("could not listen on socket/pipe: {0:?}")]
AsyncPipeListenerFailed(std::io::Error),
#[error("could not create singleton lock file")]
#[error("could not create singleton lock file: {0:?}")]
SingletonLockfileOpenFailed(std::io::Error),
#[error("could not read singleton lock file")]
#[error("could not read singleton lock file: {0:?}")]
SingletonLockfileReadFailed(rmp_serde::decode::Error),
#[error("the process holding the singleton lock file exited")]
#[error("the process holding the singleton lock file (pid={0}) exited")]
SingletonLockedProcessExited(u32),
#[error("no tunnel process is currently running")]
NoRunningTunnel,
#[error("rpc call failed: {0:?}")]
TunnelRpcCallFailed(ResponseError),
}

makeAnyError!(
Expand Down