Skip to content

Commit d0d9701

Browse files
authored
cli: publish availability of wsl on tunnel tags (microsoft#186016)
I plan to use this in the explorer to add a 'connect to wsl' button on relevant tunnels
1 parent e64712a commit d0d9701

File tree

3 files changed

+98
-16
lines changed

3 files changed

+98
-16
lines changed

cli/src/tunnels.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod shutdown_signal;
1212
pub mod singleton_client;
1313
pub mod singleton_server;
1414

15+
mod wsl_detect;
1516
mod challenge;
1617
mod control_server;
1718
mod nosleep;

cli/src/tunnels/dev_tunnels.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55
use crate::auth;
66
use crate::constants::{
7-
CONTROL_PORT, IS_INTERACTIVE_CLI, PROTOCOL_VERSION_TAG, PROTOCOL_VERSION_TAG_PREFIX,
8-
TUNNEL_SERVICE_USER_AGENT,
7+
CONTROL_PORT, IS_INTERACTIVE_CLI, PROTOCOL_VERSION_TAG, TUNNEL_SERVICE_USER_AGENT,
98
};
109
use crate::state::{LauncherPaths, PersistedState};
1110
use crate::util::errors::{
@@ -32,6 +31,8 @@ use tunnels::management::{
3231
NO_REQUEST_OPTIONS,
3332
};
3433

34+
use super::wsl_detect::is_wsl_installed;
35+
3536
#[derive(Clone, Serialize, Deserialize)]
3637
pub struct PersistedTunnel {
3738
pub name: String,
@@ -304,7 +305,7 @@ impl DevTunnels {
304305
return Ok((full_tunnel, persisted));
305306
}
306307

307-
full_tunnel.tags = vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()];
308+
full_tunnel.tags = self.get_tags(&name);
308309

309310
let new_tunnel = spanf!(
310311
self.log,
@@ -383,11 +384,9 @@ impl DevTunnels {
383384
}
384385
};
385386

386-
if !tunnel.tags.iter().any(|t| t == PROTOCOL_VERSION_TAG) {
387-
tunnel = self
388-
.update_protocol_version_tag(tunnel, &HOST_TUNNEL_REQUEST_OPTIONS)
389-
.await?;
390-
}
387+
tunnel = self
388+
.sync_tunnel_tags(&persisted.name, tunnel, &HOST_TUNNEL_REQUEST_OPTIONS)
389+
.await?;
391390

392391
let locator = TunnelLocator::try_from(&tunnel).unwrap();
393392
let host_token = get_host_token_from_tunnel(&tunnel);
@@ -504,23 +503,40 @@ impl DevTunnels {
504503
}
505504
}
506505

506+
/// Gets the expected tunnel tags
507+
fn get_tags(&self, name: &str) -> Vec<String> {
508+
let mut tags = vec![
509+
name.to_string(),
510+
PROTOCOL_VERSION_TAG.to_string(),
511+
VSCODE_CLI_TUNNEL_TAG.to_string(),
512+
];
513+
514+
if is_wsl_installed(&self.log) {
515+
tags.push("_wsl".to_string())
516+
}
517+
518+
tags
519+
}
520+
507521
/// Ensures the tunnel contains a tag for the current PROTCOL_VERSION, and no
508522
/// other version tags.
509-
async fn update_protocol_version_tag(
523+
async fn sync_tunnel_tags(
510524
&self,
525+
name: &str,
511526
tunnel: Tunnel,
512527
options: &TunnelRequestOptions,
513528
) -> Result<Tunnel, AnyError> {
529+
let new_tags = self.get_tags(name);
530+
if vec_eq_unsorted(&tunnel.tags, &new_tags) {
531+
return Ok(tunnel);
532+
}
533+
514534
debug!(
515535
self.log,
516-
"Updating tunnel protocol version tag to {}", PROTOCOL_VERSION_TAG
536+
"Updating tunnel tags {} -> {}",
537+
tunnel.tags.join(", "),
538+
new_tags.join(", ")
517539
);
518-
let mut new_tags: Vec<String> = tunnel
519-
.tags
520-
.into_iter()
521-
.filter(|t| !t.starts_with(PROTOCOL_VERSION_TAG_PREFIX))
522-
.collect();
523-
new_tags.push(PROTOCOL_VERSION_TAG.to_string());
524540

525541
let tunnel_update = Tunnel {
526542
tags: new_tags,
@@ -982,6 +998,20 @@ fn clean_hostname_for_tunnel(hostname: &str) -> String {
982998
}
983999
}
9841000

1001+
fn vec_eq_unsorted(a: &[String], b: &[String]) -> bool {
1002+
if a.len() != b.len() {
1003+
return false;
1004+
}
1005+
1006+
for item in a {
1007+
if !b.contains(item) {
1008+
return false;
1009+
}
1010+
}
1011+
1012+
true
1013+
}
1014+
9851015
#[cfg(test)]
9861016
mod test {
9871017
use super::*;

cli/src/tunnels/wsl_detect.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
use crate::log;
7+
8+
#[cfg(not(windows))]
9+
pub fn is_wsl_installed(_log: &log::Logger) -> bool {
10+
false
11+
}
12+
13+
#[cfg(windows)]
14+
pub fn is_wsl_installed(log: &log::Logger) -> bool {
15+
use std::{path::PathBuf, process::Command};
16+
17+
let system32 = {
18+
let sys_root = match std::env::var("SystemRoot") {
19+
Ok(s) => s,
20+
Err(_) => return false,
21+
};
22+
23+
let is_32_on_64 = std::env::var("PROCESSOR_ARCHITEW6432").is_ok();
24+
let mut system32 = PathBuf::from(sys_root);
25+
system32.push(if is_32_on_64 { "Sysnative" } else { "System32" });
26+
system32
27+
};
28+
29+
// Windows builds < 22000
30+
let mut maybe_lxss = system32.join("lxss");
31+
maybe_lxss.push("LxssManager.dll");
32+
if maybe_lxss.exists() {
33+
trace!(log, "wsl availability detected via lxss");
34+
return true;
35+
}
36+
37+
// Windows builds >= 22000
38+
let maybe_wsl = system32.join("wsl.exe");
39+
if maybe_wsl.exists() {
40+
if let Ok(s) = Command::new(maybe_wsl).arg("--status").output() {
41+
if s.status.success() {
42+
trace!(log, "wsl availability detected via subprocess");
43+
return true;
44+
}
45+
}
46+
}
47+
48+
trace!(log, "wsl not detected");
49+
50+
false
51+
}

0 commit comments

Comments
 (0)