cli: implement --no-sleep on linux

This commit is contained in:
Connor Peet 2023-01-21 12:29:28 -08:00
parent 758bc69404
commit 2ef991a960
6 changed files with 66 additions and 25 deletions

View file

@ -214,11 +214,13 @@ pub async fn serve(ctx: CommandContext, gateway_args: TunnelServeArgs) -> Result
} = ctx;
let no_sleep = match gateway_args.no_sleep.then(SleepInhibitor::new) {
Some(Ok(i)) => Some(i),
Some(Err(e)) => {
warning!(log, "Could not inhibit sleep: {}", e);
None
}
Some(i) => match i.await {
Ok(i) => Some(i),
Err(e) => {
warning!(log, "Could not inhibit sleep: {}", e);
None
}
},
None => None,
};

View file

@ -16,6 +16,8 @@ mod nosleep;
mod nosleep_macos;
#[cfg(target_os = "windows")]
mod nosleep_windows;
#[cfg(target_os = "linux")]
mod nosleep_linux;
mod port_forwarder;
mod protocol;
#[cfg_attr(unix, path = "tunnels/server_bridge_unix.rs")]

View file

@ -7,24 +7,7 @@
pub type SleepInhibitor = super::nosleep_windows::SleepInhibitor;
#[cfg(target_os = "linux")]
pub type SleepInhibitor = NoOpSleepInhibitor;
pub type SleepInhibitor = super::nosleep_linux::SleepInhibitor;
#[cfg(target_os = "macos")]
pub type SleepInhibitor = super::nosleep_macos::SleepInhibitor;
/// Stub no-sleep implementation for unsupported platforms.
#[allow(dead_code)]
pub struct NoOpSleepInhibitor();
#[allow(dead_code)]
impl NoOpSleepInhibitor {
pub fn new() -> std::io::Result<Self> {
Ok(NoOpSleepInhibitor())
}
}
impl Drop for NoOpSleepInhibitor {
fn drop(&mut self) {
// no-op
}
}

View file

@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
use zbus::{dbus_proxy, Connection};
use crate::{
constants::APPLICATION_NAME,
util::errors::{wrap, AnyError},
};
/// An basically undocumented API, but seems widely implemented, and is what
/// browsers use for sleep inhibition. The downside is that it also *may*
/// disable the screensaver. A much better and more granular API is available
/// on `org.freedesktop.login1.Manager`, but this requires administrative
/// permission to request inhibition, which is not possible here.
///
/// See https://source.chromium.org/chromium/chromium/src/+/main:services/device/wake_lock/power_save_blocker/power_save_blocker_linux.cc;l=54;drc=2e85357a8b76996981cc6f783853a49df2cedc3a
#[dbus_proxy(
interface = "org.freedesktop.PowerManagement.Inhibit",
gen_blocking = false,
default_service = "org.freedesktop.PowerManagement.Inhibit",
default_path = "/org/freedesktop/PowerManagement/Inhibit"
)]
trait PMInhibitor {
#[dbus_proxy(name = "Inhibit")]
fn inhibit(&self, what: &str, why: &str) -> zbus::Result<u32>;
}
pub struct SleepInhibitor {
_connection: Connection, // Inhibition is released when the connection is closed
}
impl SleepInhibitor {
pub async fn new() -> Result<Self, AnyError> {
let connection = Connection::session()
.await
.map_err(|e| wrap(e, "error creating dbus session"))?;
let proxy = PMInhibitorProxy::new(&connection)
.await
.map_err(|e| wrap(e, "error getting proxy"))?;
proxy
.inhibit(APPLICATION_NAME, "running tunnel")
.await
.map_err(|e| wrap(e, "error requesting sleep inhibition"))?;
Ok(SleepInhibitor {
_connection: connection,
})
}
}

View file

@ -28,7 +28,7 @@ pub struct SleepInhibitor {
}
impl SleepInhibitor {
pub fn new() -> io::Result<Self> {
pub async fn new() -> io::Result<Self> {
let mut assertion_id = 0;
let assertion_type = CFString::from_static_string("PreventSystemSleep");
let assertion_name =

View file

@ -66,7 +66,7 @@ pub struct SleepInhibitor {
}
impl SleepInhibitor {
pub fn new() -> io::Result<Self> {
pub async fn new() -> io::Result<Self> {
let request = Request::new()?;
request.set(PowerRequestSystemRequired)?;
Ok(Self { request })