Add GUI and remote support for temporary recordings
This commit is contained in:
parent
729319dfd2
commit
e55daa0772
|
@ -16,6 +16,7 @@ import javafx.scene.control.Dialog;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
@ -87,6 +88,23 @@ public class Dialogs {
|
||||||
return dialog.showAndWait();
|
return dialog.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean showCustomInput(Scene parent, String title, Region region) {
|
||||||
|
Dialog<?> dialog = new Dialog<>();
|
||||||
|
dialog.setTitle(title);
|
||||||
|
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||||
|
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||||
|
dialog.setResizable(true);
|
||||||
|
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
|
||||||
|
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||||
|
stage.getIcons().add(new Image(icon));
|
||||||
|
if (parent != null) {
|
||||||
|
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
|
||||||
|
}
|
||||||
|
dialog.getDialogPane().setContent(region);
|
||||||
|
dialog.showAndWait();
|
||||||
|
return dialog.getResult() == ButtonType.OK;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean showConfirmDialog(String title, String message, String header, Scene parent) {
|
public static boolean showConfirmDialog(String title, String message, String header, Scene parent) {
|
||||||
AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO);
|
AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO);
|
||||||
confirm.setTitle(title);
|
confirm.setTitle(title);
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package ctbrec.ui.tabs;
|
package ctbrec.ui.tabs;
|
||||||
|
|
||||||
|
import static ctbrec.SubsequentAction.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -25,6 +29,7 @@ import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
|
import ctbrec.SubsequentAction;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import ctbrec.ui.AutosizeAlert;
|
import ctbrec.ui.AutosizeAlert;
|
||||||
|
@ -59,8 +64,10 @@ import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.DatePicker;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.control.RadioButton;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.control.SelectionMode;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
|
@ -71,6 +78,7 @@ import javafx.scene.control.TableColumn.SortType;
|
||||||
import javafx.scene.control.TableRow;
|
import javafx.scene.control.TableRow;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
@ -84,6 +92,7 @@ import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.FlowPane;
|
import javafx.scene.layout.FlowPane;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
|
@ -612,6 +621,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
pauseRecording.setOnAction(e -> pauseRecording(selectedModels));
|
pauseRecording.setOnAction(e -> pauseRecording(selectedModels));
|
||||||
MenuItem resumeRecording = new MenuItem("Resume Recording");
|
MenuItem resumeRecording = new MenuItem("Resume Recording");
|
||||||
resumeRecording.setOnAction(e -> resumeRecording(selectedModels));
|
resumeRecording.setOnAction(e -> resumeRecording(selectedModels));
|
||||||
|
MenuItem stopRecordingAt = new MenuItem("Stop Recording at Date");
|
||||||
|
stopRecordingAt.setOnAction(e -> setStopDate(selectedModels.get(0)));
|
||||||
MenuItem openInBrowser = new MenuItem("Open in Browser");
|
MenuItem openInBrowser = new MenuItem("Open in Browser");
|
||||||
openInBrowser.setOnAction(e -> DesktopIntegration.open(selectedModels.get(0).getUrl()));
|
openInBrowser.setOnAction(e -> DesktopIntegration.open(selectedModels.get(0).getUrl()));
|
||||||
MenuItem openInPlayer = new MenuItem("Open in Player");
|
MenuItem openInPlayer = new MenuItem("Open in Player");
|
||||||
|
@ -630,6 +641,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
ContextMenu menu = new ContextMenu(stop);
|
ContextMenu menu = new ContextMenu(stop);
|
||||||
if (selectedModels.size() == 1) {
|
if (selectedModels.size() == 1) {
|
||||||
menu.getItems().add(selectedModels.get(0).isSuspended() ? resumeRecording : pauseRecording);
|
menu.getItems().add(selectedModels.get(0).isSuspended() ? resumeRecording : pauseRecording);
|
||||||
|
menu.getItems().add(stopRecordingAt);
|
||||||
} else {
|
} else {
|
||||||
menu.getItems().addAll(resumeRecording, pauseRecording);
|
menu.getItems().addAll(resumeRecording, pauseRecording);
|
||||||
}
|
}
|
||||||
|
@ -646,6 +658,46 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setStopDate(JavaFxModel model) {
|
||||||
|
DatePicker datePicker = new DatePicker();
|
||||||
|
GridPane grid = new GridPane();
|
||||||
|
grid.setHgap(10);
|
||||||
|
grid.setVgap(10);
|
||||||
|
grid.setPadding(new Insets(20, 150, 10, 10));
|
||||||
|
grid.add(new Label("Stop at"), 0, 0);
|
||||||
|
grid.add(datePicker, 1, 0);
|
||||||
|
grid.add(new Label("And then"), 0, 1);
|
||||||
|
ToggleGroup toggleGroup = new ToggleGroup();
|
||||||
|
RadioButton pauseButton = new RadioButton("pause recording");
|
||||||
|
pauseButton.setSelected(model.getRecordUntilSubsequentAction() == PAUSE);
|
||||||
|
pauseButton.setToggleGroup(toggleGroup);
|
||||||
|
RadioButton removeButton = new RadioButton("remove model");
|
||||||
|
removeButton.setSelected(model.getRecordUntilSubsequentAction() == REMOVE);
|
||||||
|
removeButton.setToggleGroup(toggleGroup);
|
||||||
|
HBox row = new HBox();
|
||||||
|
row.getChildren().addAll(pauseButton, removeButton);
|
||||||
|
HBox.setMargin(pauseButton, new Insets(5));
|
||||||
|
HBox.setMargin(removeButton, new Insets(5));
|
||||||
|
grid.add(row, 1, 1);
|
||||||
|
if (model.getRecordUntil().toEpochMilli() != Long.MAX_VALUE) {
|
||||||
|
LocalDate localDate = LocalDate.ofInstant(model.getRecordUntil(), ZoneId.systemDefault());
|
||||||
|
datePicker.setValue(localDate);
|
||||||
|
}
|
||||||
|
boolean userClickedOk = Dialogs.showCustomInput(getTabPane().getScene(), "Stop Recording at", grid);
|
||||||
|
if (userClickedOk) {
|
||||||
|
SubsequentAction action = pauseButton.isSelected() ? PAUSE : REMOVE;
|
||||||
|
LOG.info("Stop at {} and {}", datePicker.getValue(), action);
|
||||||
|
Instant stopAt = Instant.from(datePicker.getValue().atStartOfDay().atZone(ZoneId.systemDefault()));
|
||||||
|
model.setRecordUntil(stopAt);
|
||||||
|
model.setRecordUntilSubsequentAction(action);
|
||||||
|
try {
|
||||||
|
recorder.stopRecordingAt(model.getDelegate());
|
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||||
|
Dialogs.showError(getTabPane().getScene(), "Error", "Couln't set stop date", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ignore(ObservableList<JavaFxModel> selectedModels) {
|
private void ignore(ObservableList<JavaFxModel> selectedModels) {
|
||||||
for (JavaFxModel fxModel : selectedModels) {
|
for (JavaFxModel fxModel : selectedModels) {
|
||||||
Model modelToIgnore = fxModel.getDelegate();
|
Model modelToIgnore = fxModel.getDelegate();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.recorder;
|
package ctbrec.recorder;
|
||||||
|
|
||||||
|
import static ctbrec.SubsequentAction.*;
|
||||||
import static ctbrec.event.Event.Type.*;
|
import static ctbrec.event.Event.Type.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -10,6 +11,7 @@ import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -20,6 +22,7 @@ import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorCompletionService;
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
@ -42,7 +45,6 @@ import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.Recording.State;
|
import ctbrec.Recording.State;
|
||||||
import ctbrec.SubsequentAction;
|
|
||||||
import ctbrec.event.Event;
|
import ctbrec.event.Event;
|
||||||
import ctbrec.event.EventBusHolder;
|
import ctbrec.event.EventBusHolder;
|
||||||
import ctbrec.event.ModelIsOnlineEvent;
|
import ctbrec.event.ModelIsOnlineEvent;
|
||||||
|
@ -215,41 +217,14 @@ public class NextGenLocalRecorder implements Recorder {
|
||||||
recorderLock.lock();
|
recorderLock.lock();
|
||||||
try {
|
try {
|
||||||
checkRecordingPreconditions(model);
|
checkRecordingPreconditions(model);
|
||||||
|
|
||||||
LOG.info("Starting recording for model {}", model.getName());
|
LOG.info("Starting recording for model {}", model.getName());
|
||||||
Download download = model.createDownload();
|
Download download = createDownload(model);
|
||||||
download.init(config, model, Instant.now());
|
Recording rec = createRecording(download);
|
||||||
Objects.requireNonNull(download.getStartTime(),
|
completionService.submit(createDownloadJob(rec));
|
||||||
"At this point the download should have set a startTime. Make sure to set a startTime in " + download.getClass() + ".init()");
|
|
||||||
LOG.debug("Downloading with {}", download.getClass().getSimpleName());
|
|
||||||
|
|
||||||
Recording rec = createRecording(model, download);
|
|
||||||
completionService.submit(() -> {
|
|
||||||
try {
|
|
||||||
setRecordingStatus(rec, State.RECORDING);
|
|
||||||
model.setLastRecorded(rec.getStartDate());
|
|
||||||
recordingManager.saveRecording(rec);
|
|
||||||
download.start();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error("Download for {} failed. Download state: {}", model.getName(), rec.getStatus(), e);
|
|
||||||
}
|
|
||||||
boolean deleted = deleteIfEmpty(rec);
|
|
||||||
setRecordingStatus(rec, deleted ? State.DELETED : State.WAITING);
|
|
||||||
if (!deleted) {
|
|
||||||
// only save the status, if the recording has not been deleted, otherwise we recreate the metadata file
|
|
||||||
recordingManager.saveRecording(rec);
|
|
||||||
}
|
|
||||||
return rec;
|
|
||||||
});
|
|
||||||
} catch (RecordUntilExpiredException e) {
|
} catch (RecordUntilExpiredException e) {
|
||||||
LOG.info("Precondition not met to record {}: {}", model, e.getLocalizedMessage());
|
LOG.info("Precondition not met to record {}: {}", model, e.getLocalizedMessage());
|
||||||
executeRecordUntilSubsequentAction(model);
|
executeRecordUntilSubsequentAction(model);
|
||||||
} catch (PreconditionNotMetException e) {
|
} catch (PreconditionNotMetException e) {
|
||||||
// long now = System.currentTimeMillis();
|
|
||||||
// if ((now - lastSpaceMessage) > TimeUnit.MINUTES.toMillis(1)) {
|
|
||||||
// LOG.info("Not enough space for recording, not starting recording for {}", model);
|
|
||||||
// lastSpaceMessage = now;
|
|
||||||
// }
|
|
||||||
LOG.info("Precondition not met to record {}: {}", model, e.getLocalizedMessage());
|
LOG.info("Precondition not met to record {}: {}", model, e.getLocalizedMessage());
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -257,20 +232,53 @@ public class NextGenLocalRecorder implements Recorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeRecordUntilSubsequentAction(Model model) throws IOException {
|
private Download createDownload(Model model) {
|
||||||
if (model.getRecordUntilSubsequentAction() == SubsequentAction.PAUSE) {
|
Download download = model.createDownload();
|
||||||
model.setSuspended(true);
|
download.init(config, model, Instant.now());
|
||||||
} else if (model.getRecordUntilSubsequentAction() == SubsequentAction.REMOVE) {
|
Objects.requireNonNull(download.getStartTime(),
|
||||||
|
"At this point the download should have set a startTime. Make sure to set a startTime in " + download.getClass() + ".init()");
|
||||||
|
LOG.debug("Downloading with {}", download.getClass().getSimpleName());
|
||||||
|
return download;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Callable<Recording> createDownloadJob(Recording rec) {
|
||||||
|
return () -> {
|
||||||
try {
|
try {
|
||||||
LOG.info("Recording timeframe expired for model {} - {}", model, model.getRecordUntil());
|
setRecordingStatus(rec, State.RECORDING);
|
||||||
|
rec.getModel().setLastRecorded(rec.getStartDate());
|
||||||
|
recordingManager.saveRecording(rec);
|
||||||
|
rec.getDownload().start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Download for {} failed. Download state: {}", rec.getModel().getName(), rec.getStatus(), e);
|
||||||
|
}
|
||||||
|
boolean deleted = deleteIfEmpty(rec);
|
||||||
|
setRecordingStatus(rec, deleted ? State.DELETED : State.WAITING);
|
||||||
|
if (!deleted) {
|
||||||
|
// only save the status, if the recording has not been deleted, otherwise we recreate the metadata file
|
||||||
|
recordingManager.saveRecording(rec);
|
||||||
|
}
|
||||||
|
return rec;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeRecordUntilSubsequentAction(Model model) throws IOException {
|
||||||
|
if (model.getRecordUntilSubsequentAction() == PAUSE) {
|
||||||
|
model.setSuspended(true);
|
||||||
|
} else if (model.getRecordUntilSubsequentAction() == REMOVE) {
|
||||||
|
try {
|
||||||
|
LOG.info("Removing {} because the recording timeframe ended at {}", model, model.getRecordUntil().atZone(ZoneId.systemDefault()));
|
||||||
stopRecording(model);
|
stopRecording(model);
|
||||||
} catch (InvalidKeyException | NoSuchAlgorithmException e1) {
|
} catch (InvalidKeyException | NoSuchAlgorithmException e1) {
|
||||||
LOG.error("Error while stopping recording", e1);
|
LOG.error("Error while stopping recording", e1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// reset values, so that model can be recorded again
|
||||||
|
model.setRecordUntil(null);
|
||||||
|
model.setRecordUntilSubsequentAction(PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recording createRecording(Model model, Download download) throws IOException {
|
private Recording createRecording(Download download) throws IOException {
|
||||||
|
Model model = download.getModel();
|
||||||
Recording rec = new Recording();
|
Recording rec = new Recording();
|
||||||
rec.setDownload(download);
|
rec.setDownload(download);
|
||||||
rec.setPath(download.getPath(model).replaceAll("\\\\", "/"));
|
rec.setPath(download.getPath(model).replaceAll("\\\\", "/"));
|
||||||
|
@ -749,4 +757,31 @@ public class NextGenLocalRecorder implements Recorder {
|
||||||
rec.setNote(note);
|
rec.setNote(note);
|
||||||
recordingManager.saveRecording(rec);
|
recordingManager.saveRecording(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopRecordingAt(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||||
|
recorderLock.lock();
|
||||||
|
try {
|
||||||
|
int index = models.indexOf(model);
|
||||||
|
if (index >= 0) {
|
||||||
|
Model m = models.get(index);
|
||||||
|
m.setRecordUntil(model.getRecordUntil());
|
||||||
|
m.setRecordUntilSubsequentAction(model.getRecordUntilSubsequentAction());
|
||||||
|
config.save();
|
||||||
|
} else {
|
||||||
|
throw new NoSuchElementException("Model " + model.getName() + " [" + model.getUrl() + "] not found in list of recorded models");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recordingProcesses.containsKey(model)) {
|
||||||
|
Recording rec = recordingProcesses.get(model);
|
||||||
|
rec.getDownload().stop();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
recorderLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Instant.now().isAfter(model.getRecordUntil())) {
|
||||||
|
executeRecordUntilSubsequentAction(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ public interface Recorder {
|
||||||
public void startRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
public void startRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||||
|
|
||||||
public void stopRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
public void stopRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||||
|
public void stopRecordingAt(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||||
|
|
||||||
public void switchStreamSource(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
public void switchStreamSource(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,11 @@ public class RemoteRecorder implements Recorder {
|
||||||
sendRequest("stop", model);
|
sendRequest("stop", model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopRecordingAt(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||||
|
sendRequest("stopAt", model);
|
||||||
|
}
|
||||||
|
|
||||||
private void sendRequest(String action, Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
private void sendRequest(String action, Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||||
String payload = modelRequestAdapter.toJson(new ModelRequest(action, model));
|
String payload = modelRequestAdapter.toJson(new ModelRequest(action, model));
|
||||||
LOG.debug("Sending request to recording server: {}", payload);
|
LOG.debug("Sending request to recording server: {}", payload);
|
||||||
|
|
|
@ -96,6 +96,17 @@ public class RecorderServlet extends AbstractCtbrecServlet {
|
||||||
response = "{\"status\": \"success\", \"msg\": \"Stopping recording\"}";
|
response = "{\"status\": \"success\", \"msg\": \"Stopping recording\"}";
|
||||||
resp.getWriter().write(response);
|
resp.getWriter().write(response);
|
||||||
break;
|
break;
|
||||||
|
case "stopAt":
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
recorder.stopRecordingAt(request.model);
|
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
|
||||||
|
LOG.error("Couldn't stop recording for model {}", request.model, e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
response = "{\"status\": \"success\", \"msg\": \"Stopping recording\"}";
|
||||||
|
resp.getWriter().write(response);
|
||||||
|
break;
|
||||||
case "list":
|
case "list":
|
||||||
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of models\", \"models\": [");
|
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of models\", \"models\": [");
|
||||||
JsonAdapter<Model> modelAdapter = new ModelJsonAdapter();
|
JsonAdapter<Model> modelAdapter = new ModelJsonAdapter();
|
||||||
|
|
Loading…
Reference in New Issue