Skip to content

Commit

Permalink
Merge pull request #4060 from ghubstan/avoid-standby-mode
Browse files Browse the repository at this point in the history
Improve AvoidStandyModeService
  • Loading branch information
ripcurlx authored Apr 1, 2020
2 parents 6c59f6e + c0f9073 commit a96bfd4
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 36 deletions.
145 changes: 139 additions & 6 deletions core/src/main/java/bisq/core/app/AvoidStandbyModeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,25 @@
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;


Expand All @@ -46,18 +58,21 @@ public class AvoidStandbyModeService {

private final Preferences preferences;
private final Config config;
private final Optional<String> inhibitorPathSpec;
private CountDownLatch stopLinuxInhibitorCountdownLatch;

private volatile boolean isStopped;

@Inject
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();
}
Expand All @@ -73,13 +88,62 @@ public void init() {

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 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 play() {
private void playSilentAudioFile() {
try {
log.info("Started");
while (!isStopped) {
try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(getSoundFile());
SourceDataLine sourceDataLine = getSourceDataLine(audioInputStream.getFormat())) {
Expand Down Expand Up @@ -113,4 +177,73 @@ private SourceDataLine getSourceDataLine(AudioFormat audioFormat) throws LineUna
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"});
}
1 change: 1 addition & 0 deletions core/src/main/java/bisq/core/app/BisqExecutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ public void gracefulShutDown(ResultHandler resultHandler) {
injector.getInstance(BsqWalletService.class).shutDown();
});
});
injector.getInstance(AvoidStandbyModeService.class).shutDown();
// we wait max 20 sec.
UserThread.runAfter(() -> {
log.warn("Timeout triggered resultHandler");
Expand Down
27 changes: 0 additions & 27 deletions core/src/main/java/bisq/core/app/OSXStandbyModeDisabler.java

This file was deleted.

2 changes: 0 additions & 2 deletions desktop/src/main/java/bisq/desktop/app/BisqApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
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;
Expand Down Expand Up @@ -133,7 +132,6 @@ public void startApplication(Runnable onUiReadyHandler) {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public PreferencesView(PreferencesViewModel model,
!rpcUser.isEmpty() &&
!rpcPassword.isEmpty() &&
rpcBlockNotificationPort != Config.UNSPECIFIED_PORT;
this.displayStandbyModeFeature = Utilities.isOSX() || Utilities.isWindows();
this.displayStandbyModeFeature = Utilities.isLinux() || Utilities.isOSX() || Utilities.isWindows();
}

@Override
Expand Down

0 comments on commit a96bfd4

Please sign in to comment.