forked from j62/ctbrec
Add confirmation dialog for shutdown
Show confirmation dialog when a shutdown is requested and there are recordings in progress. The user now can decide to shutdown immediately, shutdown gracefully or leave the app running
This commit is contained in:
parent
17f1c3aec6
commit
7e2924d780
|
@ -5,6 +5,7 @@
|
|||
* media player isn't working because of their authetication mechanism
|
||||
* Fixed bug in recorder servlet. Actions for unpin and notes were mixed up
|
||||
* Recordings now start immediately for newly added models
|
||||
* Added confirmation dialog for "Pause All" and "Resume All"
|
||||
|
||||
3.8.6
|
||||
========================
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -70,6 +72,7 @@ import javafx.beans.value.ChangeListener;
|
|||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
|
@ -249,18 +252,34 @@ public class CamrecApplication extends Application {
|
|||
}
|
||||
}
|
||||
|
||||
// check for active recordings
|
||||
boolean shutdownNow = false;
|
||||
try {
|
||||
if (!recorder.getCurrentlyRecording().isEmpty()) {
|
||||
ButtonType result = Dialogs.showShutdownDialog(primaryStage.getScene());
|
||||
if(result == ButtonType.NO) {
|
||||
return;
|
||||
} else if(result == ButtonType.YES) {
|
||||
shutdownNow = true;
|
||||
}
|
||||
}
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException ex) {
|
||||
LOG.warn("Couldn't check, if recordings are running");
|
||||
}
|
||||
|
||||
Alert shutdownInfo = new AutosizeAlert(Alert.AlertType.INFORMATION, primaryStage.getScene());
|
||||
shutdownInfo.setTitle("Shutdown");
|
||||
shutdownInfo.setContentText("Shutting down. Please wait while recordings are finished...");
|
||||
shutdownInfo.show();
|
||||
|
||||
final boolean immediately = shutdownNow;
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
modelsTab.saveState();
|
||||
recordingsTab.saveState();
|
||||
onlineMonitor.shutdown();
|
||||
recorder.shutdown();
|
||||
recorder.shutdown(immediately);
|
||||
for (Site site : sites) {
|
||||
if(site.isEnabled()) {
|
||||
site.shutdown();
|
||||
|
|
|
@ -11,6 +11,7 @@ import javafx.geometry.Insets;
|
|||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Dialog;
|
||||
import javafx.scene.control.TextArea;
|
||||
|
@ -112,4 +113,19 @@ public class Dialogs {
|
|||
confirm.showAndWait();
|
||||
return confirm.getResult() == ButtonType.YES;
|
||||
}
|
||||
|
||||
public static ButtonType showShutdownDialog(Scene parent) {
|
||||
String message = "There are recordings in progress";
|
||||
AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO);
|
||||
confirm.setTitle("Shutdown");
|
||||
confirm.setHeaderText(message);
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setText("Shutdown Now");
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setDefaultButton(false);
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.FINISH)).setText("Shutdown Gracefully");
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.FINISH)).setDefaultButton(true);
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.NO)).setText("Keep Running");
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.NO)).setDefaultButton(false);
|
||||
confirm.showAndWait();
|
||||
return confirm.getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -410,63 +410,65 @@ public class NextGenLocalRecorder implements Recorder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
public void shutdown(boolean immediately) {
|
||||
// TODO add a config flag for waitign or stopping immediately
|
||||
LOG.info("Shutting down");
|
||||
recording = false;
|
||||
|
||||
LOG.debug("Stopping all recording processes");
|
||||
recorderLock.lock();
|
||||
try {
|
||||
// make a copy to avoid ConcurrentModificationException
|
||||
List<Recording> toStop = new ArrayList<>(recordingProcesses.values());
|
||||
if (!toStop.isEmpty()) {
|
||||
ExecutorService shutdownPool = Executors.newFixedThreadPool(toStop.size());
|
||||
List<Future<?>> shutdownFutures = new ArrayList<>(toStop.size());
|
||||
for (Recording rec : toStop) {
|
||||
Optional.ofNullable(rec.getDownload()).ifPresent(d -> {
|
||||
shutdownFutures.add(shutdownPool.submit(() -> d.stop()));
|
||||
});
|
||||
if (!immediately) {
|
||||
LOG.debug("Stopping all recording processes");
|
||||
recorderLock.lock();
|
||||
try {
|
||||
// make a copy to avoid ConcurrentModificationException
|
||||
List<Recording> toStop = new ArrayList<>(recordingProcesses.values());
|
||||
if (!toStop.isEmpty()) {
|
||||
ExecutorService shutdownPool = Executors.newFixedThreadPool(toStop.size());
|
||||
List<Future<?>> shutdownFutures = new ArrayList<>(toStop.size());
|
||||
for (Recording rec : toStop) {
|
||||
Optional.ofNullable(rec.getDownload()).ifPresent(d -> {
|
||||
shutdownFutures.add(shutdownPool.submit(() -> d.stop()));
|
||||
});
|
||||
}
|
||||
shutdownPool.shutdown();
|
||||
try {
|
||||
shutdownPool.awaitTermination(10, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
shutdownPool.shutdown();
|
||||
try {
|
||||
shutdownPool.awaitTermination(10, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
recorderLock.unlock();
|
||||
}
|
||||
|
||||
// wait for downloads to finish
|
||||
LOG.info("Waiting for downloads to finish");
|
||||
for (int i = 0; i < 60; i++) {
|
||||
if (!recordingProcesses.isEmpty()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Error while waiting for downloads to finish", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
recorderLock.unlock();
|
||||
}
|
||||
|
||||
// wait for downloads to finish
|
||||
LOG.info("Waiting for downloads to finish");
|
||||
for (int i = 0; i < 60; i++) {
|
||||
if (!recordingProcesses.isEmpty()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Error while waiting for downloads to finish", e);
|
||||
}
|
||||
// shutdown threadpools
|
||||
try {
|
||||
LOG.info("Shutting down download pool");
|
||||
downloadPool.shutdown();
|
||||
client.shutdown();
|
||||
downloadPool.awaitTermination(1, TimeUnit.MINUTES);
|
||||
LOG.info("Shutting down post-processing pool");
|
||||
ppPool.shutdown();
|
||||
int minutesToWait = 10;
|
||||
LOG.info("Waiting {} minutes (max) for post-processing to finish", minutesToWait);
|
||||
ppPool.awaitTermination(minutesToWait, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Error while waiting for pools to finish", e);
|
||||
}
|
||||
}
|
||||
|
||||
// shutdown threadpools
|
||||
try {
|
||||
LOG.info("Shutting down download pool");
|
||||
downloadPool.shutdown();
|
||||
client.shutdown();
|
||||
downloadPool.awaitTermination(1, TimeUnit.MINUTES);
|
||||
LOG.info("Shutting down post-processing pool");
|
||||
ppPool.shutdown();
|
||||
int minutesToWait = 10;
|
||||
LOG.info("Waiting {} minutes (max) for post-processing to finish", minutesToWait);
|
||||
ppPool.awaitTermination(minutesToWait, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Error while waiting for pools to finish", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,7 +52,7 @@ public interface Recorder {
|
|||
*/
|
||||
public void unpin(Recording recording) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||
|
||||
public void shutdown();
|
||||
public void shutdown(boolean immediately);
|
||||
|
||||
public void suspendRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||
public void resumeRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||
|
@ -66,7 +66,7 @@ public interface Recorder {
|
|||
public List<Model> getOnlineModels();
|
||||
|
||||
/**
|
||||
* Returns only the models from getModels(), which are actually recorded right now
|
||||
* Returns only the models from getModels(), which are actually recorded right now (a recording process is currently running).
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws IllegalStateException
|
||||
|
|
|
@ -175,7 +175,7 @@ public class RemoteRecorder implements Recorder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
public void shutdown(boolean immediately) {
|
||||
syncThread.stopThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ public class HttpServer {
|
|||
onlineMonitor.shutdown();
|
||||
}
|
||||
if (recorder != null) {
|
||||
recorder.shutdown();
|
||||
recorder.shutdown(false);
|
||||
}
|
||||
try {
|
||||
server.stop();
|
||||
|
|
Loading…
Reference in New Issue