mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
cli: add service integration for systemd (#166328)
systemd, like most 'modern' linux components, has a nice dbus API. This uses that API to register the tunnel as a service of the calling user. The dbus dependency is temporarily duplicated, until secret-service 3 is released, where they update to the latest version (should be a week or two). For https://github.com/microsoft/vscode-cli/issues/367. Next up, macOS, then it's done :)
This commit is contained in:
parent
eab3273162
commit
c47751948c
|
@ -42,6 +42,9 @@ const setLauncherEnvironmentVars = () => {
|
|||
['VSCODE_CLI_VERSION', packageJson.version],
|
||||
['VSCODE_CLI_UPDATE_ENDPOINT', product.updateUrl],
|
||||
['VSCODE_CLI_QUALITY', product.quality],
|
||||
['VSCODE_CLI_NAME_SHORT', product.nameShort],
|
||||
['VSCODE_CLI_NAME_LONG', product.nameLong],
|
||||
['VSCODE_CLI_APPLICATION_NAME', product.applicationName],
|
||||
['VSCODE_CLI_COMMIT', commit],
|
||||
[
|
||||
'VSCODE_CLI_WIN32_APP_IDS',
|
||||
|
|
|
@ -46,6 +46,9 @@ const setLauncherEnvironmentVars = () => {
|
|||
['VSCODE_CLI_VERSION', packageJson.version],
|
||||
['VSCODE_CLI_UPDATE_ENDPOINT', product.updateUrl],
|
||||
['VSCODE_CLI_QUALITY', product.quality],
|
||||
['VSCODE_CLI_NAME_SHORT', product.nameShort],
|
||||
['VSCODE_CLI_NAME_LONG', product.nameLong],
|
||||
['VSCODE_CLI_APPLICATION_NAME', product.applicationName],
|
||||
['VSCODE_CLI_COMMIT', commit],
|
||||
[
|
||||
'VSCODE_CLI_WIN32_APP_IDS',
|
||||
|
|
248
cli/Cargo.lock
generated
248
cli/Cargo.lock
generated
|
@ -26,6 +26,17 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.9.0"
|
||||
|
@ -47,10 +58,21 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.57"
|
||||
name = "async-recursion"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||
checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -241,6 +263,7 @@ dependencies = [
|
|||
"uuid",
|
||||
"windows-service",
|
||||
"winreg",
|
||||
"zbus 3.4.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
|
@ -503,7 +526,17 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"enumflags2_derive 0.6.4",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
|
||||
dependencies = [
|
||||
"enumflags2_derive 0.7.4",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -518,6 +551,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "err-derive"
|
||||
version = "0.3.1"
|
||||
|
@ -532,6 +576,12 @@ dependencies = [
|
|||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
|
@ -610,9 +660,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
@ -620,9 +670,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
|
@ -637,9 +687,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
|
@ -658,9 +708,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -669,21 +719,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -779,6 +829,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.3.4"
|
||||
|
@ -1102,6 +1158,20 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.7"
|
||||
|
@ -1362,6 +1432,16 @@ dependencies = [
|
|||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "034ce384018b245e8d8424bbe90577fbd91a533be74107e465e3474eb2285eef"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
|
@ -1830,10 +1910,10 @@ dependencies = [
|
|||
"openssl",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"zbus",
|
||||
"zbus_macros",
|
||||
"zvariant",
|
||||
"zvariant_derive",
|
||||
"zbus 1.9.3",
|
||||
"zbus_macros 1.9.3",
|
||||
"zvariant 2.10.0",
|
||||
"zvariant_derive 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2009,9 +2089,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2245,9 +2325,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
|
@ -2312,6 +2404,16 @@ version = "1.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.8"
|
||||
|
@ -2632,18 +2734,54 @@ dependencies = [
|
|||
"async-io",
|
||||
"byteorder",
|
||||
"derivative",
|
||||
"enumflags2",
|
||||
"enumflags2 0.6.4",
|
||||
"fastrand",
|
||||
"futures",
|
||||
"nb-connect",
|
||||
"nix",
|
||||
"nix 0.22.3",
|
||||
"once_cell",
|
||||
"polling",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"zbus_macros",
|
||||
"zvariant",
|
||||
"zbus_macros 1.9.3",
|
||||
"zvariant 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78a0b85c5608c27d2306d67e955b9c6e23a42d824205c85038a7afbe19c0ae22"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"derivative",
|
||||
"dirs 4.0.0",
|
||||
"enumflags2 0.7.5",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"nix 0.25.0",
|
||||
"once_cell",
|
||||
"ordered-stream",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"sha1",
|
||||
"static_assertions",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"winapi",
|
||||
"zbus_macros 3.4.0",
|
||||
"zbus_names",
|
||||
"zvariant 3.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2658,6 +2796,30 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b18018648e7e10ed856809befe7309002b87b2b12d5b282cb5040d7974b58677"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.2.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zvariant 3.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.3.0"
|
||||
|
@ -2684,11 +2846,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"enumflags2",
|
||||
"enumflags2 0.6.4",
|
||||
"libc",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zvariant_derive",
|
||||
"zvariant_derive 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "3.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b794fb7f59af4105697b0449ba31731ee5dbb3e773a17dbdf3d36206ea1b1644"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"enumflags2 0.7.5",
|
||||
"libc",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zvariant_derive 3.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2702,3 +2878,15 @@ dependencies = [
|
|||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "3.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd58d4b6c8e26d3dd2149c8c40c6613ef6451b9885ff1296d1ac86c388351a54"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.2.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -53,6 +53,7 @@ winreg = "0.10"
|
|||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
tar = { version = "0.4" }
|
||||
zbus = { version = "3.4", default-features = false, features = ["tokio"] }
|
||||
|
||||
[patch.crates-io]
|
||||
russh = { git = "https://github.com/microsoft/vscode-russh", branch = "main" }
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::str::FromStr;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use sysinfo::{Pid, SystemExt};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
@ -112,37 +112,45 @@ pub async fn service(
|
|||
ctx: CommandContext,
|
||||
service_args: TunnelServiceSubCommands,
|
||||
) -> Result<i32, AnyError> {
|
||||
let manager = create_service_manager(ctx.log.clone());
|
||||
let manager = create_service_manager(ctx.log.clone(), &ctx.paths);
|
||||
match service_args {
|
||||
TunnelServiceSubCommands::Install => {
|
||||
// ensure logged in, otherwise subsequent serving will fail
|
||||
println!("authing");
|
||||
Auth::new(&ctx.paths, ctx.log.clone())
|
||||
.get_credential()
|
||||
.await?;
|
||||
|
||||
// likewise for license consent
|
||||
println!("consent");
|
||||
legal::require_consent(&ctx.paths, false)?;
|
||||
|
||||
let current_exe =
|
||||
std::env::current_exe().map_err(|e| wrap(e, "could not get current exe"))?;
|
||||
|
||||
manager.register(
|
||||
current_exe,
|
||||
&[
|
||||
"--cli-data-dir",
|
||||
ctx.paths.root().as_os_str().to_string_lossy().as_ref(),
|
||||
"tunnel",
|
||||
"service",
|
||||
"internal-run",
|
||||
],
|
||||
)?;
|
||||
println!("calling register");
|
||||
manager
|
||||
.register(
|
||||
current_exe,
|
||||
&[
|
||||
"--verbose",
|
||||
"--cli-data-dir",
|
||||
ctx.paths.root().as_os_str().to_string_lossy().as_ref(),
|
||||
"tunnel",
|
||||
"service",
|
||||
"internal-run",
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
ctx.log.result("Service successfully installed! You can use `code tunnel service log` to monitor it, and `code tunnel service uninstall` to remove it.");
|
||||
}
|
||||
TunnelServiceSubCommands::Uninstall => {
|
||||
manager.unregister()?;
|
||||
manager.unregister().await?;
|
||||
}
|
||||
TunnelServiceSubCommands::InternalRun => {
|
||||
manager.run(ctx.paths.clone(), TunnelServiceContainer::new(ctx.args))?;
|
||||
manager
|
||||
.run(ctx.paths.clone(), TunnelServiceContainer::new(ctx.args))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,12 @@ pub const VSCODE_CLI_UPDATE_ENDPOINT: Option<&'static str> =
|
|||
|
||||
pub const TUNNEL_SERVICE_USER_AGENT_ENV_VAR: &str = "TUNNEL_SERVICE_USER_AGENT";
|
||||
|
||||
const MAYBE_APPLICATION_NAME: Option<&'static str> = option_env!("VSCODE_CLI_APPLICATION_NAME");
|
||||
const MAYBE_PRODUCT_NAME_LONG: Option<&'static str> = option_env!("VSCODE_CLI_NAME_LONG");
|
||||
// JSON map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}`
|
||||
const VSCODE_CLI_WIN32_APP_IDS: Option<&'static str> = option_env!("VSCODE_CLI_WIN32_APP_IDS");
|
||||
const MAYBE_CLI_WIN32_APP_IDS: Option<&'static str> = option_env!("VSCODE_CLI_WIN32_APP_IDS");
|
||||
// JSON map of quality names to download URIs
|
||||
const VSCODE_CLI_QUALITY_DOWNLOAD_URIS: Option<&'static str> =
|
||||
const MAYBE_CLI_QUALITY_DOWNLOAD_URIS: Option<&'static str> =
|
||||
option_env!("VSCODE_CLI_QUALITY_DOWNLOAD_URIS");
|
||||
|
||||
pub fn get_default_user_agent() -> String {
|
||||
|
@ -48,7 +50,10 @@ lazy_static! {
|
|||
_ => get_default_user_agent(),
|
||||
};
|
||||
pub static ref WIN32_APP_IDS: Option<HashMap<Quality, Vec<String>>> =
|
||||
VSCODE_CLI_WIN32_APP_IDS.and_then(|s| serde_json::from_str(s).unwrap());
|
||||
MAYBE_CLI_WIN32_APP_IDS.and_then(|s| serde_json::from_str(s).unwrap());
|
||||
pub static ref QUALITY_DOWNLOAD_URIS: Option<HashMap<Quality, String>> =
|
||||
VSCODE_CLI_QUALITY_DOWNLOAD_URIS.and_then(|s| serde_json::from_str(s).unwrap());
|
||||
MAYBE_CLI_QUALITY_DOWNLOAD_URIS.and_then(|s| serde_json::from_str(s).unwrap());
|
||||
pub static ref PRODUCT_NAME_LONG: &'static str =
|
||||
MAYBE_PRODUCT_NAME_LONG.unwrap_or("Code - OSS");
|
||||
pub static ref APPLICATION_NAME: &'static str = MAYBE_APPLICATION_NAME.unwrap_or("code");
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ mod protocol;
|
|||
#[cfg_attr(windows, path = "tunnels/server_bridge_windows.rs")]
|
||||
mod server_bridge;
|
||||
mod service;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod service_linux;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod service_windows;
|
||||
|
||||
|
|
|
@ -25,58 +25,75 @@ pub trait ServiceContainer: Send {
|
|||
) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ServiceManager {
|
||||
/// Registers the current executable as a service to run with the given set
|
||||
/// of arguments.
|
||||
fn register(&self, exe: PathBuf, args: &[&str]) -> Result<(), AnyError>;
|
||||
async fn register(&self, exe: PathBuf, args: &[&str]) -> Result<(), AnyError>;
|
||||
|
||||
/// Runs the service using the given handle. The executable *must not* take
|
||||
/// any action which may fail prior to calling this to ensure service
|
||||
/// states may update.
|
||||
fn run(
|
||||
&self,
|
||||
async fn run(
|
||||
self,
|
||||
launcher_paths: LauncherPaths,
|
||||
handle: impl 'static + ServiceContainer,
|
||||
) -> Result<(), AnyError>;
|
||||
|
||||
/// Unregisters the current executable as a service.
|
||||
fn unregister(&self) -> Result<(), AnyError>;
|
||||
async fn unregister(&self) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub type ServiceManagerImpl = super::service_windows::WindowsService;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub type ServiceManagerImpl = super::service_linux::SystemdService;
|
||||
|
||||
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
|
||||
pub type ServiceManagerImpl = UnimplementedServiceManager;
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub fn create_service_manager(log: log::Logger) -> ServiceManagerImpl {
|
||||
ServiceManagerImpl::new(log)
|
||||
#[allow(unused_variables)]
|
||||
pub fn create_service_manager(log: log::Logger, paths: &LauncherPaths) -> ServiceManagerImpl {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
super::service_windows::WindowsService::new(log)
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
super::service_linux::SystemdService::new(log, paths.clone())
|
||||
}
|
||||
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
|
||||
{
|
||||
UnimplementedServiceManager::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UnimplementedServiceManager();
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl UnimplementedServiceManager {
|
||||
fn new(_log: log::Logger) -> Self {
|
||||
fn new() -> Self {
|
||||
Self()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ServiceManager for UnimplementedServiceManager {
|
||||
fn register(&self, _exe: PathBuf, _args: &[&str]) -> Result<(), AnyError> {
|
||||
async fn register(&self, _exe: PathBuf, _args: &[&str]) -> Result<(), AnyError> {
|
||||
unimplemented!("Service management is not supported on this platform");
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
async fn run(
|
||||
self,
|
||||
_launcher_paths: LauncherPaths,
|
||||
_handle: impl 'static + ServiceContainer,
|
||||
) -> Result<(), AnyError> {
|
||||
unimplemented!("Service management is not supported on this platform");
|
||||
}
|
||||
|
||||
fn unregister(&self) -> Result<(), AnyError> {
|
||||
async fn unregister(&self) -> Result<(), AnyError> {
|
||||
unimplemented!("Service management is not supported on this platform");
|
||||
}
|
||||
}
|
||||
|
|
211
cli/src/tunnels/service_linux.rs
Normal file
211
cli/src/tunnels/service_linux.rs
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use tokio::sync::mpsc;
|
||||
use zbus::{dbus_proxy, zvariant, Connection};
|
||||
|
||||
use crate::{
|
||||
commands::tunnels::ShutdownSignal,
|
||||
constants::{APPLICATION_NAME, PRODUCT_NAME_LONG},
|
||||
log,
|
||||
state::LauncherPaths,
|
||||
util::errors::{wrap, AnyError},
|
||||
};
|
||||
|
||||
use super::ServiceManager;
|
||||
|
||||
pub struct SystemdService {
|
||||
log: log::Logger,
|
||||
service_file: PathBuf,
|
||||
}
|
||||
|
||||
impl SystemdService {
|
||||
pub fn new(log: log::Logger, paths: LauncherPaths) -> Self {
|
||||
Self {
|
||||
log,
|
||||
service_file: paths.root().join(SystemdService::service_name_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemdService {
|
||||
async fn connect() -> Result<Connection, AnyError> {
|
||||
let connection = Connection::session()
|
||||
.await
|
||||
.map_err(|e| wrap(e, "error creating dbus session"))?;
|
||||
Ok(connection)
|
||||
}
|
||||
|
||||
async fn proxy(connection: &Connection) -> Result<SystemdManagerDbusProxy<'_>, AnyError> {
|
||||
let proxy = SystemdManagerDbusProxy::new(connection)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
wrap(
|
||||
e,
|
||||
"error connecting to systemd, you may need to re-run with sudo:",
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(proxy)
|
||||
}
|
||||
|
||||
fn service_path_string(&self) -> String {
|
||||
self.service_file.as_os_str().to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn service_name_string() -> String {
|
||||
format!("{}-tunnel.service", &*APPLICATION_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ServiceManager for SystemdService {
|
||||
async fn register(
|
||||
&self,
|
||||
exe: std::path::PathBuf,
|
||||
args: &[&str],
|
||||
) -> Result<(), crate::util::errors::AnyError> {
|
||||
let connection = SystemdService::connect().await?;
|
||||
let proxy = SystemdService::proxy(&connection).await?;
|
||||
|
||||
write_systemd_service_file(&self.service_file, exe, args)
|
||||
.map_err(|e| wrap(e, "error creating service file"))?;
|
||||
|
||||
proxy
|
||||
.link_unit_files(
|
||||
vec![self.service_path_string()],
|
||||
/* 'runtime only'= */ false,
|
||||
/* replace existing = */ true,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| wrap(e, "error registering service"))?;
|
||||
|
||||
info!(self.log, "Successfully registered service...");
|
||||
|
||||
proxy
|
||||
.start_unit(SystemdService::service_name_string(), "replace".to_string())
|
||||
.await
|
||||
.map_err(|e| wrap(e, "error starting service"))?;
|
||||
|
||||
info!(self.log, "Tunnel service successfully started");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self,
|
||||
launcher_paths: crate::state::LauncherPaths,
|
||||
mut handle: impl 'static + super::ServiceContainer,
|
||||
) -> Result<(), crate::util::errors::AnyError> {
|
||||
let (tx, rx) = mpsc::channel::<ShutdownSignal>(1);
|
||||
tokio::spawn(async move {
|
||||
tokio::signal::ctrl_c().await.ok();
|
||||
tx.send(ShutdownSignal::CtrlC).await.ok();
|
||||
});
|
||||
|
||||
handle.run_service(self.log, launcher_paths, rx).await
|
||||
}
|
||||
|
||||
async fn unregister(&self) -> Result<(), crate::util::errors::AnyError> {
|
||||
let connection = SystemdService::connect().await?;
|
||||
let proxy = SystemdService::proxy(&connection).await?;
|
||||
|
||||
proxy
|
||||
.stop_unit(SystemdService::service_name_string(), "replace".to_string())
|
||||
.await
|
||||
.map_err(|e| wrap(e, "error unregistering service"))?;
|
||||
|
||||
info!(self.log, "Successfully stopped service...");
|
||||
|
||||
proxy
|
||||
.disable_unit_files(
|
||||
vec![SystemdService::service_name_string()],
|
||||
/* 'runtime only'= */ false,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| wrap(e, "error unregistering service"))?;
|
||||
|
||||
info!(self.log, "Tunnel service uninstalled");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_systemd_service_file(
|
||||
path: &PathBuf,
|
||||
exe: std::path::PathBuf,
|
||||
args: &[&str],
|
||||
) -> io::Result<()> {
|
||||
let mut f = File::create(path)?;
|
||||
write!(
|
||||
&mut f,
|
||||
"[Unit]\n\
|
||||
Description={} Tunnel\n\
|
||||
After=network.target\n\
|
||||
StartLimitIntervalSec=0\n\
|
||||
\n\
|
||||
[Service]\n\
|
||||
Type=simple\n\
|
||||
Restart=always\n\
|
||||
RestartSec=10\n\
|
||||
ExecStart={} \"{}\"\n\
|
||||
\n\
|
||||
[Install]\n\
|
||||
WantedBy=multi-user.target\n\
|
||||
",
|
||||
&*PRODUCT_NAME_LONG,
|
||||
exe.into_os_string().to_string_lossy(),
|
||||
args.join("\" \"")
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Minimal implementation of systemd types for the services we need. The full
|
||||
/// definition can be found on any systemd machine with the command:
|
||||
///
|
||||
/// gdbus introspect --system --dest org.freedesktop.systemd1 --object-path /org/freedesktop/systemd1
|
||||
///
|
||||
/// See docs here: https://www.freedesktop.org/software/systemd/man/org.freedesktop.systemd1.html
|
||||
#[dbus_proxy(
|
||||
interface = "org.freedesktop.systemd1.Manager",
|
||||
gen_blocking = false,
|
||||
default_service = "org.freedesktop.systemd1",
|
||||
default_path = "/org/freedesktop/systemd1"
|
||||
)]
|
||||
trait SystemdManagerDbus {
|
||||
#[dbus_proxy(name = "EnableUnitFiles")]
|
||||
fn enable_unit_files(
|
||||
&self,
|
||||
files: Vec<String>,
|
||||
runtime: bool,
|
||||
force: bool,
|
||||
) -> zbus::Result<(bool, Vec<(String, String, String)>)>;
|
||||
|
||||
fn link_unit_files(
|
||||
&self,
|
||||
files: Vec<String>,
|
||||
runtime: bool,
|
||||
force: bool,
|
||||
) -> zbus::Result<Vec<(String, String, String)>>;
|
||||
|
||||
fn disable_unit_files(
|
||||
&self,
|
||||
files: Vec<String>,
|
||||
runtime: bool,
|
||||
) -> zbus::Result<Vec<(String, String, String)>>;
|
||||
|
||||
#[dbus_proxy(name = "StartUnit")]
|
||||
fn start_unit(&self, name: String, mode: String) -> zbus::Result<zvariant::OwnedObjectPath>;
|
||||
|
||||
#[dbus_proxy(name = "StopUnit")]
|
||||
fn stop_unit(&self, name: String, mode: String) -> zbus::Result<zvariant::OwnedObjectPath>;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
use async_trait::async_trait;
|
||||
use dialoguer::{theme::ColorfulTheme, Input, Password};
|
||||
use lazy_static::lazy_static;
|
||||
use std::{ffi::OsString, sync::Mutex, thread, time::Duration};
|
||||
|
@ -44,8 +45,9 @@ impl WindowsService {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CliServiceManager for WindowsService {
|
||||
fn register(&self, exe: std::path::PathBuf, args: &[&str]) -> Result<(), AnyError> {
|
||||
async fn register(&self, exe: std::path::PathBuf, args: &[&str]) -> Result<(), AnyError> {
|
||||
let service_manager = ServiceManager::local_computer(
|
||||
None::<&str>,
|
||||
ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE,
|
||||
|
@ -118,8 +120,8 @@ impl CliServiceManager for WindowsService {
|
|||
}
|
||||
|
||||
#[allow(unused_must_use)] // triggers incorrectly on `define_windows_service!`
|
||||
fn run(
|
||||
&self,
|
||||
async fn run(
|
||||
self,
|
||||
launcher_paths: LauncherPaths,
|
||||
handle: impl 'static + ServiceContainer,
|
||||
) -> Result<(), AnyError> {
|
||||
|
@ -149,7 +151,7 @@ impl CliServiceManager for WindowsService {
|
|||
.map_err(|e| wrap(e, "error starting service dispatcher").into())
|
||||
}
|
||||
|
||||
fn unregister(&self) -> Result<(), AnyError> {
|
||||
async fn unregister(&self) -> Result<(), AnyError> {
|
||||
let service_manager =
|
||||
ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT)
|
||||
.map_err(|e| wrap(e, "error getting service manager"))?;
|
||||
|
@ -214,7 +216,9 @@ fn service_main(_arguments: Vec<OsString>) -> Result<(), AnyError> {
|
|||
match control_event {
|
||||
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
|
||||
ServiceControl::Stop => {
|
||||
shutdown_tx.take().and_then(|tx| tx.blocking_send(ShutdownSignal::ServiceStopped).ok());
|
||||
shutdown_tx
|
||||
.take()
|
||||
.and_then(|tx| tx.blocking_send(ShutdownSignal::ServiceStopped).ok());
|
||||
ServiceControlHandlerResult::NoError
|
||||
}
|
||||
_ => ServiceControlHandlerResult::NotImplemented,
|
||||
|
|
Loading…
Reference in a new issue