mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 08:41:28 +00:00
cleanup + error handling
This commit is contained in:
@@ -7,7 +7,7 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.UpdateChecker;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.cryptomator.ui.preferences;
|
||||
import com.google.common.io.CharStreams;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.UpdateChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.UpdateChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.update.UpdateStep;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.UpdateChecker;
|
||||
import org.cryptomator.updater.FallbackUpdateInfo;
|
||||
import org.cryptomator.updater.UpdateService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -22,7 +22,10 @@ import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.binding.ObjectBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Worker;
|
||||
@@ -60,9 +63,9 @@ public class UpdatesPreferencesController implements FxController {
|
||||
private final ObjectBinding<ContentDisplay> updateButtonState;
|
||||
private final ObservableValue<String> timeDifferenceMessage;
|
||||
private final StringBinding lastUpdateCheckMessage;
|
||||
|
||||
private final BooleanBinding prohibitUpdateWhileUnlocked;
|
||||
private final BooleanBinding updateButtonDisabled;
|
||||
private final StringProperty errorMessage = new SimpleStringProperty("");
|
||||
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
|
||||
|
||||
/* FXML */
|
||||
@@ -76,6 +79,7 @@ public class UpdatesPreferencesController implements FxController {
|
||||
this.settings = settings;
|
||||
this.updateChecker = updateChecker;
|
||||
this.updateService = new UpdateService(updateChecker.updateProperty());
|
||||
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
||||
this.vaultService = vaultService;
|
||||
this.worker = Bindings.when(updateChecker.updateAvailableProperty()).<Worker<?>>then(this.updateService).otherwise(this.updateChecker);
|
||||
this.running = Bindings.createBooleanBinding(this::isRunning, updateService.stateProperty(), updateChecker.stateProperty());
|
||||
@@ -83,7 +87,6 @@ public class UpdatesPreferencesController implements FxController {
|
||||
this.updateButtonState = Bindings.createObjectBinding(this::getUpdateButtonState, updateChecker.stateProperty(), updateService.stateProperty());
|
||||
this.timeDifferenceMessage = Bindings.createStringBinding(this::getTimeDifferenceMessage, updateChecker.lastSuccessfulUpdateCheckProperty());
|
||||
this.lastUpdateCheckMessage = Bindings.createStringBinding(this::getLastUpdateCheckMessage, updateChecker.lastSuccessfulUpdateCheckProperty());
|
||||
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
||||
this.prohibitUpdateWhileUnlocked = Bindings.createBooleanBinding(this::isProhibitUpdateWhileUnlocked, unlockedVaults, updateChecker.updateProperty());
|
||||
this.updateButtonDisabled = Bindings.when(worker.isEqualTo(updateChecker)).then(running).otherwise(prohibitUpdateWhileUnlocked.or(running));
|
||||
}
|
||||
@@ -98,6 +101,7 @@ public class UpdatesPreferencesController implements FxController {
|
||||
delay.play();
|
||||
}
|
||||
});
|
||||
updateChecker.setOnFailed(this::checkFailed);
|
||||
updateService.setOnSucceeded(this::updateSucceeded);
|
||||
updateService.setOnFailed(this::updateFailed);
|
||||
}
|
||||
@@ -119,6 +123,12 @@ public class UpdatesPreferencesController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkFailed(WorkerStateEvent workerStateEvent) {
|
||||
assert workerStateEvent.getSource() == updateChecker;
|
||||
LOG.error("Update check failed.", updateChecker.getException());
|
||||
errorMessage.set(resourceBundle.getString("preferences.updates.checkFailed"));
|
||||
}
|
||||
|
||||
private void updateSucceeded(WorkerStateEvent workerStateEvent) {
|
||||
assert workerStateEvent.getSource() == updateService;
|
||||
var lastStep = updateService.getValue();
|
||||
@@ -138,9 +148,10 @@ public class UpdatesPreferencesController implements FxController {
|
||||
private void updateFailed(WorkerStateEvent workerStateEvent) {
|
||||
assert workerStateEvent.getSource() == updateService;
|
||||
LOG.error("Update failed.", updateService.getException());
|
||||
updateService.reset();
|
||||
errorMessage.set(resourceBundle.getString("preferences.updates.updateFailed"));
|
||||
// try fallback mechanism:
|
||||
updateChecker.recheckWithFallbackMechanism();
|
||||
updateService.reset();
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -180,9 +191,9 @@ public class UpdatesPreferencesController implements FxController {
|
||||
} else {
|
||||
return switch (updateService.getState()) {
|
||||
case READY -> updateChecker.getUpdate().updateMechanism().getName();
|
||||
case SCHEDULED, RUNNING -> updateService.getMessage(); // "Preparing Update..."; // TODO: resourceBundle.getString("preferences.updates.preparingUpdate")...
|
||||
case SUCCEEDED -> "Restart to Update"; // TODO: resourceBundle.getString("preferences.updates.readyToRestart")...
|
||||
case FAILED, CANCELLED -> "failed";
|
||||
case SCHEDULED, RUNNING -> updateService.getMessage();
|
||||
case SUCCEEDED -> resourceBundle.getString("generic.button.done");
|
||||
case FAILED, CANCELLED -> "failed"; // should never be visible
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -233,6 +244,14 @@ public class UpdatesPreferencesController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage.get();
|
||||
}
|
||||
|
||||
public ReadOnlyStringProperty errorMessageProperty() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public boolean isProhibitUpdateWhileUnlocked() {
|
||||
// If the result of the last update check was from the fallback mechanism, we don't need to show the warning
|
||||
return !unlockedVaults.isEmpty() && !FallbackUpdateInfo.class.isInstance(updateChecker.getUpdate());
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.cryptomator.ui.updatereminder;
|
||||
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.UpdateChecker;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.fxapp;
|
||||
package org.cryptomator.updater;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
@@ -5,15 +5,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.integrations.common.DisplayName;
|
||||
import org.cryptomator.integrations.common.Priority;
|
||||
import org.cryptomator.integrations.update.BasicUpdateInfo;
|
||||
import org.cryptomator.integrations.update.UpdateInfo;
|
||||
import org.cryptomator.integrations.common.LocalizedDisplayName;
|
||||
import org.cryptomator.integrations.update.UpdateMechanism;
|
||||
import org.cryptomator.integrations.update.UpdateStep;
|
||||
import org.cryptomator.integrations.update.UpdateStepAdapter;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -28,11 +23,9 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@FxApplicationScoped
|
||||
@Priority(Priority.FALLBACK)
|
||||
@DisplayName("Show Download Page") // TODO localize
|
||||
@LocalizedDisplayName(bundle = "i18n.strings", key = "preferences.updates.visitDownloadPage")
|
||||
public class FallbackUpdateMechanism implements UpdateMechanism<FallbackUpdateInfo> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FallbackUpdateMechanism.class);
|
||||
|
||||
@@ -110,8 +110,7 @@ public class MacOsDmgUpdateMechanism extends DownloadUpdateMechanism {
|
||||
} else if (selfPath.contains("/Cryptomator.app/")) {
|
||||
installPath = selfPath.substring(0, selfPath.indexOf("/Cryptomator.app/")) + "/Cryptomator.app";
|
||||
} else {
|
||||
installPath = "/Applications/Cryptomator.app";
|
||||
// throw new UpdateFailedException("Cannot determine destination path for Cryptomator.app, current path: " + selfPath);
|
||||
throw new UpdateFailedException("Cannot determine destination path for Cryptomator.app, current path: " + selfPath);
|
||||
}
|
||||
LOG.info("Restarting to apply Update in {} now...", workDir);
|
||||
String script = """
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.cryptomator.ui.fxapp;
|
||||
package org.cryptomator.updater;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.integrations.update.UpdateFailedException;
|
||||
import org.cryptomator.integrations.update.UpdateInfo;
|
||||
import org.cryptomator.integrations.update.UpdateMechanism;
|
||||
import org.cryptomator.updater.FallbackUpdateMechanism;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -19,7 +19,6 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.util.Duration;
|
||||
import java.net.http.HttpClient;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@@ -46,19 +45,16 @@ public class UpdateChecker extends ScheduledService<UpdateInfo<?>> {
|
||||
private final BooleanBinding updateAvailable = update.isNotNull();
|
||||
private final ObjectBinding<UpdateCheckState> updateState = Bindings.createObjectBinding(this::getUpdateCheckState, stateProperty());
|
||||
private final BooleanBinding checkFailed = Bindings.equal(UpdateCheckState.CHECK_FAILED, updateState);
|
||||
private final HttpClient httpClient;
|
||||
private final UpdateMechanism<?> fallbackUpdateMechanism;
|
||||
private UpdateMechanism<?> updateMechanism;
|
||||
|
||||
@Inject
|
||||
UpdateChecker(Settings settings, //
|
||||
Environment env,
|
||||
FallbackUpdateMechanism fallbackUpdateMechanism,
|
||||
UpdateCheckerHttpClient httpClient) {
|
||||
FallbackUpdateMechanism fallbackUpdateMechanism) {
|
||||
this.env = env;
|
||||
this.settings = settings;
|
||||
this.lastSuccessfulUpdateCheck = settings.lastSuccessfulUpdateCheck;
|
||||
this.httpClient = httpClient;
|
||||
this.fallbackUpdateMechanism = fallbackUpdateMechanism;
|
||||
|
||||
// Prefer the safer fallback mechanism if the last update attempt was already made by this app version
|
||||
@@ -178,7 +174,7 @@ public class UpdateChecker extends ScheduledService<UpdateInfo<?>> {
|
||||
|
||||
@Override
|
||||
protected UpdateInfo<?> call() {
|
||||
try {
|
||||
try (var httpClient = new UpdateCheckerHttpClient(env)) {
|
||||
var result = updateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
if (result != null) {
|
||||
return result;
|
||||
@@ -190,7 +186,7 @@ public class UpdateChecker extends ScheduledService<UpdateInfo<?>> {
|
||||
return null;
|
||||
}
|
||||
LOG.debug("Trying fallback update check...");
|
||||
try {
|
||||
try (var httpClient = new UpdateCheckerHttpClient(env)) {
|
||||
return fallbackUpdateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
} catch (UpdateFailedException e) {
|
||||
LOG.error("Fallback update check failed.", e);
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.cryptomator.ui.fxapp;
|
||||
package org.cryptomator.updater;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
|
||||
@@ -12,12 +11,10 @@ import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class UpdateCheckerHttpClient extends DelegatingHttpClient {
|
||||
|
||||
private final String userAgent;
|
||||
|
||||
@Inject
|
||||
public UpdateCheckerHttpClient(Environment env) {
|
||||
var delegate = HttpClient.newBuilder() //
|
||||
.followRedirects(HttpClient.Redirect.NORMAL) // from version 1.6.11 onwards, Cryptomator can follow redirects, in case this URL ever changes
|
||||
@@ -4,6 +4,8 @@ import org.cryptomator.integrations.update.UpdateInfo;
|
||||
import org.cryptomator.integrations.update.UpdateMechanism;
|
||||
import org.cryptomator.integrations.update.UpdateStep;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
@@ -18,6 +20,8 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class UpdateService extends Service<UpdateStep> {
|
||||
|
||||
private final BooleanBinding updateFailed = Bindings.equal(State.FAILED, stateProperty());
|
||||
|
||||
private ObservableValue<UpdateInfo<?>> updateInfo;
|
||||
|
||||
public UpdateService(ObservableValue<UpdateInfo<?>> updateInfo) {
|
||||
@@ -65,4 +69,13 @@ public class UpdateService extends Service<UpdateStep> {
|
||||
}
|
||||
}
|
||||
|
||||
/* Observable Properties */
|
||||
|
||||
public boolean isUpdateFailed() {
|
||||
return updateFailed.get();
|
||||
}
|
||||
|
||||
public BooleanBinding updateFailedProperty() {
|
||||
return updateFailed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,18 +52,20 @@
|
||||
<Text text="%preferences.updates.prohibitedDueToUnlockedVaults.3"/>
|
||||
</TextFlow>
|
||||
|
||||
<TextFlow styleClass="text-flow" textAlignment="CENTER" visible="${controller.updateChecker.checkFailed}" managed="${controller.updateChecker.checkFailed}">
|
||||
<TextFlow styleClass="text-flow" textAlignment="CENTER" visible="${!controller.errorMessage.empty}" managed="${!controller.errorMessage.empty}">
|
||||
<FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-orange" glyph="EXCLAMATION_TRIANGLE"/>
|
||||
<Text text=" "/>
|
||||
<Text text="%preferences.updates.checkFailed"/>
|
||||
<Text text="${controller.errorMessage}"/>
|
||||
<Text text=" "/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%preferences.general.debugDirectory" onAction="#showLogfileDirectory"/>
|
||||
</TextFlow>
|
||||
|
||||
<FormattedLabel format="%preferences.updates.lastUpdateCheck" arg1="${controller.timeDifferenceMessage}" textAlignment="CENTER" wrapText="true" visible="${!controller.updateChecker.updateAvailable}" managed="${!controller.updateChecker.updateAvailable}">
|
||||
<tooltip>
|
||||
<Tooltip text="${controller.lastUpdateCheckMessage}" showDelay="10ms"/>
|
||||
</tooltip>
|
||||
</FormattedLabel>
|
||||
|
||||
<Label text="%preferences.updates.upToDate" visible="${controller.upToDateLabelVisible}" managed="${controller.upToDateLabelVisible}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-primary" glyph="CHECK"/>
|
||||
|
||||
@@ -334,7 +334,9 @@ preferences.updates.prohibitedDueToUnlockedVaults.1=Please
|
||||
preferences.updates.prohibitedDueToUnlockedVaults.2=lock your vaults
|
||||
preferences.updates.prohibitedDueToUnlockedVaults.3=to install the update.
|
||||
preferences.updates.checkFailed=Looking for updates failed. Please check your internet connection or try again later.
|
||||
preferences.updates.updateFailed=Update failed. Please install the update manually.
|
||||
preferences.updates.upToDate=Cryptomator is up-to-date.
|
||||
preferences.updates.visitDownloadPage=Visit Download Page
|
||||
|
||||
## Contribution
|
||||
preferences.contribute=Support Us
|
||||
|
||||
Reference in New Issue
Block a user