mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Improve AvoidStandyModeService
This change substitutes use of memory efficient, OS supplied sleep/suspend inhibitor utilties for the silent audio file player on Linux, merges OSXStandbyModeDisabler functionality into AvoidStandyModeService, and removes that class. This change also stops Bisq from running the audio file on OSX; it is currently running both caffeinate and the silent audio file, and the avoid standby mode button in the the OSX settings view is currently toggling the audio player on and off, but not caffeinate. (The only way to shut down caffeinate is by shutting down Bisq.) The OSX avoid standby mode button button has not been hidden so a cached 'do not avoid standby mode' preference does not leave the user stuck without a caffeinate service the next time they start Bisq. (They can use it to turn caffeinate on, but it can't be used to turn it off without shutting down Bisq too.) The avoid standy mode button is now displayed on Linux because the native inhibitor can be toggled on and off. There is no change to the avoid shutdown service on Windows and Unix.
This commit is contained in:
parent
96934d9107
commit
c0f9073698
5 changed files with 141 additions and 36 deletions
|
@ -22,13 +22,25 @@ import bisq.core.user.Preferences;
|
|||
import bisq.common.config.Config;
|
||||
import bisq.common.storage.FileUtil;
|
||||
import bisq.common.storage.ResourceNotFoundException;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
|
@ -46,6 +58,8 @@ public class AvoidStandbyModeService {
|
|||
|
||||
private final Preferences preferences;
|
||||
private final Config config;
|
||||
private final Optional<String> inhibitorPathSpec;
|
||||
private CountDownLatch stopLinuxInhibitorCountdownLatch;
|
||||
|
||||
private volatile boolean isStopped;
|
||||
|
||||
|
@ -53,11 +67,12 @@ public class AvoidStandbyModeService {
|
|||
public AvoidStandbyModeService(Preferences preferences, Config config) {
|
||||
this.preferences = preferences;
|
||||
this.config = config;
|
||||
|
||||
this.inhibitorPathSpec = inhibitorPath();
|
||||
preferences.getUseStandbyModeProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
isStopped = true;
|
||||
log.info("AvoidStandbyModeService stopped");
|
||||
if (Utilities.isLinux() && runningInhibitorProcess().isPresent()) {
|
||||
Objects.requireNonNull(stopLinuxInhibitorCountdownLatch).countDown();
|
||||
}
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
|
@ -73,13 +88,62 @@ public class AvoidStandbyModeService {
|
|||
|
||||
private void start() {
|
||||
isStopped = false;
|
||||
log.info("AvoidStandbyModeService started");
|
||||
new Thread(this::play, "AvoidStandbyModeService-thread").start();
|
||||
if (Utilities.isLinux() || Utilities.isOSX()) {
|
||||
startInhibitor();
|
||||
} else {
|
||||
new Thread(this::playSilentAudioFile, "AvoidStandbyModeService-thread").start();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
isStopped = true;
|
||||
stopInhibitor();
|
||||
}
|
||||
|
||||
private void play() {
|
||||
private void startInhibitor() {
|
||||
try {
|
||||
if (runningInhibitorProcess().isPresent()) {
|
||||
log.info("Inhibitor already started");
|
||||
return;
|
||||
}
|
||||
inhibitCommand().ifPresent(cmd -> {
|
||||
try {
|
||||
new ProcessBuilder(cmd).start();
|
||||
log.info("Started -- disabled power management via {}", String.join(" ", cmd));
|
||||
if (Utilities.isLinux()) {
|
||||
stopLinuxInhibitorCountdownLatch = new CountDownLatch(1);
|
||||
new Thread(this::stopInhibitor, "StopAvoidStandbyModeService-thread").start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot avoid standby mode", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopInhibitor() {
|
||||
try {
|
||||
// Cannot toggle off osx caffeinate, but it will shutdown with bisq.
|
||||
if (Utilities.isLinux()) {
|
||||
if (!isStopped) {
|
||||
Objects.requireNonNull(stopLinuxInhibitorCountdownLatch).await();
|
||||
}
|
||||
Optional<ProcessHandle> runningInhibitor = runningInhibitorProcess();
|
||||
runningInhibitor.ifPresent(processHandle -> {
|
||||
processHandle.destroy();
|
||||
log.info("Stopped");
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Stop inhibitor thread interrupted", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void playSilentAudioFile() {
|
||||
try {
|
||||
log.info("Started");
|
||||
while (!isStopped) {
|
||||
try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(getSoundFile());
|
||||
SourceDataLine sourceDataLine = getSourceDataLine(audioInputStream.getFormat())) {
|
||||
|
@ -113,4 +177,73 @@ public class AvoidStandbyModeService {
|
|||
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
|
||||
return (SourceDataLine) AudioSystem.getLine(dataLineInfo);
|
||||
}
|
||||
|
||||
private Optional<String> inhibitorPath() {
|
||||
for (Optional<String> installedInhibitor : installedInhibitors.get()) {
|
||||
if (installedInhibitor.isPresent()) {
|
||||
return installedInhibitor;
|
||||
}
|
||||
}
|
||||
return Optional.empty(); // falling back to silent audio file player
|
||||
}
|
||||
|
||||
private Optional<String[]> inhibitCommand() {
|
||||
final String[] params;
|
||||
if (inhibitorPathSpec.isPresent()) {
|
||||
String cmd = inhibitorPathSpec.get();
|
||||
if (Utilities.isLinux()) {
|
||||
params = cmd.contains("gnome-session-inhibit")
|
||||
? new String[]{cmd, "--app-id", "Bisq", "--inhibit", "suspend", "--reason", "Avoid Standby", "--inhibit-only"}
|
||||
: new String[]{cmd, "--who", "Bisq", "--what", "sleep", "--why", "Avoid Standby", "--mode", "block", "tail", "-f", "/dev/null"};
|
||||
} else {
|
||||
params = Utilities.isOSX() ? new String[]{cmd, "-w", "" + ProcessHandle.current().pid()} : null;
|
||||
}
|
||||
} else {
|
||||
params = null; // fall back to silent audio file player
|
||||
}
|
||||
return params == null ? Optional.empty() : Optional.of(params);
|
||||
}
|
||||
|
||||
private Optional<ProcessHandle> runningInhibitorProcess() {
|
||||
final ProcessHandle[] inhibitorProc = new ProcessHandle[1];
|
||||
inhibitorPathSpec.ifPresent(cmd -> {
|
||||
Optional<ProcessHandle> jvmProc = ProcessHandle.of(ProcessHandle.current().pid());
|
||||
jvmProc.ifPresent(proc -> proc.children().forEach(childProc -> childProc.info().command().ifPresent(command -> {
|
||||
if (command.equals(cmd) && childProc.isAlive()) {
|
||||
inhibitorProc[0] = childProc;
|
||||
}
|
||||
})));
|
||||
});
|
||||
return inhibitorProc[0] == null ? Optional.empty() : Optional.of(inhibitorProc[0]);
|
||||
}
|
||||
|
||||
private final Predicate<String> isCmdInstalled = (p) -> {
|
||||
File executable = Paths.get(p).toFile();
|
||||
return executable.exists() && executable.canExecute();
|
||||
};
|
||||
|
||||
private final Function<String[], Optional<String>> cmdPath = (possiblePaths) -> {
|
||||
for (String path : possiblePaths) {
|
||||
if (isCmdInstalled.test(path)) {
|
||||
return Optional.of(path);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
};
|
||||
|
||||
private final Supplier<List<Optional<String>>> installedInhibitors = () ->
|
||||
new ArrayList<>() {{
|
||||
add(gnomeSessionInhibitPathSpec.get()); // On linux, preferred inhibitor is gnome-session-inhibit,
|
||||
add(systemdInhibitPathSpec.get()); // then fall back to systemd-inhibit if it is installed.
|
||||
add(caffeinatePathSec.get()); // On OSX, caffeinate should be installed.
|
||||
}};
|
||||
|
||||
private final Supplier<Optional<String>> gnomeSessionInhibitPathSpec = () ->
|
||||
cmdPath.apply(new String[]{"/usr/bin/gnome-session-inhibit", "/bin/gnome-session-inhibit"});
|
||||
|
||||
private final Supplier<Optional<String>> systemdInhibitPathSpec = () ->
|
||||
cmdPath.apply(new String[]{"/usr/bin/systemd-inhibit", "/bin/systemd-inhibit"});
|
||||
|
||||
private final Supplier<Optional<String>> caffeinatePathSec = () ->
|
||||
cmdPath.apply(new String[]{"/usr/bin/caffeinate"});
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ public abstract class BisqExecutable implements GracefulShutDownHandler, BisqSet
|
|||
injector.getInstance(BsqWalletService.class).shutDown();
|
||||
});
|
||||
});
|
||||
injector.getInstance(AvoidStandbyModeService.class).shutDown();
|
||||
// we wait max 20 sec.
|
||||
UserThread.runAfter(() -> {
|
||||
log.warn("Timeout triggered resultHandler");
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package bisq.core.app;
|
||||
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class OSXStandbyModeDisabler {
|
||||
public void doIt() {
|
||||
if (!Utilities.isOSX()) {
|
||||
return;
|
||||
}
|
||||
long pid = ProcessHandle.current().pid();
|
||||
try {
|
||||
String[] params = {"/usr/bin/caffeinate", "-w", "" + pid};
|
||||
|
||||
// we only start the process. caffeinate blocks until we exit.
|
||||
new ProcessBuilder(params).start();
|
||||
log.info("disabled power management via " + String.join(" ", params));
|
||||
} catch (IOException e) {
|
||||
log.error("could not disable standby mode on osx", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ import bisq.desktop.util.CssTheme;
|
|||
import bisq.desktop.util.ImageUtil;
|
||||
|
||||
import bisq.core.app.AvoidStandbyModeService;
|
||||
import bisq.core.app.OSXStandbyModeDisabler;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.dao.governance.voteresult.MissingDataRequestService;
|
||||
|
@ -133,7 +132,6 @@ public class BisqApp extends Application implements UncaughtExceptionHandler {
|
|||
scene = createAndConfigScene(mainView, injector);
|
||||
setupStage(scene);
|
||||
|
||||
injector.getInstance(OSXStandbyModeDisabler.class).doIt();
|
||||
injector.getInstance(AvoidStandbyModeService.class).init();
|
||||
|
||||
UserThread.runPeriodically(() -> Profiler.printSystemLoad(log), LOG_MEMORY_PERIOD_MIN, TimeUnit.MINUTES);
|
||||
|
|
|
@ -173,7 +173,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
!rpcUser.isEmpty() &&
|
||||
!rpcPassword.isEmpty() &&
|
||||
rpcBlockNotificationPort != Config.UNSPECIFIED_PORT;
|
||||
this.displayStandbyModeFeature = Utilities.isOSX() || Utilities.isWindows();
|
||||
this.displayStandbyModeFeature = Utilities.isLinux() || Utilities.isOSX() || Utilities.isWindows();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue