Added stuff

This commit is contained in:
Andrew Lalis 2023-04-05 16:51:58 +02:00
parent 55eb95e08a
commit af3435834f
5 changed files with 52 additions and 21 deletions

View File

@ -62,7 +62,8 @@ public class SecurityConfig {
"/auth/token",
"/auth/register",
"/auth/activate",
"/auth/reset-password"
"/auth/reset-password",
"/submissions/video-processing-complete"
).permitAll()
// Everything else must be authenticated, just to be safe.
.anyRequest().authenticated();

View File

@ -5,6 +5,7 @@ import nl.andrewlalis.gymboard_api.domains.auth.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -14,5 +15,8 @@ public interface SubmissionRepository extends JpaRepository<Submission, String>,
@Modifying
void deleteAllByUser(User user);
List<Submission> findAllByVideoProcessingTaskId(long taskId);
@Query("SELECT s FROM Submission s " +
"WHERE s.videoProcessingTaskId = :taskId AND " +
"(s.videoFileId IS NULL OR s.thumbnailFileId IS NULL)")
List<Submission> findUnprocessedByTaskId(long taskId);
}

View File

@ -157,7 +157,9 @@ public class ExerciseSubmissionService {
@Transactional
public void handleVideoProcessingComplete(VideoProcessingCompletePayload payload) {
for (var submission : submissionRepository.findAllByVideoProcessingTaskId(payload.taskId())) {
var submissionsToUpdate = submissionRepository.findUnprocessedByTaskId(payload.taskId());
log.info("Received video processing complete message from CDN: {}, affecting {} submissions.", payload, submissionsToUpdate.size());
for (var submission : submissionsToUpdate) {
if (payload.status().equalsIgnoreCase("COMPLETE")) {
submission.setVideoFileId(payload.videoFileId());
submission.setThumbnailFileId(payload.thumbnailFileId());

View File

@ -116,10 +116,15 @@ public class TokenService {
public Jws<Claims> getToken(String token) {
if (token == null) return null;
var builder = Jwts.parserBuilder()
.setSigningKey(this.getPrivateKey())
.requireIssuer(ISSUER);
return builder.build().parseClaimsJws(token);
try {
var builder = Jwts.parserBuilder()
.setSigningKey(this.getPrivateKey())
.requireIssuer(ISSUER);
return builder.build().parseClaimsJws(token);
} catch (Exception e) {
log.warn("Error parsing JWT.", e);
return null;
}
}
private PrivateKey getPrivateKey() {

View File

@ -1,5 +1,6 @@
package nl.andrewlalis.gymboardcdn.uploads.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import nl.andrewlalis.gymboardcdn.files.FileMetadata;
@ -10,6 +11,7 @@ import nl.andrewlalis.gymboardcdn.uploads.service.process.ThumbnailGenerator;
import nl.andrewlalis.gymboardcdn.uploads.service.process.VideoProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@ -20,6 +22,7 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.Executor;
@ -36,6 +39,9 @@ public class VideoProcessingService {
private final ThumbnailGenerator thumbnailGenerator;
private final ObjectMapper objectMapper;
@Value("${app.api-origin}")
private String apiOrigin;
public VideoProcessingService(Executor videoProcessingExecutor,
VideoProcessingTaskRepository taskRepo,
FileStorageService fileStorageService,
@ -52,6 +58,9 @@ public class VideoProcessingService {
private void updateTask(VideoProcessingTask task, VideoProcessingTask.Status status) {
task.setStatus(status);
taskRepo.saveAndFlush(task);
if (status == VideoProcessingTask.Status.COMPLETED || status == VideoProcessingTask.Status.FAILED) {
sendTaskCompleteToApi(task);
}
}
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)
@ -143,9 +152,6 @@ public class VideoProcessingService {
task.setThumbnailFileId(thumbnailFileId);
updateTask(task, VideoProcessingTask.Status.COMPLETED);
log.info("Finished processing task {}.", task.getId());
// Send HTTP POST to API, with video id and thumbnail id.
sendProcessedDataToApi(videoFileId, thumbnailFileId);
} catch (IOException e) {
log.error("Failed to copy processed video to final storage location.", e);
updateTask(task, VideoProcessingTask.Status.FAILED);
@ -162,24 +168,37 @@ public class VideoProcessingService {
}
}
private void sendProcessedDataToApi(String videoId, String thumbnailId) throws IOException {
/**
* Sends an update message to the Gymboard API when a task finishes its
* processing.
* @param task The task to send.
*/
private void sendTaskCompleteToApi(VideoProcessingTask task) {
ObjectNode obj = objectMapper.createObjectNode();
obj.put("videoFileId", videoId);
obj.put("thumbnailFileId", thumbnailId);
String json = objectMapper.writeValueAsString(obj);
obj.put("taskId", task.getId());
obj.put("status", task.getStatus().name());
obj.put("videoFileId", task.getVideoFileId());
obj.put("thumbnailFileId", task.getThumbnailFileId());
String json;
try {
json = objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
log.error("JSON error while sending task data to API for task " + task.getId(), e);
return;
}
HttpClient httpClient = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://localhost:8080/submissions/123/processed-data"))
.header("Authorization", "Bearer bullshit")
HttpRequest request = HttpRequest.newBuilder(URI.create(apiOrigin + "/submissions/video-processing-complete"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(3))
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
try {
HttpResponse<Void> response = httpClient.send(request, HttpResponse.BodyHandlers.discarding());
if (response.statusCode() == 200) {
// We can now delete the task.
if (response.statusCode() >= 400) {
log.error("API returned not-ok response {}", response.statusCode());
}
} catch (InterruptedException e) {
// TODO: Retry!
throw new RuntimeException(e);
} catch (Exception e) {
log.error("Failed to send HTTP request to API.", e);
}
}
}