From 7bb33568cf52a269ca9d866823bd1b870bfdae01 Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Fri, 21 Aug 2020 17:09:07 +0200 Subject: [PATCH] Add new event for when the disk space is exhausted --- CHANGELOG.md | 7 +++++- .../ui/settings/ActionSettingsPanel.java | 21 +++++++++++++++- .../ctbrec/ui/settings/ListSelectionPane.java | 4 +++ common/src/main/java/ctbrec/event/Event.java | 7 +++++- .../java/ctbrec/event/MatchAllPredicate.java | 17 +++++++++++++ .../java/ctbrec/event/NoSpaceLeftEvent.java | 25 +++++++++++++++++++ .../ctbrec/recorder/NextGenLocalRecorder.java | 4 ++- .../java/ctbrec/recorder/RemoteRecorder.java | 13 ++++++++++ .../recorder/server/RecorderServlet.java | 2 ++ 9 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 common/src/main/java/ctbrec/event/MatchAllPredicate.java create mode 100644 common/src/main/java/ctbrec/event/NoSpaceLeftEvent.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d9bec8e..a44639de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,13 @@ * login / favorites * media player isn't working because of their authetication mechanism * Fixed bug in recorder servlet. Actions for unpin and notes were mixed up + and not properly synchronized between the server and the client * Recordings now start immediately for newly added models -* Added confirmation dialog for "Pause All" and "Resume All" +* Added confirmation dialog for "Pause All", "Resume All" and shutdown +* Fix: recording started event was not fired in client / server mode +* CTB Recorder now stops recording, if less than 100 MiB space is left +* New event, which is fired, if the disk is full (or less than the configured + threshold is available) 3.8.6 ======================== diff --git a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java index 6e945d46..8ef600e4 100644 --- a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java +++ b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java @@ -23,6 +23,7 @@ import ctbrec.event.EventHandlerConfiguration; import ctbrec.event.EventHandlerConfiguration.ActionConfiguration; import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration; import ctbrec.event.ExecuteProgram; +import ctbrec.event.MatchAllPredicate; import ctbrec.event.ModelPredicate; import ctbrec.event.ModelStatePredicate; import ctbrec.event.RecordingStatePredicate; @@ -152,6 +153,11 @@ public class ActionSettingsPanel extends GridPane { pc.getConfiguration().put("state", recordingState.getValue().name()); pc.setName("state = " + recordingState.getValue().toString()); config.getPredicates().add(pc); + } else if(event.getValue() == Event.Type.NO_SPACE_LEFT) { + PredicateConfiguration pc = new PredicateConfiguration(); + pc.setType(MatchAllPredicate.class.getName()); + pc.setName("no space left"); + config.getPredicates().add(pc); } if(!modelSelectionPane.isAllSelected()) { PredicateConfiguration pc = new PredicateConfiguration(); @@ -200,7 +206,7 @@ public class ActionSettingsPanel extends GridPane { if(event.getValue() == Event.Type.RECORDING_STATUS_CHANGED && recordingState.getValue() == null) { throw new IllegalStateException("Select a state"); } - if(modelSelectionPane.getSelectedItems().isEmpty() && !modelSelectionPane.isAllSelected()) { + if(event.getValue() != Event.Type.NO_SPACE_LEFT && modelSelectionPane.getSelectedItems().isEmpty() && !modelSelectionPane.isAllSelected()) { throw new IllegalStateException("Select one or more models or tick off \"all\""); } if(!(showNotification.isSelected() || playSound.isSelected() || executeProgram.isSelected())) { @@ -231,10 +237,23 @@ public class ActionSettingsPanel extends GridPane { event.getItems().clear(); event.getItems().add(Event.Type.MODEL_STATUS_CHANGED); event.getItems().add(Event.Type.RECORDING_STATUS_CHANGED); + event.getItems().add(Event.Type.NO_SPACE_LEFT); event.setOnAction(evt -> modelState.setVisible(event.getSelectionModel().getSelectedItem() == Event.Type.MODEL_STATUS_CHANGED)); event.getSelectionModel().select(Event.Type.MODEL_STATUS_CHANGED); layout.add(event, 1, row++); + event.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> { + boolean modelRelatedStuffDisabled = false; + if(newV == Event.Type.NO_SPACE_LEFT) { + modelRelatedStuffDisabled = true; + modelSelectionPane.selectAll(); + } + + modelState.setDisable(modelRelatedStuffDisabled); + recordingState.setDisable(modelRelatedStuffDisabled); + modelSelectionPane.setDisable(modelRelatedStuffDisabled); + }); + layout.add(new Label("State"), 0, row); modelState.getItems().clear(); modelState.getItems().addAll(Model.State.values()); diff --git a/client/src/main/java/ctbrec/ui/settings/ListSelectionPane.java b/client/src/main/java/ctbrec/ui/settings/ListSelectionPane.java index e5cd9dc1..58c61824 100644 --- a/client/src/main/java/ctbrec/ui/settings/ListSelectionPane.java +++ b/client/src/main/java/ctbrec/ui/settings/ListSelectionPane.java @@ -118,4 +118,8 @@ public class ListSelectionPane> extends GridPane { public boolean isAllSelected() { return selectAll.isSelected(); } + + public void selectAll() { + selectAll.setSelected(true); + } } diff --git a/common/src/main/java/ctbrec/event/Event.java b/common/src/main/java/ctbrec/event/Event.java index 9e67d032..f5f00710 100644 --- a/common/src/main/java/ctbrec/event/Event.java +++ b/common/src/main/java/ctbrec/event/Event.java @@ -18,7 +18,12 @@ public abstract class Event { /** * This event is fired whenever the state of a recording changes. */ - RECORDING_STATUS_CHANGED("recording status changed"); + RECORDING_STATUS_CHANGED("recording status changed"), + + /** + * This event is fired when the disk space is exhausted + */ + NO_SPACE_LEFT("no space left"); private String desc; diff --git a/common/src/main/java/ctbrec/event/MatchAllPredicate.java b/common/src/main/java/ctbrec/event/MatchAllPredicate.java new file mode 100644 index 00000000..c9141893 --- /dev/null +++ b/common/src/main/java/ctbrec/event/MatchAllPredicate.java @@ -0,0 +1,17 @@ +package ctbrec.event; + +import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration; + +public class MatchAllPredicate extends EventPredicate { + + @Override + public boolean test(Event evt) { + return true; + } + + @Override + public void configure(PredicateConfiguration pc) { + // noop + } + +} diff --git a/common/src/main/java/ctbrec/event/NoSpaceLeftEvent.java b/common/src/main/java/ctbrec/event/NoSpaceLeftEvent.java new file mode 100644 index 00000000..1f6ecbb5 --- /dev/null +++ b/common/src/main/java/ctbrec/event/NoSpaceLeftEvent.java @@ -0,0 +1,25 @@ +package ctbrec.event; + +public class NoSpaceLeftEvent extends Event { + + @Override + public Type getType() { + return Type.NO_SPACE_LEFT; + } + + @Override + public String getName() { + return "No space left on device"; + } + + @Override + public String getDescription() { + return "No space left on device"; + } + + @Override + public String[] getExecutionParams() { + return new String[0]; + } + +} diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index 34f44cb4..f337c7c6 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -49,6 +49,7 @@ import ctbrec.Recording.State; import ctbrec.event.Event; import ctbrec.event.EventBusHolder; import ctbrec.event.ModelIsOnlineEvent; +import ctbrec.event.NoSpaceLeftEvent; import ctbrec.event.RecordingStateChangedEvent; import ctbrec.io.HttpClient; import ctbrec.recorder.download.Download; @@ -111,6 +112,7 @@ public class NextGenLocalRecorder implements Recorder { if (!recordingProcesses.isEmpty() && !enoughSpaceForRecording()) { LOG.info("No space left -> Stopping all recordings"); stopRecordingProcesses(); + EventBusHolder.BUS.post(new NoSpaceLeftEvent()); } } catch (IOException e) { LOG.error("Couldn't check space left on device", e); @@ -577,7 +579,7 @@ public class NextGenLocalRecorder implements Recorder { boolean enoughSpaceForRecording() throws IOException { long minimum = config.getSettings().minimumSpaceLeftInBytes; if (minimum == 0) { // 0 means don't check - return true; + return getFreeSpaceBytes() > 100 * 1024 * 1024; // leave at least 100 MiB free } else { return getFreeSpaceBytes() > minimum; } diff --git a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java index 4710e2ac..5cec3296 100644 --- a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java +++ b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java @@ -24,6 +24,7 @@ import ctbrec.Hmac; import ctbrec.Model; import ctbrec.Recording; import ctbrec.event.EventBusHolder; +import ctbrec.event.NoSpaceLeftEvent; import ctbrec.event.RecordingStateChangedEvent; import ctbrec.io.BandwidthMeter; import ctbrec.io.HttpClient; @@ -57,6 +58,7 @@ public class RemoteRecorder implements Recorder { private List sites; private long spaceTotal = -1; private long spaceFree = -1; + private boolean noSpaceLeftDetected = false; private Config config; private HttpClient client; @@ -184,6 +186,7 @@ public class RemoteRecorder implements Recorder { private static final String COULDNT_SYNCHRONIZE_WITH_SERVER = "Couldn't synchronize with server"; private static final String COULDNT_SYNCHRONIZE_WITH_SERVER_HTTP_STATUS = "Couldn't synchronize with server. HTTP status: {} - {}"; private volatile boolean running = false; + private static final long ONE_HUNDRED_MIB = 100 * 1024 * 1024; public SyncThread() { setName("RemoteRecorder SyncThread"); @@ -218,6 +221,16 @@ public class RemoteRecorder implements Recorder { long throughput = resp.getLong("throughput"); Duration timeframe = Duration.ofSeconds(resp.getInt("throughputTimeframe")); BandwidthMeter.setThroughput(throughput, timeframe); + long minimumSpaceLeftInBytes = resp.optLong("minimumSpaceLeftInBytes"); + if (minimumSpaceLeftInBytes > 0 && minimumSpaceLeftInBytes >= spaceFree + || minimumSpaceLeftInBytes == 0 && spaceFree < ONE_HUNDRED_MIB) { + if (!noSpaceLeftDetected) { + EventBusHolder.BUS.post(new NoSpaceLeftEvent()); + } + noSpaceLeftDetected = true; + } else { + noSpaceLeftDetected = false; + } } else { LOG.error(COULDNT_SYNCHRONIZE_WITH_SERVER_HTTP_STATUS, response.code(), json); } diff --git a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java index 0e8bf92f..d42478bd 100644 --- a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java +++ b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; +import ctbrec.Config; import ctbrec.Model; import ctbrec.Recording; import ctbrec.io.BandwidthMeter; @@ -211,6 +212,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { jsonResponse.put("spaceFree", recorder.getFreeSpaceBytes()); jsonResponse.put("throughput", BandwidthMeter.getThroughput()); jsonResponse.put("throughputTimeframe", BandwidthMeter.MEASURE_TIMEFRAME.getSeconds()); + jsonResponse.put("minimumSpaceLeftInBytes", Config.getInstance().getSettings().minimumSpaceLeftInBytes); resp.getWriter().write(jsonResponse.toString()); break; case "changePriority":