Show stack trace in UI for vaults in error state

This commit is contained in:
Sebastian Stenzel
2020-04-21 12:38:36 +02:00
parent a9a983d7ed
commit 243c74b0cb
10 changed files with 138 additions and 31 deletions
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import java.io.IOException;
import java.nio.file.NoSuchFileException;
@@ -51,6 +52,7 @@ public class Vault {
private final StringBinding defaultMountFlags;
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
private final ObjectProperty<VaultState> state;
private final ObjectProperty<Exception> lastKnownException;
private final VaultStats stats;
private final StringBinding displayableName;
private final StringBinding displayablePath;
@@ -59,18 +61,20 @@ public class Vault {
private final BooleanBinding unlocked;
private final BooleanBinding missing;
private final BooleanBinding needsMigration;
private final BooleanBinding unknownError;
private final StringBinding accessPoint;
private final BooleanBinding accessPointPresent;
private volatile Volume volume;
@Inject
Vault(VaultSettings vaultSettings, Provider<Volume> volumeProvider, @DefaultMountFlags StringBinding defaultMountFlags, AtomicReference<CryptoFileSystem> cryptoFileSystem, ObjectProperty<VaultState> state, VaultStats stats) {
Vault(VaultSettings vaultSettings, Provider<Volume> volumeProvider, @DefaultMountFlags StringBinding defaultMountFlags, AtomicReference<CryptoFileSystem> cryptoFileSystem, ObjectProperty<VaultState> state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, VaultStats stats) {
this.vaultSettings = vaultSettings;
this.volumeProvider = volumeProvider;
this.defaultMountFlags = defaultMountFlags;
this.cryptoFileSystem = cryptoFileSystem;
this.state = state;
this.lastKnownException = lastKnownException;
this.stats = stats;
this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.path());
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
@@ -79,6 +83,7 @@ public class Vault {
this.unlocked = Bindings.createBooleanBinding(this::isUnlocked, state);
this.missing = Bindings.createBooleanBinding(this::isMissing, state);
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
this.accessPoint = Bindings.createStringBinding(this::getAccessPoint, state);
this.accessPointPresent = this.accessPoint.isNotEmpty();
}
@@ -149,6 +154,18 @@ public class Vault {
state.setValue(value);
}
public ObjectProperty<Exception> lastKnownExceptionProperty() {
return lastKnownException;
}
public Exception getLastKnownException() {
return lastKnownException.get();
}
public void setLastKnownException(Exception e) {
lastKnownException.setValue(e);
}
public BooleanBinding lockedProperty() {
return locked;
}
@@ -189,6 +206,14 @@ public class Vault {
return state.get() == VaultState.NEEDS_MIGRATION;
}
public BooleanBinding unknownErrorProperty() {
return unknownError;
}
public boolean isUnknownError() {
return state.get() == VaultState.ERROR;
}
public StringBinding displayableNameProperty() {
return displayableName;
}
@@ -10,6 +10,9 @@ import org.cryptomator.common.settings.VaultSettings;
import dagger.Subcomponent;
import javax.annotation.Nullable;
import javax.inject.Named;
@PerVault
@Subcomponent(modules = {VaultModule.class})
public interface VaultComponent {
@@ -25,6 +28,9 @@ public interface VaultComponent {
@BindsInstance
Builder initialVaultState(VaultState vaultState);
@BindsInstance
Builder initialErrorCause(@Nullable @Named("lastKnownException") Exception initialErrorCause);
VaultComponent build();
}
@@ -31,9 +31,9 @@ import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
@Singleton
public class VaultListManager {
private static final Logger LOG = LoggerFactory.getLogger(VaultListManager.class);
private final VaultComponent.Builder vaultComponentBuilder;
private final ObservableList<Vault> vaultList;
@@ -41,7 +41,7 @@ public class VaultListManager {
public VaultListManager(VaultComponent.Builder vaultComponentBuilder, Settings settings) {
this.vaultComponentBuilder = vaultComponentBuilder;
this.vaultList = FXCollections.observableArrayList(Vault::observables);
addAll(settings.getDirectories());
vaultList.addListener(new VaultListChangeListener(settings.getDirectories()));
}
@@ -65,12 +65,12 @@ public class VaultListManager {
return newVault;
}
}
private void addAll(Collection<VaultSettings> vaultSettings) {
Collection<Vault> vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
vaultList.addAll(vaults);
}
private Optional<Vault> get(Path vaultPath) {
return vaultList.stream().filter(v -> {
try {
@@ -82,23 +82,25 @@ public class VaultListManager {
}
private Vault create(VaultSettings vaultSettings) {
VaultState vaultState = determineVaultState(vaultSettings.path().get());
VaultComponent comp = vaultComponentBuilder.vaultSettings(vaultSettings).initialVaultState(vaultState).build();
return comp.vault();
VaultComponent.Builder compBuilder = vaultComponentBuilder.vaultSettings(vaultSettings);
try {
VaultState vaultState = determineVaultState(vaultSettings.path().get());
compBuilder.initialVaultState(vaultState);
} catch (IOException e) {
LOG.warn("Failed to determine vault state for " + vaultSettings.path().get(), e);
compBuilder.initialVaultState(VaultState.ERROR);
compBuilder.initialErrorCause(e);
}
return compBuilder.build().vault();
}
public static VaultState determineVaultState(Path pathToVault) {
try {
if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
return VaultState.MISSING;
} else if (Migrators.get().needsMigration(pathToVault, MASTERKEY_FILENAME)) {
return VaultState.NEEDS_MIGRATION;
} else {
return VaultState.LOCKED;
}
} catch (IOException e) {
LOG.warn("Could not determine vault state of " + pathToVault + " due to unexpected exception.", e);
return VaultState.ERROR;
public static VaultState determineVaultState(Path pathToVault) throws IOException {
if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
return VaultState.MISSING;
} else if (Migrators.get().needsMigration(pathToVault, MASTERKEY_FILENAME)) {
return VaultState.NEEDS_MIGRATION;
} else {
return VaultState.LOCKED;
}
}
@@ -23,6 +23,8 @@ import org.cryptomator.cryptofs.CryptoFileSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -46,6 +48,14 @@ public class VaultModule {
return new SimpleObjectProperty<>(initialState);
}
@Provides
@Named("lastKnownException")
@PerVault
public ObjectProperty<Exception> provideLastKnownException(@Named("lastKnownException") @Nullable Exception initialErrorCause) {
return new SimpleObjectProperty<>(initialErrorCause);
}
@Provides
public Volume provideVolume(Settings settings, WebDavVolume webDavVolume, FuseVolume fuseVolume, DokanyVolume dokanyVolume) {
VolumeImpl preferredImpl = settings.preferredVolumeImpl().get();