fix(maintainability): clean up reliability issues

This commit is contained in:
2026-06-25 20:36:39 +01:00
parent 5e00965baa
commit a7818fbebc
6 changed files with 22 additions and 16 deletions

View File

@@ -16,6 +16,7 @@ import java.util.Optional;
@RequestMapping("/api/v1/stream")
public class StreamController {
private static final Logger logger = LoggerFactory.getLogger(StreamController.class);
private static final String SUCCESS = "success";
private final StreamService streamService;
@@ -28,7 +29,7 @@ public class StreamController {
public ResponseEntity<APIResponse<Stream>> startStream(@RequestParam("name") String streamKey) {
logger.info("Stream start callback for key: {}", streamKey);
Stream stream = streamService.startStream(streamKey);
return ResponseEntity.ok(new APIResponse<>("success", "Stream started", stream));
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Stream started", stream));
}
// Called by nginx on_publish_done
@@ -36,26 +37,26 @@ public class StreamController {
public ResponseEntity<APIResponse<Void>> stopStream(@RequestParam("name") String streamKey) {
logger.info("Stream stop callback for key: {}", streamKey);
streamService.endStream(streamKey);
return ResponseEntity.ok(new APIResponse<>("success", "Stream ended", null));
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Stream ended", null));
}
// Called by nginx on_update
@PostMapping("/heartbeat")
public ResponseEntity<APIResponse<Void>> heartbeat(@RequestParam("name") String streamKey) {
streamService.heartbeatStream(streamKey);
return ResponseEntity.ok(new APIResponse<>("success", "Heartbeat recorded", null));
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Heartbeat recorded", null));
}
@GetMapping("/history/{userId}")
public ResponseEntity<APIResponse<List<Stream>>> getStreamHistory(@PathVariable Long userId) {
List<Stream> history = streamService.getStreamHistory(userId);
return ResponseEntity.ok(new APIResponse<>("success", "Stream history retrieved", history));
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Stream history retrieved", history));
}
@GetMapping("/current")
public ResponseEntity<APIResponse<StreamResponse>> getCurrentStream() {
Optional<Stream> stream = streamService.getActiveStream();
return stream.map(value -> ResponseEntity.ok(new APIResponse<>("success",
return stream.map(value -> ResponseEntity.ok(new APIResponse<>(SUCCESS,
"Streaming status retrieved",
new StreamResponse(true, value.getId())))).orElseGet(() -> ResponseEntity.ok(new APIResponse<>("success",
"Streaming status retrieved",

View File

@@ -20,6 +20,7 @@ public class UserController {
@Value("${jwt.expiration}")
private long jwtExpiration;
private static final String SUCCESS = "success";
public UserController(UserService userService) {
this.userService = userService;
@@ -34,7 +35,7 @@ public class UserController {
}
return ResponseEntity.ok(
new APIResponse<>("success", "User retrieved successfully", user.get())
new APIResponse<>(SUCCESS, "User retrieved successfully", user.get())
);
}
@@ -54,7 +55,7 @@ public class UserController {
response.addHeader("Set-Cookie", cookie.toString());
return ResponseEntity.ok(
new APIResponse<>("success", "Logged in successfully", new Token(jwt))
new APIResponse<>(SUCCESS, "Logged in successfully", new Token(jwt))
);
}
@@ -71,7 +72,7 @@ public class UserController {
response.addHeader("Set-Cookie", cookie.toString());
return ResponseEntity.ok(
new APIResponse<>("success", "Logged out successfully", null)
new APIResponse<>(SUCCESS, "Logged out successfully", null)
);
}
}

View File

@@ -16,7 +16,6 @@ import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service
@@ -215,7 +214,7 @@ public class MediaService {
return segMs < endMs && (segMs + HLS_SEGMENT_LENGTH * 1000) > startMs;
})
.sorted(Comparator.comparingLong(this::parseTimestampMs))
.collect(Collectors.toList());
.toList();
}
}

View File

@@ -28,6 +28,8 @@ public class UserService {
private final UserRepository userRepository;
private final JwtService jwtService;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
public UserService(UserRepository userRepository,
JwtService jwtService,
@Value("${google.client.id}") String googleClientId) {
@@ -116,7 +118,7 @@ public class UserService {
private String generateStreamKey() {
byte[] bytes = new byte[24];
new SecureRandom().nextBytes(bytes);
SECURE_RANDOM.nextBytes(bytes);
return HexFormat.of().formatHex(bytes);
}
}

View File

@@ -20,6 +20,8 @@ import java.util.concurrent.Future;
public class MetadataService {
private static final Logger logger = LoggerFactory.getLogger(MetadataService.class);
private static final String DURATION = "duration";
@Async("ffmpegTaskExecutor")
public Future<ClipOptions> getVideoMetadata(Path file) {
logger.info("Getting metadata for file {}", file);
@@ -78,8 +80,8 @@ public class MetadataService {
}
private Float extractDuration(JsonNode streamNode) {
if (streamNode.has("duration")) {
return Float.valueOf(streamNode.get("duration").asText());
if (streamNode.has(DURATION)) {
return Float.valueOf(streamNode.get(DURATION).asText());
}
throw new FFMPEGException("ffprobe duration missing");
@@ -115,8 +117,8 @@ public class MetadataService {
}
private void extractEndPointFromFormat(ClipOptions metadata, JsonNode formatNode) {
if (formatNode != null && formatNode.has("duration") && metadata.getDuration() == null) {
metadata.setDuration(Float.parseFloat(formatNode.get("duration").asText()));
if (formatNode != null && formatNode.has(DURATION) && metadata.getDuration() == null) {
metadata.setDuration(Float.parseFloat(formatNode.get(DURATION).asText()));
}
}

View File

@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -75,7 +76,7 @@ public class StreamActionsService {
progressTracker.markComplete();
return CompletableFuture.completedFuture(outputFile);
} catch (Exception e) {
} catch (IOException | InterruptedException e) {
logger.error("Failed to save section to '{}'", outputFile, e);
return CompletableFuture.failedFuture(e);
}