Merge pull request #1935 from cryptomator/feature/lock-retry-loop

Handle exception when force-locking
This commit is contained in:
Sebastian Stenzel 2021-11-17 16:00:41 +01:00 committed by GitHub
commit 0c47af2f15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 17 deletions

View File

@ -16,7 +16,11 @@ public class UserInteractionLock<E extends Enum> {
private volatile E state;
public UserInteractionLock(E initialValue) {
state = initialValue;
this.state = initialValue;
}
public synchronized void reset(E value) {
this.state = value;
}
public void interacted(E result) {

View File

@ -35,7 +35,13 @@ public class LockForcedController implements FxController {
}
@FXML
public void confirmForcedLock() {
public void retry() {
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.RETRY);
window.close();
}
@FXML
public void force() {
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE);
window.close();
}
@ -54,4 +60,8 @@ public class LockForcedController implements FxController {
return vault.getDisplayName();
}
public boolean isForceSupported() {
return vault.supportsForcedUnmount();
}
}

View File

@ -28,6 +28,7 @@ abstract class LockModule {
enum ForceLockDecision {
CANCEL,
RETRY,
FORCE;
}

View File

@ -51,20 +51,26 @@ public class LockWorkflow extends Task<Void> {
@Override
protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException {
try {
vault.lock(false);
} catch (Volume.VolumeException | LockNotCompletedException e) {
LOG.debug("Regular lock of {} failed.", vault.getDisplayName(), e);
var decision = askUserForAction();
switch (decision) {
case FORCE -> vault.lock(true);
case CANCEL -> cancel(false);
}
}
lock(false);
return null;
}
private void lock(boolean forced) throws InterruptedException {
try {
vault.lock(forced);
} catch (Volume.VolumeException | LockNotCompletedException e) {
LOG.info("Locking {} failed (forced: {}).", vault.getDisplayName(), forced, e);
var decision = askUserForAction();
switch (decision) {
case RETRY -> lock(false);
case FORCE -> lock(true);
case CANCEL -> cancel(false);
}
}
}
private LockModule.ForceLockDecision askUserForAction() throws InterruptedException {
forceLockDecisionLock.reset(null);
// show forcedLock dialogue ...
Platform.runLater(() -> {
lockWindow.setScene(lockForcedScene.get());

View File

@ -33,11 +33,11 @@
</HBox>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<ButtonBar buttonMinWidth="100" buttonOrder="+CIU">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#cancel"/>
<!-- TODO: third button with retry? -->
<Button text="%lock.forced.confirmBtn" ButtonBar.buttonData="FINISH" onAction="#confirmForcedLock"/>
<Button text="%lock.forced.retryBtn" ButtonBar.buttonData="FINISH" onAction="#retry"/>
<Button text="%lock.forced.forceBtn" ButtonBar.buttonData="OTHER" onAction="#force" disable="${!controller.forceSupported}"/>
</buttons>
</ButtonBar>
</VBox>

View File

@ -118,9 +118,10 @@ unlock.error.invalidMountPoint.existing=Mount point "%s" already exists or paren
# Lock
## Force
lock.forced.heading=Graceful lock failed
lock.forced.heading=Lock failed
lock.forced.message=Locking "%s" was blocked by pending operations or open files. You can force lock this vault, however interrupting I/O may result in the loss of unsaved data.
lock.forced.confirmBtn=Force Lock
lock.forced.retryBtn=Retry
lock.forced.forceBtn=Force Lock
## Failure
lock.fail.heading=Locking vault failed.
lock.fail.message=Vault "%s" could not be locked. Ensure unsaved work is saved elsewhere and important Read/Write operations are finished. In order to close the vault, kill the Cryptomator process.