show progress during vault migration (ugly prototype)

This commit is contained in:
Sebastian Stenzel
2019-09-27 21:44:24 +02:00
parent 633470b0d6
commit cd4cb70896
3 changed files with 70 additions and 6 deletions

View File

@@ -7,8 +7,13 @@ import javafx.animation.Timeline;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.WritableValue;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
@@ -17,6 +22,7 @@ import javafx.util.Duration;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptofs.migration.Migrators;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptofs.migration.api.NoApplicableMigratorException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccess;
@@ -39,6 +45,7 @@ public class MigrationRunController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(MigrationRunController.class);
private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes
private static final Duration MIGRATION_PROGRESS_UPDATE_INTERVAL = Duration.millis(25);
private final Stage window;
private final Vault vault;
@@ -48,6 +55,9 @@ public class MigrationRunController implements FxController {
private final Lazy<Scene> successScene;
private final ObjectBinding<ContentDisplay> migrateButtonContentDisplay;
private final BooleanProperty migrationButtonDisabled;
private final DoubleProperty migrationProgress;
private final ScheduledService<Double> migrationProgressObservationService;
private volatile double volatileMigrationProgress = -1.0;
public NiceSecurePasswordField passwordField;
@Inject
@@ -60,6 +70,10 @@ public class MigrationRunController implements FxController {
this.successScene = successScene;
this.migrateButtonContentDisplay = Bindings.createObjectBinding(this::getMigrateButtonContentDisplay, vault.stateProperty());
this.migrationButtonDisabled = new SimpleBooleanProperty();
this.migrationProgress = new SimpleDoubleProperty(volatileMigrationProgress);
this.migrationProgressObservationService = new MigrationProgressObservationService();
migrationProgressObservationService.setExecutor(executor);
migrationProgressObservationService.setPeriod(MIGRATION_PROGRESS_UPDATE_INTERVAL);
}
public void initialize() {
@@ -79,17 +93,18 @@ public class MigrationRunController implements FxController {
LOG.info("Migrating vault {}", vault.getPath());
CharSequence password = passwordField.getCharacters();
vault.setState(VaultState.PROCESSING);
migrationProgressObservationService.start();
Tasks.create(() -> {
Migrators migrators = Migrators.get();
migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password);
migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged);
return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME);
}).onSuccess(needsAnotherMigration -> {
LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName());
if (needsAnotherMigration) {
vault.setState(VaultState.NEEDS_MIGRATION);
} else {
vault.setState(VaultState.LOCKED);
passwordField.swipe();
LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName());
window.setScene(successScene.get());
}
}).onError(InvalidPassphraseException.class, e -> {
@@ -105,9 +120,29 @@ public class MigrationRunController implements FxController {
LOG.error("Migration failed for technical reasons.", e);
vault.setState(VaultState.ERROR);
// TODO show generic error screen
}).andFinally(() -> {
migrationProgressObservationService.cancel();
migrationProgressObservationService.reset();
}).runOnce(executor);
}
// Called by a background task. We can not directly modify observable properties from here
private void migrationProgressChanged(MigrationProgressListener.ProgressState state, double progress) {
switch (state) {
case INITIALIZING:
volatileMigrationProgress = -1.0;
break;
case MIGRATING:
volatileMigrationProgress = progress;
break;
case FINALIZING:
volatileMigrationProgress = 1.0;
break;
default:
throw new IllegalStateException("Unexpted state " + state);
}
}
private void loadStoredPassword() {
assert keychainAccess.isPresent();
char[] storedPw = null;
@@ -126,6 +161,27 @@ public class MigrationRunController implements FxController {
}
}
// Sets migrationProgress to volatileMigrationProgress at its configured interval
private class MigrationProgressObservationService extends ScheduledService<Double> {
@Override
protected Task<Double> createTask() {
return new Task<>() {
@Override
protected Double call() {
return volatileMigrationProgress;
}
};
}
@Override
protected void succeeded() {
assert getValue() != null;
migrationProgress.set(getValue());
super.succeeded();
}
}
/* Animations */
private void shakeWindow() {
@@ -180,4 +236,12 @@ public class MigrationRunController implements FxController {
}
}
public ReadOnlyDoubleProperty migrationProgressProperty() {
return migrationProgress;
}
public double getMigrationProgress() {
return migrationProgress.get();
}
}

View File

@@ -23,6 +23,9 @@
<NiceSecurePasswordField fx:id="passwordField"/>
</VBox>
<!-- TODO add a progress bar... -->
<FormattedLabel format="progress: %.3f" arg1="${controller.migrationProgress}"/>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="B+X">
<buttons>

View File

@@ -2,7 +2,6 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.scene.control.Label?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.mainwindow.VaultDetailNeedsMigrationController"
@@ -12,9 +11,7 @@
<Insets topRightBottomLeft="24"/>
</padding>
<children>
<!-- TODO -->
<Label text="Migration disabled during Alpha"/>
<Button styleClass="button-large" text="TODO Upgrade Vault" minWidth="120" onAction="#showVaultMigrator" disable="true">
<Button styleClass="button-large" text="TODO Upgrade Vault" minWidth="120" onAction="#showVaultMigrator">
<graphic>
<FontAwesome5IconView glyph="FILE_IMPORT" glyphSize="15"/>
</graphic>