keepawake

Native keep-awake guards for MoonBit on Windows, Linux, and macOS.

keepawake
native
windows
linux
macos
power-management
moon add moonbit-community/keepawake@0.1.14
Download zip
Version
0.1.14
License
Apache-2.0
Last updated
10 days ago
Downloads
14

Dependencies

README

#keepawake

Native-only keep-awake guards for MoonBit on Windows, Linux, and macOS.

///|
test {
assert_eq(Scope::PreventSystemSleep.to_string(), "PreventSystemSleep")
}

let guard = @keepawake.acquire(
reason="Rendering a large animation",
scope=@keepawake.Scope::PreventSystemAndDisplaySleep,
)

guard.release()

#
KeepAwakeError

pub(all) suberror KeepAwakeError {
BackendUnavailable(detail~ : String)
OperationFailed(operation~ : String, detail~ : String)
} derive(Eq)

Describes failures raised by the native keep-awake backends.

BackendUnavailable means the current environment cannot offer the requested inhibition mechanism, while OperationFailed means a supported backend was found but the requested operation still failed.

Use the variant payloads to surface actionable diagnostics to callers or end users:

  • BackendUnavailable(detail~) reports that the current environment does not expose a usable keep-awake mechanism, for example because systemd-inhibit is missing or the expected macOS framework cannot be loaded.
  • OperationFailed(operation~, detail~) reports that the selected backend exists but could not complete the requested lifecycle action such as acquire or release.

The detail strings are intentionally human-readable, so they can be logged directly or attached to higher-level application errors without extra translation.

#
Guard

pub type Guard

Represents a native keep-awake request managed by the current platform.

A Guard is created by acquire and released explicitly through Guard::release or implicitly when the runtime reclaims it. The type is intentionally opaque so callers interact only through the safe public API instead of depending on backend-specific state layout. On Windows the implicit reclaim may run on a different thread than the one that acquired the guard: the release is then accounted for correctly, but the acquiring thread's power-state flags can persist until that thread exits, so explicit release is the recommended path.

#
Guard::active

fn Guard::active(self : Guard) -> Bool

Returns whether the underlying native inhibition is still active.

This becomes false after a successful call to Guard::release, and it is also false for guards returned by a failed acquire attempt before the error is raised to the caller.

Use this method for diagnostics, assertions, or defensive checks around cleanup-heavy workflows. Most callers do not need to poll it during normal operation because the guard exposes only a single lifecycle boundary: active versus released.

#
Guard::release

fn Guard::release(self : Guard) -> Unit raise KeepAwakeError

Releases the native keep-awake request.

Releasing a guard is idempotent. Calling release on an inactive guard is a no-op. If the backend reports an unexpected release failure, this method raises KeepAwakeError::OperationFailed.

Call this as soon as the protected work finishes when you acquired the guard manually. Releasing early is preferred over waiting for runtime cleanup, because explicit release makes the lifetime obvious and avoids depending on garbage collection timing.

Errors

Raises KeepAwakeError::OperationFailed if the backend reports that the native release operation did not complete successfully.

#
Guard::scope

fn Guard::scope(self : Guard) -> Scope

Returns the scope that was requested when the guard was created.

This is the semantic scope originally passed to acquire or with_keepawake, not a platform-specific low-level flag set. It is useful when code stores guards in higher-level abstractions and later wants to inspect or report what kind of inhibition is currently in effect.

#
Scope

pub(all) enum Scope {
PreventSystemSleep
PreventDisplaySleep
PreventSystemAndDisplaySleep
} derive(Eq,
Debug
)

Describes which kind of idle policy should be inhibited while a guard is alive.

PreventSystemSleep asks the operating system to keep the machine awake. PreventDisplaySleep asks the operating system to keep the display awake. PreventSystemAndDisplaySleep requests both when the backend supports both concepts directly.

Choose the smallest scope that matches the protected work:

  • use PreventSystemSleep for background work such as builds, exports, or downloads where the display may still turn off
  • use PreventDisplaySleep for presentation-style tasks where the screen must remain visible
  • use PreventSystemAndDisplaySleep when both machine sleep and display sleep would interrupt the task

Backends may map these variants to different native APIs, but the semantic meaning of each variant stays stable across operating systems.

Example

test {
assert_eq(
Scope::PreventSystemAndDisplaySleep.to_string(),
"PreventSystemAndDisplaySleep",
)
}
impl Show for Scope

#
acquire

fn acquire(reason? : String, scope? : Scope) -> Guard raise KeepAwakeError

Acquires a keep-awake guard for the current operating system.

The returned guard activates the native inhibition immediately and keeps it alive until Guard::release is called or the guard is reclaimed by the runtime. On Windows the reclaim path may run on a different thread; the release is accounted for correctly, but the acquiring thread's power-state flags can persist until that thread exits, so explicit release from the acquiring thread is recommended. Blank reasons are normalized to default_reason so callers can keep call sites simple without losing readable backend diagnostics.

reason should describe the user-visible work being protected, such as "Exporting a large report" or "Downloading offline assets". scope controls whether the request blocks system sleep, display sleep, or both.

Prefer acquire when your code naturally manages a long-lived handle. If the work is already scoped to a single callback, with_keepawake is usually more convenient because it guarantees structured release.

Errors

Raises KeepAwakeError::BackendUnavailable when the current environment cannot provide a usable keep-awake backend, and raises KeepAwakeError::OperationFailed when a backend exists but the native acquire step still fails.

Example

let guard = @keepawake.acquire(
reason="Encoding a large video",
scope=@keepawake.Scope::PreventSystemAndDisplaySleep,
)

// ... perform the long-running work ...

guard.release()

#
default_reason

let default_reason : String

The fallback reason used when callers pass an empty or whitespace-only reason.

This value is intentionally readable because some native backends expose the reason in system diagnostics or activity monitors. Applications can override it per call when they want more task-specific text, but keeping a default reason makes the simple API path ergonomic.

#
with_keepawake

fn[T] with_keepawake(action : () -> T raise?, reason? : String, scope? : Scope) -> T raise

Runs an action while a keep-awake guard is held.

This is the most ergonomic API for scoped work such as file exports, build steps, or long-running synchronization tasks. The guard is released after action finishes. If action raises, release is still attempted and any release failure is suppressed in favor of the original error.

This helper is the best default when the keep-awake lifetime should exactly match one operation. It keeps the call site small, avoids leaking a guard in early-return branches, and preserves the original application error if both the action and the release step fail.

reason and scope behave the same way as in acquire. The return value of action is passed through unchanged.

Errors

Raises the same KeepAwakeError values as acquire, plus any error raised by action.

Example

let summary = @keepawake.with_keepawake(
() => "done",
reason="Syncing local cache",
// ... perform long-running work ...
scope=@keepawake.Scope::PreventSystemSleep,
)

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io