Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.ezcode.codetest.application.submission.dto.event;

import org.ezcode.codetest.infrastructure.github.model.PushStatus;

public record GitPushStatusEvent(

String sessionKey,

PushStatus pushStatus

) {
public static GitPushStatusEvent started(String sessionKey) {
return new GitPushStatusEvent(sessionKey, PushStatus.STARTED);
}

public static GitPushStatusEvent succeeded(String sessionKey) {
return new GitPushStatusEvent(sessionKey, PushStatus.SUCCESS);
}

public static GitPushStatusEvent failed(String sessionKey) {
return new GitPushStatusEvent(sessionKey, PushStatus.FAILED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ public record GitHubPushRequest(

Long problemId,

String difficulty,

String problemTitle,

String problemDescription,

String languageName,

String languageVersion,

Long averageMemoryUsage,

Long averageExecutionTime,
Expand All @@ -31,19 +37,26 @@ public record GitHubPushRequest(
String submittedAt

) {
public static GitHubPushRequest of(SubmissionContext ctx, UserGithubInfo info) {
public static GitHubPushRequest of(SubmissionContext ctx, UserGithubInfo info, String decryptedToken) {
return new GitHubPushRequest(
info.getOwner(),
info.getRepo(),
info.getBranch(),
info.getGithubAccessToken(),
decryptedToken,
ctx.getProblem().getId(),
ctx.getProblem().getDifficulty().getDifficulty(),
ctx.getProblem().getTitle(),
ctx.getProblem().getDescription(),
ctx.getLanguageName(),
ctx.getLanguageVersion(),
ctx.aggregator().averageMemoryUsage(),
ctx.aggregator().averageExecutionTime(),
ctx.getSourceCode(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
);
}

public String getLanguage() {
return languageName + " " + languageVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.ezcode.codetest.domain.language.model.entity.Language;
import org.ezcode.codetest.domain.problem.model.ProblemInfo;
import org.ezcode.codetest.domain.problem.model.entity.Problem;
import org.ezcode.codetest.domain.problem.model.entity.ProblemCategory;
import org.ezcode.codetest.domain.problem.model.entity.Testcase;
import org.ezcode.codetest.domain.submission.model.SubmissionAggregator;
import org.ezcode.codetest.domain.user.model.entity.User;
Expand Down Expand Up @@ -139,7 +138,7 @@ public void incrementCorrectSubmissions() {
getProblem().incrementCorrectSubmissions();
}

public boolean isGitPushStatus(){
public boolean isGitPushStatus() {
return user.isGitPushStatus();
}

Expand All @@ -150,4 +149,12 @@ public Long getUserId() {
public boolean isPassed() {
return getPassedCount() == getTestcaseCount();
}

public String getLanguageName() {
return language.getName();
}

public String getLanguageVersion() {
return language.getVersion();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ezcode.codetest.application.submission.port;

import org.ezcode.codetest.application.submission.dto.event.GitPushStatusEvent;
import org.ezcode.codetest.application.submission.dto.event.SubmissionErrorEvent;
import org.ezcode.codetest.application.submission.dto.event.SubmissionJudgingFinishedEvent;
import org.ezcode.codetest.application.submission.dto.event.TestcaseListInitializedEvent;
Expand All @@ -14,4 +15,6 @@ public interface SubmissionEventService {
void publishFinalResult(SubmissionJudgingFinishedEvent event);

void publishSubmissionError(SubmissionErrorEvent event);

void publishGitPushStatus(GitPushStatusEvent event);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.ezcode.codetest.application.submission.service;

import org.ezcode.codetest.application.submission.dto.event.GitPushStatusEvent;
import org.ezcode.codetest.application.submission.dto.request.github.GitHubPushRequest;
import org.ezcode.codetest.application.submission.model.SubmissionContext;
import org.ezcode.codetest.application.submission.port.ExceptionNotifier;
import org.ezcode.codetest.application.submission.port.GitHubClient;
import org.ezcode.codetest.application.submission.port.SubmissionEventService;
import org.ezcode.codetest.common.security.util.AESUtil;
import org.ezcode.codetest.domain.user.model.entity.UserGithubInfo;
import org.ezcode.codetest.domain.user.service.UserGithubService;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class GitHubPushService {

private final GitHubClient gitHubClient;
private final UserGithubService userGithubService;
private final ExceptionNotifier exceptionNotifier;
private final SubmissionEventService eventService;
private final AESUtil aesUtil;

public void pushSolutionToRepo(SubmissionContext ctx) {
if (!ctx.isGitPushStatus() || !ctx.isPassed()) {
return;
}

eventService.publishGitPushStatus(GitPushStatusEvent.started(ctx.getSessionKey()));
UserGithubInfo info = userGithubService.getUserGithubInfoById(ctx.getUserId());

try {
String decryptedToken = aesUtil.decrypt(info.getGithubAccessToken());
gitHubClient.commitAndPushToRepo(GitHubPushRequest.of(ctx, info, decryptedToken));
eventService.publishGitPushStatus(GitPushStatusEvent.succeeded(ctx.getSessionKey()));
} catch (Exception e) {
exceptionNotifier.notifyException("commitAndPush", e);
eventService.publishGitPushStatus(GitPushStatusEvent.failed(ctx.getSessionKey()));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class SubmissionService {
private final ExceptionNotifier exceptionNotifier;
private final LockManager lockManager;
private final JudgementService judgementService;
private final GitHubService gitHubService;
private final GitHubPushService gitHubPushService;

public String enqueueCodeSubmission(Long problemId, CodeSubmitRequest request, AuthUser authUser) {

Expand All @@ -68,7 +68,7 @@ public String enqueueCodeSubmission(Long problemId, CodeSubmitRequest request, A

@Async("judgeSubmissionExecutor")
@Transactional
public void submitCodeStream(SubmissionMessage msg) {
public void processSubmissionAsync(SubmissionMessage msg) {
try {
log.info("[Submission RUN] Thread = {}", Thread.currentThread().getName());
log.info("[큐 수신] SubmissionMessage.sessionKey: {}", msg.sessionKey());
Expand All @@ -77,7 +77,7 @@ public void submitCodeStream(SubmissionMessage msg) {
judgementService.publishInitTestcases(ctx);
judgementService.runTestcases(ctx);
judgementService.finalizeAndPublish(ctx);
gitHubService.commitAndPushToRepo(ctx);
gitHubPushService.pushSolutionToRepo(ctx);
} catch (Exception e) {
judgementService.publishSubmissionError(msg.sessionKey(), e);
exceptionNotifier.notifyException("submitCodeStream", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.ezcode.codetest.domain.submission.exception;

import org.ezcode.codetest.common.base.exception.BaseException;
import org.ezcode.codetest.common.base.exception.ResponseCode;
import org.ezcode.codetest.domain.submission.exception.code.GitHubExceptionCode;
import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public class GitHubClientException extends BaseException {

private final ResponseCode responseCode;
private final HttpStatus httpStatus;
private final String message;

public GitHubClientException(GitHubExceptionCode responseCode) {
this.responseCode = responseCode;
this.httpStatus = responseCode.getStatus();
this.message = responseCode.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.ezcode.codetest.domain.submission.exception.code;

import org.ezcode.codetest.common.base.exception.ResponseCode;
import org.springframework.http.HttpStatus;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum GitHubExceptionCode implements ResponseCode {

INVALID_ACCESS_TOKEN(false, HttpStatus.UNAUTHORIZED, "유효하지 않은 GitHub 액세스 토큰입니다."),
AUTHENTICATION_FAILED(false, HttpStatus.UNAUTHORIZED, "GitHub 인증에 실패했습니다."),
PERMISSION_DENIED(false, HttpStatus.FORBIDDEN, "해당 리소스에 대한 권한이 없습니다."),

REPOSITORY_NOT_FOUND(false, HttpStatus.NOT_FOUND, "지정한 리포지토리를 찾을 수 없습니다."),
BRANCH_NOT_FOUND(false, HttpStatus.NOT_FOUND, "지정한 브랜치를 찾을 수 없습니다."),
SOURCE_FILE_NOT_FOUND(false, HttpStatus.NOT_FOUND, "소스 파일을 찾을 수 없습니다."),

TREE_CREATION_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "새 Git 트리 생성에 실패했습니다."),
COMMIT_CREATION_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "커밋 생성에 실패했습니다."),
BRANCH_UPDATE_FAILED(false, HttpStatus.INTERNAL_SERVER_ERROR, "브랜치 포인터 업데이트(푸시)에 실패했습니다."),

RATE_LIMIT_EXCEEDED(false, HttpStatus.TOO_MANY_REQUESTS, "GitHub API 호출 한도를 초과했습니다."),
NETWORK_ERROR(false, HttpStatus.SERVICE_UNAVAILABLE, "GitHub 서버와의 통신 중 네트워크 오류가 발생했습니다."),

UNKNOWN_ERROR(false, HttpStatus.INTERNAL_SERVER_ERROR, "알 수 없는 GitHub 연동 오류가 발생했습니다.");

private final boolean success;
private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.ezcode.codetest.infrastructure.event.dto.submission.response;

import org.ezcode.codetest.infrastructure.github.model.PushStatus;

public record GitPushStatusResponse(

String displayMessage

) {
public GitPushStatusResponse(PushStatus pushStatus) {
this(pushStatus.getDisplayMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void onMessage(MapRecord<String, String, String> message) {

try {
log.info("[컨슈머 수신] {}", msg.sessionKey());
submissionService.submitCodeStream(msg);
submissionService.processSubmissionAsync(msg);

log.info("[컨슈머 ACK] messageId={}", message.getId());
redisTemplate.opsForStream().acknowledge("judge-group", message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import java.util.List;

import org.ezcode.codetest.application.submission.dto.event.GitPushStatusEvent;
import org.ezcode.codetest.application.submission.dto.event.SubmissionErrorEvent;
import org.ezcode.codetest.application.submission.dto.event.SubmissionJudgingFinishedEvent;
import org.ezcode.codetest.application.submission.dto.event.TestcaseListInitializedEvent;
import org.ezcode.codetest.application.submission.dto.event.TestcaseEvaluatedEvent;
import org.ezcode.codetest.infrastructure.event.dto.submission.response.GitPushStatusResponse;
import org.ezcode.codetest.infrastructure.event.dto.submission.response.ErrorWsResponse;
import org.ezcode.codetest.infrastructure.event.dto.submission.response.SubmissionFinalResultResponse;
import org.ezcode.codetest.infrastructure.event.dto.submission.response.InitTestcaseListResponse;
Expand Down Expand Up @@ -47,4 +49,10 @@ public void onSubmissionError(SubmissionErrorEvent event) {
ErrorWsResponse wsDto = ErrorWsResponse.from(event.code());
messageService.sendError(event.sessionKey(), wsDto);
}

@EventListener
public void onGitPushStatus(GitPushStatusEvent event) {
GitPushStatusResponse wsDto = new GitPushStatusResponse(event.pushStatus());
messageService.sendGitStatus(event.sessionKey(), wsDto);
}
}
Loading