From c9ce8a2521c7b3faf3314714a0c4a10fe7b465da Mon Sep 17 00:00:00 2001 From: toximu Date: Sat, 13 Jun 2026 13:06:09 +0300 Subject: [PATCH 1/4] send submissions by websocket --- .../{PreMatch => }/MatchRoom/Match.java | 2 +- .../MatchDeliveryListener.java | 28 +++- .../MatchRoom/MatchRepository.java | 2 +- .../MatchRoom/MatchService.java | 8 +- .../Matchmaking/MatchmakingService.java | 2 +- .../backend/PreMatch/DTO/WebSocketDTO.java | 4 +- .../backend/PreMatch/MatchSettings.java | 2 +- ...WebsocketTopicSubscriptionInterceptor.java | 6 +- .../judge/problem/ProblemController.java | 4 +- .../submission/SubmissionController.java | 140 ++++++++++-------- .../submission/SubmissionPollingService.java | 6 +- .../submission/SubmissionRepository.java | 2 + .../submission/SubmissionResponseDTO.java | 4 +- .../submission/SubmissionUpdatedEvent.java | 2 +- .../Matchmaking/MatchmakingServiceTest.java | 2 +- .../PreMatch/MatchRoom/MatchFinishTest.java | 3 + .../controller/ProblemControllerFileTest.java | 4 +- 17 files changed, 128 insertions(+), 93 deletions(-) rename src/main/java/com/codzilla/backend/{PreMatch => }/MatchRoom/Match.java (97%) rename src/main/java/com/codzilla/backend/{PreMatch => MatchRoom}/MatchDeliveryListener.java (70%) rename src/main/java/com/codzilla/backend/{PreMatch => }/MatchRoom/MatchRepository.java (76%) rename src/main/java/com/codzilla/backend/{PreMatch => }/MatchRoom/MatchService.java (91%) diff --git a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/Match.java b/src/main/java/com/codzilla/backend/MatchRoom/Match.java similarity index 97% rename from src/main/java/com/codzilla/backend/PreMatch/MatchRoom/Match.java rename to src/main/java/com/codzilla/backend/MatchRoom/Match.java index 0aefb29..629b24e 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/Match.java +++ b/src/main/java/com/codzilla/backend/MatchRoom/Match.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.PreMatch.MatchRoom; +package com.codzilla.backend.MatchRoom; import com.codzilla.backend.PreMatch.DraftSession.DraftSession; import com.codzilla.backend.PreMatch.model.Category; diff --git a/src/main/java/com/codzilla/backend/PreMatch/MatchDeliveryListener.java b/src/main/java/com/codzilla/backend/MatchRoom/MatchDeliveryListener.java similarity index 70% rename from src/main/java/com/codzilla/backend/PreMatch/MatchDeliveryListener.java rename to src/main/java/com/codzilla/backend/MatchRoom/MatchDeliveryListener.java index bd8fb26..123270e 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/MatchDeliveryListener.java +++ b/src/main/java/com/codzilla/backend/MatchRoom/MatchDeliveryListener.java @@ -1,12 +1,14 @@ -package com.codzilla.backend.PreMatch; +package com.codzilla.backend.MatchRoom; import com.codzilla.backend.PreMatch.DTO.DraftSessionResponseDTO; import com.codzilla.backend.PreMatch.DTO.MatchResultDTO; import com.codzilla.backend.PreMatch.DTO.WebSocketDTO; +import com.codzilla.backend.PreMatch.MatchSettings; import com.codzilla.backend.PreMatch.events.MatchResultNotifyEvent; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; import com.codzilla.backend.PreMatch.events.DraftSessionFinishedEvent; import com.codzilla.backend.PreMatch.events.DraftSessionUpdatedEvent; +import com.codzilla.backend.judge.submission.SubmissionResponseDTO; +import com.codzilla.backend.judge.submission.SubmissionUpdatedEvent; import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.messaging.simp.SimpMessagingTemplate; @@ -74,4 +76,26 @@ public void handleMatchResult(MatchResultNotifyEvent event) { ) ); } + + @Async + @EventListener + public void handleSubmissionUpdated(SubmissionUpdatedEvent submissionUpdatedEvent) { + var submission = submissionUpdatedEvent.submission(); + messagingTemplate.convertAndSend( + matchSettings.getWebSocketMatchDestination(submission.getMatchId()), + new WebSocketDTO( + WebSocketDTO.Status.SUBMISSION, + new SubmissionResponseDTO( + submission.getId(), + submission.getProblemId(), + submission.getLanguageId(), + submission.getStatus().name(), + submission.getCreatedAt(), + submission.getUpdatedAt(), + submission.getResultDetails(), + submission.getUserId() + ) + ) + ); + } } diff --git a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchRepository.java b/src/main/java/com/codzilla/backend/MatchRoom/MatchRepository.java similarity index 76% rename from src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchRepository.java rename to src/main/java/com/codzilla/backend/MatchRoom/MatchRepository.java index d9c340a..043855c 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchRepository.java +++ b/src/main/java/com/codzilla/backend/MatchRoom/MatchRepository.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.PreMatch.MatchRoom; +package com.codzilla.backend.MatchRoom; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchService.java b/src/main/java/com/codzilla/backend/MatchRoom/MatchService.java similarity index 91% rename from src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchService.java rename to src/main/java/com/codzilla/backend/MatchRoom/MatchService.java index 70ba9fa..59d7ee6 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/MatchRoom/MatchService.java +++ b/src/main/java/com/codzilla/backend/MatchRoom/MatchService.java @@ -1,14 +1,11 @@ -package com.codzilla.backend.PreMatch.MatchRoom; +package com.codzilla.backend.MatchRoom; import com.codzilla.backend.Rating.MatchFinishedEvent; -import com.codzilla.backend.PreMatch.DTO.WebSocketDTO; import com.codzilla.backend.PreMatch.DraftSession.DraftSession; import com.codzilla.backend.PreMatch.DraftSession.DraftSessionService; import com.codzilla.backend.PreMatch.MatchSettings; -import com.codzilla.backend.PreMatch.events.DraftSessionFinishedEvent; import com.codzilla.backend.PreMatch.model.Category; import com.codzilla.backend.PreMatch.model.Language; -import com.codzilla.backend.PreMatch.model.ProblemType; import com.codzilla.backend.judge.client.SqlServiceClient; import com.codzilla.backend.judge.problem.Problem; import com.codzilla.backend.judge.problem.ProblemRepository; @@ -16,11 +13,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.simp.SimpMessagingTemplate; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.event.TransactionPhase; -import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.context.ApplicationEventPublisher; import java.time.Instant; diff --git a/src/main/java/com/codzilla/backend/Matchmaking/MatchmakingService.java b/src/main/java/com/codzilla/backend/Matchmaking/MatchmakingService.java index f6de21a..e139e10 100644 --- a/src/main/java/com/codzilla/backend/Matchmaking/MatchmakingService.java +++ b/src/main/java/com/codzilla/backend/Matchmaking/MatchmakingService.java @@ -2,7 +2,7 @@ import com.codzilla.backend.Authentication.Exceptions.UserNotFoundException; import com.codzilla.backend.User.UserRepository; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; +import com.codzilla.backend.MatchRoom.MatchService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; diff --git a/src/main/java/com/codzilla/backend/PreMatch/DTO/WebSocketDTO.java b/src/main/java/com/codzilla/backend/PreMatch/DTO/WebSocketDTO.java index b034ee2..ca33375 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/DTO/WebSocketDTO.java +++ b/src/main/java/com/codzilla/backend/PreMatch/DTO/WebSocketDTO.java @@ -11,8 +11,8 @@ public class WebSocketDTO { public enum Status { MATCH_STARTED_REDIRECT, DRAFT, - LIVE, - MATCH_FINISHED + SUBMISSION, + MATCH_FINISHED, } public WebSocketDTO(Status status, Object payload) { diff --git a/src/main/java/com/codzilla/backend/PreMatch/MatchSettings.java b/src/main/java/com/codzilla/backend/PreMatch/MatchSettings.java index 31bb2ec..46c1030 100644 --- a/src/main/java/com/codzilla/backend/PreMatch/MatchSettings.java +++ b/src/main/java/com/codzilla/backend/PreMatch/MatchSettings.java @@ -16,7 +16,7 @@ public class MatchSettings { Duration timeToPick; String websocketMatchPrefix; - String getWebSocketMatchDestination(UUID matchId) { + public String getWebSocketMatchDestination(UUID matchId) { return websocketMatchPrefix + matchId; } } diff --git a/src/main/java/com/codzilla/backend/WebSocket/WebsocketTopicSubscriptionInterceptor.java b/src/main/java/com/codzilla/backend/WebSocket/WebsocketTopicSubscriptionInterceptor.java index 3661b2b..226a9a2 100644 --- a/src/main/java/com/codzilla/backend/WebSocket/WebsocketTopicSubscriptionInterceptor.java +++ b/src/main/java/com/codzilla/backend/WebSocket/WebsocketTopicSubscriptionInterceptor.java @@ -1,10 +1,6 @@ package com.codzilla.backend.WebSocket; -import com.codzilla.backend.PreMatch.MatchRoom.Match; -import com.codzilla.backend.PreMatch.MatchRoom.MatchRepository; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; -import com.codzilla.backend.PreMatch.MatchSettings; -import com.codzilla.backend.User.User; +import com.codzilla.backend.MatchRoom.MatchRepository; import com.codzilla.backend.User.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.Message; diff --git a/src/main/java/com/codzilla/backend/judge/problem/ProblemController.java b/src/main/java/com/codzilla/backend/judge/problem/ProblemController.java index 6bdba6d..bab722d 100644 --- a/src/main/java/com/codzilla/backend/judge/problem/ProblemController.java +++ b/src/main/java/com/codzilla/backend/judge/problem/ProblemController.java @@ -1,7 +1,7 @@ package com.codzilla.backend.judge.problem; -import com.codzilla.backend.PreMatch.MatchRoom.Match; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; +import com.codzilla.backend.MatchRoom.Match; +import com.codzilla.backend.MatchRoom.MatchService; import com.codzilla.backend.PreMatch.model.Category; import com.codzilla.backend.PreMatch.model.Language; import com.codzilla.backend.User.User; diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionController.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionController.java index 881d875..9fa5301 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionController.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionController.java @@ -9,10 +9,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import java.time.LocalDateTime; @@ -25,7 +22,7 @@ import java.util.stream.Collectors; @RestController -@RequestMapping("/my-submissions") +@RequestMapping("/submissions") @RequiredArgsConstructor public class SubmissionController { @@ -34,64 +31,81 @@ public class SubmissionController { private final Map>>>> waiters = new ConcurrentHashMap<>(); private final UserRepository userRepository; - @GetMapping - public DeferredResult>> getUserSubmissions( - @AuthenticationPrincipal User user, - @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastUpdate) { - - DeferredResult>> output = new DeferredResult<>(20000L); - - if (user == null) { - output.setResult(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - return output; - } - - User fullUser = userRepository.findByEmail(user.getEmail()) - .orElseThrow(() -> new UsernameNotFoundException("User not found")); - UUID userId = fullUser.getId(); - - output.onTimeout(() -> output.setResult(ResponseEntity.status(HttpStatus.NOT_MODIFIED).build())); - - Optional latestSub = submissionRepository.findFirstByUserIdOrderByUpdatedAtDesc(userId); - boolean hasUpdates = lastUpdate == null || - (latestSub.isPresent() && latestSub.get().getUpdatedAt().isAfter(lastUpdate)); - - if (hasUpdates) { - output.setResult(ResponseEntity.ok(fetchUserSubmissions(userId))); - return output; - } - - waiters.computeIfAbsent(userId, k -> new ConcurrentLinkedQueue<>()).add(output); - - output.onCompletion(() -> { - ConcurrentLinkedQueue>>> queue = waiters.get(userId); - if (queue != null) { - queue.remove(output); - } - }); - - return output; + @GetMapping("/{matchId}") + ResponseEntity getSubmissionsOfMatch(@PathVariable UUID matchId) { + return ResponseEntity.ok( + submissionRepository.findByMatchIdAndStatusNotIn(matchId, List.of(Submission.Status.PROCESSING, Submission.Status.IN_QUEUE)) + .stream().map((sub) -> new SubmissionResponseDTO( + sub.getId(), + sub.getProblemId(), + sub.getLanguageId(), + sub.getStatus().name(), + sub.getCreatedAt(), + sub.getUpdatedAt(), + sub.getResultDetails(), + sub.getUserId() + )) + ); } - @EventListener - public void onSubmissionUpdated(SubmissionUpdatedEvent event) { - ConcurrentLinkedQueue>>> queue = waiters.get(event.userId()); - - if (queue != null && !queue.isEmpty()) { - List freshData = fetchUserSubmissions(event.userId()); - - DeferredResult>> result; - while ((result = queue.poll()) != null) { - result.setResult(ResponseEntity.ok(freshData)); - } - } - } - - private List fetchUserSubmissions(UUID userId) { - return submissionRepository - .findAllByUserIdOrderByCreatedAtDesc(userId) - .stream() - .map(SubmissionResponseDTO::fromEntity) - .collect(Collectors.toList()); - } +// @GetMapping +// public DeferredResult>> getUserSubmissions( +// @AuthenticationPrincipal User user, +// @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastUpdate) { +// +// DeferredResult>> output = new DeferredResult<>(20000L); +// +// if (user == null) { +// output.setResult(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); +// return output; +// } +// +// User fullUser = userRepository.findByEmail(user.getEmail()) +// .orElseThrow(() -> new UsernameNotFoundException("User not found")); +// UUID userId = fullUser.getId(); +// +// output.onTimeout(() -> output.setResult(ResponseEntity.status(HttpStatus.NOT_MODIFIED).build())); +// +// Optional latestSub = submissionRepository.findFirstByUserIdOrderByUpdatedAtDesc(userId); +// boolean hasUpdates = lastUpdate == null || +// (latestSub.isPresent() && latestSub.get().getUpdatedAt().isAfter(lastUpdate)); +// +// if (hasUpdates) { +// output.setResult(ResponseEntity.ok(fetchUserSubmissions(userId))); +// return output; +// } +// +// waiters.computeIfAbsent(userId, k -> new ConcurrentLinkedQueue<>()).add(output); +// +// output.onCompletion(() -> { +// ConcurrentLinkedQueue>>> queue = waiters.get(userId); +// if (queue != null) { +// queue.remove(output); +// } +// }); +// +// return output; +// } + +// @EventListener +// public void onSubmissionUpdated(SubmissionUpdatedEvent event) { +// ConcurrentLinkedQueue>>> queue = waiters.get(event.userId()); +// +// if (queue != null && !queue.isEmpty()) { +// List freshData = fetchUserSubmissions(event.userId()); +// +// DeferredResult>> result; +// while ((result = queue.poll()) != null) { +// result.setResult(ResponseEntity.ok(freshData)); +// } +// } +// } + +// private List fetchUserSubmissions(UUID userId) { +// return submissionRepository +// .findAllByUserIdOrderByCreatedAtDesc(userId) +// .stream() +// .map(SubmissionResponseDTO::fromEntity) +// .collect(Collectors.toList()); +// } } \ No newline at end of file diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java index 7873dde..b4d0703 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java @@ -2,7 +2,7 @@ import com.codzilla.backend.judge.client.SqlServiceClient; import com.codzilla.backend.judge.judge0.Judge0Client; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; +import com.codzilla.backend.MatchRoom.MatchService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; @@ -120,7 +120,7 @@ private void updateSubmissionStatus(Long submissionId) { submissionRepository.save(sub); log.info("Submission {} final verdict: {}", submissionId, sub.getStatus()); - eventPublisher.publishEvent(new SubmissionUpdatedEvent(sub.getUserId())); + eventPublisher.publishEvent(new SubmissionUpdatedEvent(sub)); } @Scheduled(fixedDelay = 2000) @@ -169,6 +169,6 @@ private void updateSqlSubmissionStatus(Submission sub, submissionRepository.save(sub); log.info("SQL Submission {} final verdict: {}", sub.getId(), sub.getStatus()); - eventPublisher.publishEvent(new SubmissionUpdatedEvent(sub.getUserId())); + eventPublisher.publishEvent(new SubmissionUpdatedEvent(sub)); } } \ No newline at end of file diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionRepository.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionRepository.java index 165fcb9..30f3779 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionRepository.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionRepository.java @@ -14,4 +14,6 @@ public interface SubmissionRepository extends JpaRepository { List findAllByStatusAndSqlSubmissionIdIsNotNull(Submission.Status status); List findAllByUserIdOrderByCreatedAtDesc(UUID userId); Optional findFirstByUserIdOrderByUpdatedAtDesc(UUID userId); + + List findByMatchIdAndStatusNotIn(UUID matchId, List statuses); } diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java index 987e955..4b1400a 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java @@ -1,6 +1,7 @@ package com.codzilla.backend.judge.submission; import java.time.LocalDateTime; +import java.util.UUID; public record SubmissionResponseDTO( Long id, @@ -9,7 +10,8 @@ public record SubmissionResponseDTO( String status, LocalDateTime createdAt, LocalDateTime updatedAt, - String resultDetails + String resultDetails, + UUID userId ) { public static SubmissionResponseDTO fromEntity(Submission submission) { return new SubmissionResponseDTO( diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionUpdatedEvent.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionUpdatedEvent.java index cba83f7..5d27004 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionUpdatedEvent.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionUpdatedEvent.java @@ -2,4 +2,4 @@ import java.util.UUID; -public record SubmissionUpdatedEvent(UUID userId) {} \ No newline at end of file +public record SubmissionUpdatedEvent(Submission submission) {} \ No newline at end of file diff --git a/src/test/java/com/codzilla/backend/Matchmaking/MatchmakingServiceTest.java b/src/test/java/com/codzilla/backend/Matchmaking/MatchmakingServiceTest.java index cd0dfa7..7de80ab 100644 --- a/src/test/java/com/codzilla/backend/Matchmaking/MatchmakingServiceTest.java +++ b/src/test/java/com/codzilla/backend/Matchmaking/MatchmakingServiceTest.java @@ -2,7 +2,7 @@ import com.codzilla.backend.User.User; import com.codzilla.backend.User.UserRepository; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; +import com.codzilla.backend.MatchRoom.MatchService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java b/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java index 0753703..224cf1c 100644 --- a/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java +++ b/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java @@ -1,5 +1,8 @@ package com.codzilla.backend.PreMatch.MatchRoom; +import com.codzilla.backend.MatchRoom.Match; +import com.codzilla.backend.MatchRoom.MatchRepository; +import com.codzilla.backend.MatchRoom.MatchService; import com.codzilla.backend.Rating.MatchFinishedEvent; import com.codzilla.backend.judge.client.SqlServiceClient; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/codzilla/backend/Sandbox/controller/ProblemControllerFileTest.java b/src/test/java/com/codzilla/backend/Sandbox/controller/ProblemControllerFileTest.java index 76a6ff4..f63b5c0 100644 --- a/src/test/java/com/codzilla/backend/Sandbox/controller/ProblemControllerFileTest.java +++ b/src/test/java/com/codzilla/backend/Sandbox/controller/ProblemControllerFileTest.java @@ -1,7 +1,7 @@ package com.codzilla.backend.Sandbox.controller; -import com.codzilla.backend.PreMatch.MatchRoom.Match; -import com.codzilla.backend.PreMatch.MatchRoom.MatchService; +import com.codzilla.backend.MatchRoom.Match; +import com.codzilla.backend.MatchRoom.MatchService; import com.codzilla.backend.PreMatch.model.Category; import com.codzilla.backend.S3.S3Repository; import com.codzilla.backend.User.User; From 8777e01a1c1ec6b88aaee9eeb0b5933c2d93a6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=D1=88=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= Date: Sat, 13 Jun 2026 13:43:37 +0300 Subject: [PATCH 2/4] edit bag --- .../backend/judge/submission/SubmissionResponseDTO.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java index 4b1400a..770c673 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionResponseDTO.java @@ -21,7 +21,8 @@ public static SubmissionResponseDTO fromEntity(Submission submission) { submission.getStatus().name(), submission.getCreatedAt(), submission.getUpdatedAt(), - submission.getResultDetails() + submission.getResultDetails(), + submission.getUserId() ); } } \ No newline at end of file From f38d73bf5275c1681ae608dd8c53e35e1a4d1109 Mon Sep 17 00:00:00 2001 From: toximu Date: Tue, 16 Jun 2026 22:50:13 +0300 Subject: [PATCH 3/4] send submission by websocket and login controller --- .../AuthController/AuthController.java | 7 ++----- .../Authentication/dto/UserResponseDTO.java | 11 +++++++++++ .../submission/SubmissionPollingService.java | 17 ++++++++++------- src/main/resources/application.properties | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/codzilla/backend/Authentication/AuthController/AuthController.java b/src/main/java/com/codzilla/backend/Authentication/AuthController/AuthController.java index 6e48308..675e071 100644 --- a/src/main/java/com/codzilla/backend/Authentication/AuthController/AuthController.java +++ b/src/main/java/com/codzilla/backend/Authentication/AuthController/AuthController.java @@ -1,13 +1,10 @@ package com.codzilla.backend.Authentication.AuthController; import com.codzilla.backend.Authentication.JWTUtils.JWTUtils; +import com.codzilla.backend.Authentication.dto.*; import com.codzilla.backend.User.User; import com.codzilla.backend.User.UserService; import com.codzilla.backend.Authentication.config.AuthSettings; -import com.codzilla.backend.Authentication.dto.LoginRequestDTO; -import com.codzilla.backend.Authentication.dto.LoginResponseDTO; -import com.codzilla.backend.Authentication.dto.RegisterRequestDTO; -import com.codzilla.backend.Authentication.dto.RegisterResponseDTO; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -64,7 +61,7 @@ public ResponseEntity login(@RequestBody LoginRequestDTO request, HttpServlet refreshCookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds()); refreshCookie.setSecure(false); response.addCookie(refreshCookie); - return ResponseEntity.ok(new LoginResponseDTO(user.getNickname())); + return ResponseEntity.ok(new UserResponseDTO(user)); } @PostMapping("/logout") diff --git a/src/main/java/com/codzilla/backend/Authentication/dto/UserResponseDTO.java b/src/main/java/com/codzilla/backend/Authentication/dto/UserResponseDTO.java index 76f677b..8e26234 100644 --- a/src/main/java/com/codzilla/backend/Authentication/dto/UserResponseDTO.java +++ b/src/main/java/com/codzilla/backend/Authentication/dto/UserResponseDTO.java @@ -1,6 +1,9 @@ package com.codzilla.backend.Authentication.dto; +import com.codzilla.backend.User.User; + import java.util.List; +import java.util.Objects; import java.util.UUID; public record UserResponseDTO( @@ -9,4 +12,12 @@ public record UserResponseDTO( UUID id, List authorities ) { + public UserResponseDTO(User user) { + this( + user.getNickname(), + user.getEmail(), + user.getId(), + user.getAuthorities().stream().map(Objects::toString).toList() + ); + } } diff --git a/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java b/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java index b4d0703..6f29e08 100644 --- a/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java +++ b/src/main/java/com/codzilla/backend/judge/submission/SubmissionPollingService.java @@ -53,9 +53,11 @@ private void updateTestStatus(SubmissionTest subTest, Judge0Client.SubmissionRes String actual = response.getStdout(); if (actual != null && !actual.isBlank()) { try { + actual = actual.trim(); byte[] decoded = Base64.getDecoder().decode(actual); actual = new String(decoded, StandardCharsets.UTF_8).trim(); } catch (IllegalArgumentException e) { + log.info("Cannot decode output!"); actual = actual.trim(); } } else { @@ -70,16 +72,17 @@ private void updateTestStatus(SubmissionTest subTest, Judge0Client.SubmissionRes subTest.setStatus(SubmissionTest.Status.RUNTIME_ERROR); } else if (statusId == 3) { String expected = subTest.getExpectedOutput() == null ? "" : subTest.getExpectedOutput().trim(); + log.info("Actual output is {}, expected : {}", actual, expected); subTest.setStatus(actual.equals(expected) - ? SubmissionTest.Status.ACCEPTED - : SubmissionTest.Status.WRONG_ANSWER); + ? SubmissionTest.Status.ACCEPTED + : SubmissionTest.Status.WRONG_ANSWER); } else { subTest.setStatus(SubmissionTest.Status.RUNTIME_ERROR); } submissionTestRepository.save(subTest); log.info("Test {} of submission {} → {}", - subTest.getTestIndex(), subTest.getSubmissionId(), subTest.getStatus()); + subTest.getTestIndex(), subTest.getSubmissionId(), subTest.getStatus()); } private void updateSubmissionStatus(Long submissionId) { @@ -87,13 +90,13 @@ private void updateSubmissionStatus(Long submissionId) { .findAllBySubmissionIdOrderByTestIndex(submissionId); boolean allDone = allTests.stream() - .allMatch(t -> t.getStatus() != SubmissionTest.Status.IN_QUEUE); + .allMatch(t -> t.getStatus() != SubmissionTest.Status.IN_QUEUE); if (!allDone) return; SubmissionTest firstFailed = allTests.stream() - .filter(t -> t.getStatus() != SubmissionTest.Status.ACCEPTED) - .findFirst() - .orElse(null); + .filter(t -> t.getStatus() != SubmissionTest.Status.ACCEPTED) + .findFirst() + .orElse(null); Submission sub = submissionRepository.findById(submissionId).orElse(null); if (sub == null) return; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b63b042..a01dbeb 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ spring.application.name=Backend spring.jpa.hibernate.ddl-auto=update -app.security.jwt.access-token-ttl=10m +app.security.jwt.access-token-ttl=7d app.security.jwt.refresh-token-ttl=7d app.s3.endpoint=${S3_ENDPOINT:http://localhost:9000} From 932561a97427b10b9260de4845259b3f65ee8462 Mon Sep 17 00:00:00 2001 From: toximu Date: Tue, 16 Jun 2026 22:58:00 +0300 Subject: [PATCH 4/4] fix tests --- src/main/java/com/codzilla/backend/MatchRoom/Match.java | 4 ++-- .../codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/codzilla/backend/MatchRoom/Match.java b/src/main/java/com/codzilla/backend/MatchRoom/Match.java index 629b24e..37d7b6c 100644 --- a/src/main/java/com/codzilla/backend/MatchRoom/Match.java +++ b/src/main/java/com/codzilla/backend/MatchRoom/Match.java @@ -24,7 +24,7 @@ @Setter public class Match { - enum Status { + public enum Status { DRAFTING, LIVE, FINISHED @@ -77,7 +77,7 @@ public UUID opponentOf(UUID userId) { return null; } - Match(UUID firstUserId, UUID secondUserId) { + public Match(UUID firstUserId, UUID secondUserId) { this.firstUserId = firstUserId; this.secondUserId = secondUserId; } diff --git a/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java b/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java index 224cf1c..4f0409b 100644 --- a/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java +++ b/src/test/java/com/codzilla/backend/PreMatch/MatchRoom/MatchFinishTest.java @@ -40,7 +40,7 @@ class MatchFinishTest { private Match liveMatch(UUID id, UUID first, UUID second) { Match m = new Match(first, second); - m.id = id; + m.setId(id); m.setStatus(Match.Status.LIVE); return m; }