Fix loading of EventHandlerConfiguration

This commit is contained in:
0xb00bface 2023-11-01 18:02:11 +01:00
parent 33b054bc68
commit b268549ef6
4 changed files with 22 additions and 295 deletions

View File

@ -7,6 +7,7 @@ import ctbrec.StringUtil;
import ctbrec.event.*;
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
import ctbrec.io.json.mapper.ModelMapper;
import ctbrec.recorder.Recorder;
import ctbrec.ui.CamrecApplication;
import ctbrec.ui.DesktopIntegration;
@ -33,6 +34,7 @@ import javafx.scene.layout.Priority;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.mapstruct.factory.Mappers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,6 +50,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class ActionSettingsPanel extends GridPane {
private static final Logger LOG = LoggerFactory.getLogger(ActionSettingsPanel.class);
@ -168,7 +171,7 @@ public class ActionSettingsPanel extends GridPane {
if (!modelSelectionPane.isAllSelected()) {
var pc = new PredicateConfiguration();
pc.setType(ModelPredicate.class.getName());
pc.setModels(modelSelectionPane.getSelectedItems());
pc.setModels(modelSelectionPane.getSelectedItems().stream().map(Mappers.getMapper(ModelMapper.class)::toDto).collect(Collectors.toList())); // NOSONAR
pc.setName("model is one of:" + modelSelectionPane.getSelectedItems());
config.getPredicates().add(pc);
}

View File

@ -1,9 +1,13 @@
package ctbrec.event;
import ctbrec.Model;
import ctbrec.io.json.dto.ModelDto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.*;
@Data
@EqualsAndHashCode(of = "id")
public class EventHandlerConfiguration {
private String id;
@ -16,111 +20,25 @@ public class EventHandlerConfiguration {
id = UUID.randomUUID().toString();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Event.Type getEvent() {
return event;
}
public void setEvent(Event.Type event) {
this.event = event;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<PredicateConfiguration> getPredicates() {
return predicates;
}
public void setPredicates(List<PredicateConfiguration> predicates) {
this.predicates = predicates;
}
public List<ActionConfiguration> getActions() {
return actions;
}
public void setActions(List<ActionConfiguration> actions) {
this.actions = actions;
}
@Data
public static class PredicateConfiguration {
private String name;
private String type;
private List<Model> models;
private List<ModelDto> models;
private Map<String, Object> configuration = new HashMap<>();
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, Object> getConfiguration() {
return configuration;
}
public void setConfiguration(Map<String, Object> configuration) {
this.configuration = configuration;
}
public List<Model> getModels() {
return models;
}
public void setModels(List<Model> models) {
this.models = models;
}
@Override
public String toString() {
return name;
}
}
@Data
public static class ActionConfiguration {
private String name;
private String type;
private Map<String, Object> configuration = new HashMap<>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, Object> getConfiguration() {
return configuration;
}
public void setConfiguration(Map<String, Object> configuration) {
this.configuration = configuration;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
@ -131,26 +49,4 @@ public class EventHandlerConfiguration {
public String toString() {
return name + ", when:" + predicates + " do:" + actions + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EventHandlerConfiguration other = (EventHandlerConfiguration) obj;
if (id == null) {
return other.id == null;
} else return id.equals(other.id);
}
}

View File

@ -1,17 +1,20 @@
package ctbrec.event;
import ctbrec.Model;
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
import ctbrec.io.json.mapper.ModelMapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import ctbrec.Model;
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
public class ModelPredicate extends EventPredicate {
private Predicate<Event> internal;
public ModelPredicate() {}
public ModelPredicate() {
}
public ModelPredicate(Model model) {
internal = createFor(model);
@ -22,7 +25,7 @@ public class ModelPredicate extends EventPredicate {
}
private void configure(List<Model> models) {
if(models.isEmpty()) {
if (models.isEmpty()) {
throw new IllegalArgumentException("List has to contain at least one model");
}
@ -40,8 +43,7 @@ public class ModelPredicate extends EventPredicate {
private Predicate<Event> createFor(Model model) {
return evt -> {
if(evt instanceof AbstractModelEvent) {
AbstractModelEvent modelEvent = (AbstractModelEvent) evt;
if (evt instanceof AbstractModelEvent modelEvent) {
Model other = modelEvent.getModel();
return Objects.equals(model, other);
} else {
@ -52,6 +54,6 @@ public class ModelPredicate extends EventPredicate {
@Override
public void configure(PredicateConfiguration pc) {
configure(pc.getModels());
configure(pc.getModels().stream().map(Mappers.getMapper(ModelMapper.class)::toModel).toList());
}
}

View File

@ -1,174 +0,0 @@
package ctbrec.recorder.download.hls;
import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.OS;
import ctbrec.Recording;
import ctbrec.io.HttpClient;
import ctbrec.io.StreamRedirector;
import ctbrec.recorder.download.ProcessExitedUncleanException;
import ctbrec.recorder.download.hls.SegmentPlaylist.Segment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
/**
* Does the whole HLS download with FFmpeg. Not used at the moment, because FFMpeg can't
* handle the HLS encryption of Flirt4Free correctly
*/
public class FFmpegDownload extends AbstractHlsDownload {
private static final transient Logger LOG = LoggerFactory.getLogger(FFmpegDownload.class);
private transient Process ffmpeg;
private File targetFile;
public FFmpegDownload(HttpClient client) {
super(client);
}
@Override
public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException {
super.init(config, model, startTime, executorService);
String suffix = config.getSettings().ffmpegFileSuffix;
targetFile = config.getFileForRecording(model, suffix, startTime);
}
@Override
public FFmpegDownload call() throws IOException {
try {
Files.createDirectories(targetFile.getParentFile().toPath());
String chunkPlaylist = getSegmentPlaylistUrl(model);
String[] args = config.getSettings().ffmpegMergedDownloadArgs.split(" ");
String[] argsPlusFile = new String[args.length + 5];
int i = 0;
argsPlusFile[i++] = "-headers";
argsPlusFile[i++] = "User-Agent: " + config.getSettings().httpUserAgent;
argsPlusFile[i++] = "-i";
argsPlusFile[i++] = chunkPlaylist;
System.arraycopy(args, 0, argsPlusFile, i, args.length);
argsPlusFile[argsPlusFile.length - 1] = targetFile.getAbsolutePath();
String[] cmdline = OS.getFFmpegCommand(argsPlusFile);
LOG.debug("Command line: {}", Arrays.toString(cmdline));
ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], targetFile.getParentFile());
int exitCode = 1;
File ffmpegLog = File.createTempFile(targetFile.getName(), ".log");
ffmpegLog.deleteOnExit();
try (FileOutputStream mergeLogStream = new FileOutputStream(ffmpegLog)) {
Thread stdout = new Thread(new StreamRedirector(ffmpeg.getInputStream(), mergeLogStream));
Thread stderr = new Thread(new StreamRedirector(ffmpeg.getErrorStream(), mergeLogStream));
stdout.start();
stderr.start();
exitCode = ffmpeg.waitFor();
stdout.join();
stderr.join();
mergeLogStream.flush();
}
if (exitCode == 0) {
if (ffmpegLog.exists()) {
Files.delete(ffmpegLog.toPath());
}
} else {
LOG.info("FFmpeg exit code was {}. Logfile: {}", exitCode, ffmpegLog.getAbsolutePath());
throw new ProcessExitedUncleanException("FFmpeg exit code was " + exitCode);
}
} catch (InterruptedException e) {
LOG.error("Thread interrupted while waiting for FFmpeg to terminate");
Thread.currentThread().interrupt();
} catch (ExecutionException | ParseException | PlaylistException | JAXBException e) {
LOG.error("Couldn't start FFmpeg process for stream download", e);
}
return this;
}
@Override
public void stop() {
if (ffmpeg != null && ffmpeg.isAlive()) {
OutputStream ffmpegStdIn = ffmpeg.getOutputStream();
try {
ffmpegStdIn.write("q".getBytes(StandardCharsets.UTF_8));
ffmpegStdIn.flush();
ffmpegStdIn.close();
} catch (IOException e) {
LOG.error("Couldn't terminate FFmpeg by sending 'q'", e);
ffmpeg.destroy();
}
}
}
@Override
public Model getModel() {
return model;
}
@Override
public void postProcess(Recording recording) {
// nothing to here for now
}
@Override
public File getTarget() {
return targetFile;
}
@Override
public String getPath(Model model) {
String absolutePath = getTarget().getAbsolutePath();
String recordingsDir = Config.getInstance().getSettings().recordingsDir;
String relativePath = absolutePath.replaceFirst(Pattern.quote(recordingsDir), "");
return relativePath;
}
@Override
protected void internalStop() {
stop();
}
@Override
public boolean isSingleFile() {
return true;
}
@Override
public long getSizeInByte() {
return getTarget().length();
}
protected void createTargetDirectory() throws IOException {
// TODO Auto-generated method stub
}
@Override
protected void execute(SegmentDownload segmentDownload) {
// TODO Auto-generated method stub
}
@Override
protected OutputStream getSegmentOutputStream(Segment segment) throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public void finalizeDownload() {
// TODO Auto-generated method stub
}
}