Fix server stuff for new recording path handling

This commit is contained in:
0xb00bface 2020-09-13 19:54:43 +02:00
parent 4f526fd13e
commit 90192d9b8f
7 changed files with 75 additions and 36 deletions

View File

@ -230,5 +230,15 @@ public class JavaFxRecording extends Recording {
delegate.setAbsoluteFile(absoluteFile);
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public void setId(String id) {
delegate.setId(id);
}
}

View File

@ -19,7 +19,6 @@ import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -72,9 +71,6 @@ public class Recording implements Serializable {
}
public String getId() {
if (id == null) {
id = UUID.randomUUID().toString();
}
return id;
}

View File

@ -281,6 +281,7 @@ public class NextGenLocalRecorder implements Recorder {
private Recording createRecording(Download download) throws IOException {
Model model = download.getModel();
Recording rec = new Recording();
rec.setId(UUID.randomUUID().toString());
rec.setDownload(download);
String recordingFile = download.getPath(model).replaceAll("\\\\", "/");
File absoluteFile = new File(config.getSettings().recordingsDir, recordingFile);

View File

@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
@ -82,6 +83,10 @@ public class RecordingManager {
if (recording.getStatus() == RECORDING || recording.getStatus() == GENERATING_PLAYLIST || recording.getStatus() == POST_PROCESSING) {
recording.setStatus(WAITING);
}
if (recording.getId() == null) {
recording.setId(UUID.randomUUID().toString());
saveRecording(recording);
}
if (recordingExists(recording)) {
recordings.add(recording);
} else {

View File

@ -9,6 +9,8 @@ import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -20,6 +22,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.Recording;
import ctbrec.recorder.Recorder;
public class HlsServlet extends AbstractCtbrecServlet {
@ -27,50 +31,69 @@ public class HlsServlet extends AbstractCtbrecServlet {
private final Config config;
public HlsServlet(Config config) {
private Recorder recorder;
public HlsServlet(Config config, Recorder recorder) {
this.config = config;
this.recorder = recorder;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String contextPath = getServletContext().getContextPath();
String request = req.getRequestURI().substring(contextPath.length() + 5);
Path recordingsDirPath = Paths.get(config.getSettings().recordingsDir).toAbsolutePath().normalize();
Path requestedFilePath = recordingsDirPath.resolve(request).toAbsolutePath().normalize();
boolean isValidRequestedPath = requestedFilePath.startsWith(recordingsDirPath);
if (isValidRequestedPath) {
File requestedFile = requestedFilePath.toFile();
File requestedFile = requestedFilePath.toFile();
try {
if (requestedFile.getName().equals("playlist.m3u8")) {
try {
boolean isRequestAuthenticated = checkAuthentication(req, req.getRequestURI());
if (!isRequestAuthenticated) {
writeResponse(resp, SC_UNAUTHORIZED, "{\"status\": \"error\", \"msg\": \"HMAC does not match\"}");
return;
}
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
writeResponse(resp, SC_UNAUTHORIZED, "{\"status\": \"error\", \"msg\": \"Authentication failed\"}");
boolean isRequestAuthenticated = checkAuthentication(req, req.getRequestURI());
if (!isRequestAuthenticated) {
writeResponse(resp, SC_UNAUTHORIZED, "{\"status\": \"error\", \"msg\": \"HMAC does not match\"}");
return;
}
servePlaylist(req, resp, requestedFile);
} else {
if (requestedFile.exists()) {
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
LOG.trace("{}: {}", header, req.getHeader(header));
}
serveSegment(req, resp, requestedFile);
String id = request.substring(0, request.indexOf('/'));
Optional<Recording> rec = getRecordingById(id);
if (rec.isPresent()) {
servePlaylist(req, resp, rec.get().getAbsoluteFile());
} else {
error404(req, resp);
return;
}
} else {
String id = request.split("/")[0];
Optional<Recording> rec = getRecordingById(id);
if (rec.isPresent()) {
File file = rec.get().getAbsoluteFile();
if (LOG.isTraceEnabled()) {
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
LOG.trace("{}: {}", header, req.getHeader(header));
}
}
serveSegment(req, resp, file);
} else {
error404(req, resp);
return;
}
}
} else {
writeResponse(resp, SC_FORBIDDEN, "Stop it!");
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
writeResponse(resp, SC_UNAUTHORIZED, "{\"status\": \"error\", \"msg\": \"Authentication failed\"}");
return;
}
}
private Optional<Recording> getRecordingById(String id) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
return recorder.getRecordings().stream()
.filter(r -> Objects.equals(id, r.getId()))
.findFirst();
}
private void writeResponse(HttpServletResponse resp, int code, String body) {
try {
resp.setStatus(code);
@ -81,6 +104,7 @@ public class HlsServlet extends AbstractCtbrecServlet {
}
private void error404(HttpServletRequest req, HttpServletResponse resp) {
writeResponse(resp, SC_NOT_FOUND, "{\"status\": \"error\", \"msg\": \"Recording not found\"}");
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
@ -90,7 +114,9 @@ public class HlsServlet extends AbstractCtbrecServlet {
}
private void servePlaylist(HttpServletRequest req, HttpServletResponse resp, File requestedFile) throws IOException {
serveFile(req, resp, requestedFile, "application/x-mpegURL");
LOG.debug("Serving playlist {}", requestedFile);
File playlist = new File(requestedFile, "playlist.m3u8");
serveFile(req, resp, playlist, "application/x-mpegURL");
}
private void serveFile(HttpServletRequest req, HttpServletResponse resp, File file, String contentType) throws IOException {
@ -103,6 +129,7 @@ public class HlsServlet extends AbstractCtbrecServlet {
byte[] buffer = new byte[1024 * 100];
long bytesLeft = range.to - range.from;
resp.setContentLengthLong(bytesLeft);
resp.addHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
if (range.set) {
resp.setHeader("Content-Range", "bytes " + range.from + '-' + range.to + '/' + file.length());
}

View File

@ -213,7 +213,7 @@ public class HttpServer {
holder = new ServletHolder(configServlet);
defaultContext.addServlet(holder, "/config");
HlsServlet hlsServlet = new HlsServlet(this.config);
HlsServlet hlsServlet = new HlsServlet(this.config, recorder);
holder = new ServletHolder(hlsServlet);
defaultContext.addServlet(holder, "/hls/*");

View File

@ -1,5 +1,5 @@
function play(recording) {
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
let src = recording.singleFile ? '/hls/' + recording.id : recording.playlist;
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
src = '..' + src;
if(console) console.log("Path", src, "HMAC", hmacOfPath);
@ -48,7 +48,7 @@ function play(recording) {
}
function download(recording) {
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
let src = recording.singleFile ? '/hls/' + recording.id : recording.playlist;
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
src = '..' + src;
if(console) console.log("Path", src, "HMAC", hmacOfPath);
@ -77,7 +77,7 @@ function calculateSize(sizeInByte) {
function isRecordingInArray(array, recording) {
for ( let idx in array) {
let r = array[idx];
if (r.path === recording.path) {
if (r.id === recording.id) {
return true;
}
}
@ -115,10 +115,10 @@ function syncRecordings(recordings) {
recording.ko_progressString = ko.observable(recording.progress === -1 ? '' : recording.progress);
recording.ko_size = ko.observable(calculateSize(recording.sizeInByte));
recording.ko_status = ko.observable(recording.status);
if (recording.path.endsWith('.mp4')) {
recording.playlist = '/hls' + recording.path;
if (recording.singleFile) {
recording.playlist = '/hls/' + recording.id;
} else {
recording.playlist = '/hls' + recording.path + '/playlist.m3u8';
recording.playlist = '/hls/' + recording.id + '/playlist.m3u8';
}
observableRecordingsArray.push(recording);
}
@ -129,7 +129,7 @@ function syncRecordings(recordings) {
let recording = recordings[i];
for ( let j in observableRecordingsArray()) {
let r = observableRecordingsArray()[j];
if (recording.path === r.path) {
if (recording.id === r.id) {
r.progress = recording.progress;
r.sizeInByte = recording.sizeInByte;
r.status = recording.status;