mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-05-24 08:18:33 -04:00
Rework operation mode error handling
This commit is contained in:
@@ -4,6 +4,7 @@ import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.ext.DataStoreProviders;
|
||||
import io.xpipe.app.issue.*;
|
||||
import io.xpipe.app.launcher.LauncherCommand;
|
||||
import io.xpipe.app.util.PlatformState;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.app.util.XPipeSession;
|
||||
import io.xpipe.core.store.LocalStore;
|
||||
@@ -121,10 +122,21 @@ public abstract class OperationMode {
|
||||
}
|
||||
|
||||
public static void switchToAsync(OperationMode newMode) {
|
||||
ThreadHelper.createPlatformThread("mode switcher", false, () -> switchTo(newMode)).start();
|
||||
ThreadHelper.createPlatformThread("mode switcher", false, () -> {
|
||||
switchToSyncIfPossible(newMode);
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void switchTo(OperationMode newMode) {
|
||||
public static void switchToSyncOrThrow(OperationMode newMode) throws Throwable {
|
||||
TrackEvent.info("Attempting to switch mode to " + newMode.getId());
|
||||
|
||||
if (!newMode.isSupported()) {
|
||||
throw PlatformState.getLastError() != null ? PlatformState.getLastError() : new IllegalStateException("Unsupported operation mode: " + newMode.getId());
|
||||
}
|
||||
|
||||
set(newMode);
|
||||
}
|
||||
public static void switchToSyncIfPossible(OperationMode newMode) {
|
||||
TrackEvent.info("Attempting to switch mode to " + newMode.getId());
|
||||
|
||||
if (newMode.equals(TRAY) && !TRAY.isSupported()) {
|
||||
@@ -142,6 +154,7 @@ public abstract class OperationMode {
|
||||
set(newMode);
|
||||
}
|
||||
|
||||
|
||||
public static void switchUp(OperationMode newMode) {
|
||||
if (newMode == BACKGROUND) {
|
||||
return;
|
||||
|
||||
@@ -13,8 +13,8 @@ public abstract class PlatformMode extends OperationMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
PlatformState.initPlatform();
|
||||
return PlatformState.getCurrent() == PlatformState.RUNNING;
|
||||
var r = PlatformState.initPlatformIfNeeded();
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -24,11 +24,7 @@ public abstract class PlatformMode extends OperationMode {
|
||||
}
|
||||
|
||||
TrackEvent.info("mode", "Platform mode initial setup");
|
||||
var r = PlatformState.initPlatform();
|
||||
if (r.isPresent()) {
|
||||
throw r.get();
|
||||
}
|
||||
|
||||
PlatformState.initPlatformOrThrow();
|
||||
AppFont.loadFonts();
|
||||
AppTheme.init();
|
||||
AppStyle.init();
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ModeExchangeImpl extends ModeExchange
|
||||
.toList()));
|
||||
}
|
||||
|
||||
OperationMode.switchTo(mode);
|
||||
OperationMode.switchToSyncIfPossible(mode);
|
||||
return ModeExchange.Response.builder()
|
||||
.usedMode(OperationMode.map(OperationMode.get()))
|
||||
.build();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.app.issue;
|
||||
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.util.LicenseProvider;
|
||||
import io.xpipe.app.util.LicenseRequiredException;
|
||||
|
||||
@@ -12,23 +11,23 @@ public class GuiErrorHandler extends GuiErrorHandlerBase implements ErrorHandler
|
||||
public void handle(ErrorEvent event) {
|
||||
log.handle(event);
|
||||
|
||||
if (!OperationMode.GUI.isSupported() || event.isOmitted()) {
|
||||
if (event.isOmitted()) {
|
||||
ErrorAction.ignore().handle(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!startupGui(throwable -> {
|
||||
var second = ErrorEvent.fromThrowable(throwable).build();
|
||||
log.handle(second);
|
||||
ErrorAction.ignore().handle(second);
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleGui(event);
|
||||
}
|
||||
|
||||
private void handleGui(ErrorEvent event) {
|
||||
if (!startupGui(throwable -> {
|
||||
log.handle(ErrorEvent.fromThrowable(throwable).build());
|
||||
ErrorAction.ignore().handle(event);
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (event.getThrowable() instanceof LicenseRequiredException lex) {
|
||||
LicenseProvider.get().showLicenseAlert(lex);
|
||||
event.setShouldSendDiagnostics(true);
|
||||
|
||||
@@ -8,21 +8,16 @@ import java.util.function.Consumer;
|
||||
public class GuiErrorHandlerBase {
|
||||
|
||||
protected boolean startupGui(Consumer<Throwable> onFail) {
|
||||
var ex = PlatformState.initPlatform();
|
||||
if (ex.isPresent()) {
|
||||
onFail.accept(ex.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
PlatformState.initPlatformOrThrow();
|
||||
AppProperties.init();
|
||||
AppState.init();
|
||||
AppExtensionManager.init(false);
|
||||
AppI18n.init();
|
||||
AppStyle.init();
|
||||
AppTheme.init();
|
||||
} catch (Throwable r) {
|
||||
onFail.accept(r);
|
||||
} catch (Throwable ex) {
|
||||
onFail.accept(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,23 +16,23 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa
|
||||
public void handle(ErrorEvent event) {
|
||||
log.handle(event);
|
||||
|
||||
if (!OperationMode.GUI.isSupported() || event.isOmitted() || OperationMode.isInShutdown()) {
|
||||
SentryErrorHandler.getInstance().handle(event);
|
||||
if (event.isOmitted() || OperationMode.isInShutdown()) {
|
||||
ErrorAction.ignore().handle(event);
|
||||
OperationMode.halt(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!startupGui(throwable -> {
|
||||
handleWithSecondaryException(event, throwable);
|
||||
ErrorAction.ignore().handle(event);
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleGui(event);
|
||||
}
|
||||
|
||||
private void handleGui(ErrorEvent event) {
|
||||
if (!startupGui(throwable -> {
|
||||
handleSecondaryException(event, throwable);
|
||||
ErrorAction.ignore().handle(event);
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
AppProperties.init();
|
||||
AppState.init();
|
||||
@@ -43,7 +43,7 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa
|
||||
ErrorHandlerComp.showAndTryWait(event, true);
|
||||
} catch (Throwable r) {
|
||||
event.clearAttachments();
|
||||
handleSecondaryException(event, r);
|
||||
handleWithSecondaryException(event, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,13 +54,12 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa
|
||||
OperationMode.halt(1);
|
||||
}
|
||||
|
||||
private void handleSecondaryException(ErrorEvent event, Throwable t) {
|
||||
log.handle(event);
|
||||
SentryErrorHandler.getInstance().handle(event);
|
||||
private void handleWithSecondaryException(ErrorEvent event, Throwable t) {
|
||||
ErrorAction.ignore().handle(event);
|
||||
|
||||
var second = ErrorEvent.fromThrowable(t).build();
|
||||
log.handle(second);
|
||||
SentryErrorHandler.getInstance().handle(ErrorEvent.fromThrowable(t).build());
|
||||
ErrorAction.ignore().handle(second);
|
||||
OperationMode.halt(1);
|
||||
}
|
||||
|
||||
@@ -89,7 +88,7 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa
|
||||
} catch (Throwable t) {
|
||||
var event = ErrorEvent.fromThrowable(t).build();
|
||||
log.handle(event);
|
||||
SentryErrorHandler.getInstance().handle(event);
|
||||
ErrorAction.ignore().handle(event);
|
||||
OperationMode.halt(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.xpipe.beacon.exchange.FocusExchange;
|
||||
import io.xpipe.beacon.exchange.OpenExchange;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.util.XPipeDaemonMode;
|
||||
import lombok.SneakyThrows;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -118,11 +119,12 @@ public class LauncherCommand implements Callable<Integer> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Integer call() {
|
||||
checkStart();
|
||||
// Initialize base mode first to have access to the preferences to determine effective mode
|
||||
OperationMode.switchTo(OperationMode.BACKGROUND);
|
||||
OperationMode.switchTo(OperationMode.map(getEffectiveMode()));
|
||||
OperationMode.switchToSyncOrThrow(OperationMode.BACKGROUND);
|
||||
OperationMode.switchToSyncOrThrow(OperationMode.map(getEffectiveMode()));
|
||||
LauncherInput.handle(inputs);
|
||||
|
||||
// URL open operations have to be handled in a special way on macOS!
|
||||
|
||||
@@ -39,7 +39,7 @@ public abstract class LauncherInput {
|
||||
|
||||
var requiresPlatform = all.stream().anyMatch(launcherInput -> launcherInput.requiresJavaFXPlatform());
|
||||
if (requiresPlatform) {
|
||||
OperationMode.switchTo(OperationMode.GUI);
|
||||
OperationMode.switchToSyncIfPossible(OperationMode.GUI);
|
||||
}
|
||||
var hasGui = OperationMode.get() == OperationMode.GUI;
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ public enum PlatformState {
|
||||
@Setter
|
||||
private static PlatformState current = PlatformState.NOT_INITIALIZED;
|
||||
|
||||
@Getter
|
||||
private static Exception lastError;
|
||||
|
||||
public static void teardown() {
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
// Fix to preserve clipboard contents after shutdown
|
||||
@@ -36,14 +39,24 @@ public enum PlatformState {
|
||||
setCurrent(PlatformState.EXITED);
|
||||
}
|
||||
|
||||
public static void initPlatformOrThrow() throws Throwable {
|
||||
var r = PlatformState.initPlatform();
|
||||
if (r.isPresent()) {
|
||||
throw r.get();
|
||||
public static void initPlatformOrThrow() throws Exception {
|
||||
initPlatformIfNeeded();
|
||||
if (lastError != null) {
|
||||
throw lastError;
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<Throwable> initPlatform() {
|
||||
public static boolean initPlatformIfNeeded() {
|
||||
if (current == NOT_INITIALIZED) {
|
||||
var t = PlatformState.initPlatform().orElse(null);
|
||||
lastError = t instanceof Exception e ? e : t != null ? new Exception(t) : null;
|
||||
}
|
||||
|
||||
return current == RUNNING;
|
||||
}
|
||||
|
||||
|
||||
private static Optional<Throwable> initPlatform() {
|
||||
if (current == EXITED) {
|
||||
return Optional.of(new IllegalStateException("Platform has already exited"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user