diff --git a/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/StatusGrpcService.kt b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/StatusGrpcService.kt new file mode 100644 index 0000000..9117bbb --- /dev/null +++ b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/StatusGrpcService.kt @@ -0,0 +1,85 @@ +package hs.kr.entrydsm.status.infrastructure.grpc.server + +import com.google.protobuf.Empty +import hs.kr.entrydsm.casper.status.proto.StatusServiceGrpcKt +import hs.kr.entrydsm.casper.status.proto.StatusServiceProto +import hs.kr.entrydsm.status.infrastructure.grpc.server.dto.response.InternalStatusResponse +import hs.kr.entrydsm.status.domain.status.application.port.`in`.GetAllStatusUseCase +import hs.kr.entrydsm.status.domain.status.application.port.`in`.GetStatusByReceiptCodeUseCase +import hs.kr.entrydsm.status.domain.status.application.port.`in`.UpdateExamCodeUseCase +import hs.kr.entrydsm.status.infrastructure.grpc.server.mapper.StatusGrpcMapper +import net.devh.boot.grpc.server.service.GrpcService + +/** + * 상태 관련 gRPC 서비스 구현 클래스입니다. + * 다른 마이크로서비스와의 gRPC 통신을 통해 상태 정보를 제공합니다. + * + * @property getStatusByReceiptCodeUseCase 접수번호로 상태 조회 유스케이스 + * @property getAllStatusUseCase 모든 상태 조회 유스케이스 + * @property updateExamCodeUseCase 수험번호 업데이트 유스케이스 + * @property statusGrpcMapper gRPC 메시지 변환 매퍼 + */ +@GrpcService +class StatusGrpcService( + private val getStatusByReceiptCodeUseCase: GetStatusByReceiptCodeUseCase, + private val getAllStatusUseCase: GetAllStatusUseCase, + private val updateExamCodeUseCase: UpdateExamCodeUseCase, + private val statusGrpcMapper: StatusGrpcMapper +): StatusServiceGrpcKt.StatusServiceCoroutineImplBase() { + + /** + * 모든 상태 리스트를 조회합니다. + * + * @param request Empty 요청 + * @return 모든 상태 정보를 포함한 gRPC 응답 + */ + override suspend fun getStatusList(request: Empty): StatusServiceProto.GetStatusListResponse { + val statusList = getAllStatusUseCase.execute() + + val internalStatusResponseList = statusList.map { + InternalStatusResponse( + id = it.id, + applicationStatus = it.applicationStatus, + examCode = it.examCode, + isFirstRoundPass = it.isFirstRoundPass, + isSecondRoundPass = it.isSecondRoundPass, + receiptCode = it.receiptCode + ) + } + return statusGrpcMapper.toGetStatusListResponse(internalStatusResponseList) + } + + /** + * 접수번호로 특정 상태를 조회합니다. + * + * @param request 접수번호가 포함된 gRPC 요청 + * @return 해당 접수번호의 상태 정보 gRPC 응답 + */ + override suspend fun getStatusByReceiptCode(request: StatusServiceProto.GetStatusByReceiptCodeRequest): StatusServiceProto.GetStatusByReceiptCodeResponse { + + val status = getStatusByReceiptCodeUseCase.execute(request.receiptCode) + + val internalStatusResponse = InternalStatusResponse( + id = status.id, + applicationStatus = status.applicationStatus, + examCode = status.examCode, + isFirstRoundPass = status.isFirstRoundPass, + isSecondRoundPass = status.isSecondRoundPass, + receiptCode = status.receiptCode + ) + return statusGrpcMapper.toGetStatusByReceiptCodeResponse(internalStatusResponse) + } + + /** + * 수험번호를 업데이트합니다. + * + * @param request 접수번호와 새로운 수험번호가 포함된 gRPC 요청 + * @return Empty 응답 + */ + override suspend fun updateExamCode(request: StatusServiceProto.GetExamCodeRequest): Empty { + + updateExamCodeUseCase.execute(request.receiptCode, request.examCode) + return Empty.getDefaultInstance() + } + +} diff --git a/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/dto/response/InternalStatusResponse.kt b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/dto/response/InternalStatusResponse.kt new file mode 100644 index 0000000..abde20f --- /dev/null +++ b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/dto/response/InternalStatusResponse.kt @@ -0,0 +1,23 @@ +package hs.kr.entrydsm.status.infrastructure.grpc.server.dto.response + +import hs.kr.entrydsm.status.domain.status.model.ApplicationStatus + +/** + * 내부 gRPC 통신용 상태 응답 DTO 클래스입니다. + * 다른 마이크로서비스와의 통신에서 상태 정보를 전달하는 데 사용됩니다. + * + * @property id 상태 식별자 + * @property applicationStatus 현재 지원 상태 + * @property examCode 수험번호 + * @property isFirstRoundPass 1차 전형 합격 여부 + * @property isSecondRoundPass 2차 전형 합격 여부 + * @property receiptCode 접수번호 + */ +data class InternalStatusResponse( + val id: Long, + val applicationStatus: ApplicationStatus, + var examCode: String? = null, + var isFirstRoundPass: Boolean = false, + var isSecondRoundPass: Boolean = false, + val receiptCode: Long +) diff --git a/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/mapper/StatusGrpcMapper.kt b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/mapper/StatusGrpcMapper.kt new file mode 100644 index 0000000..cd83184 --- /dev/null +++ b/casper-status/src/main/kotlin/hs/kr/entrydsm/status/infrastructure/grpc/server/mapper/StatusGrpcMapper.kt @@ -0,0 +1,73 @@ +package hs.kr.entrydsm.status.infrastructure.grpc.server.mapper + +import hs.kr.entrydsm.casper.status.proto.StatusServiceProto +import hs.kr.entrydsm.status.domain.status.model.ApplicationStatus +import hs.kr.entrydsm.status.infrastructure.grpc.server.dto.response.InternalStatusResponse +import org.springframework.stereotype.Component + +/** + * 상태 정보를 gRPC 프로토콜 버퍼와 매핑하는 매퍼 클래스입니다. + * 내부 DTO와 gRPC 메시지 간의 변환을 담당합니다. + */ +@Component +class StatusGrpcMapper { + + /** + * 상태 리스트를 gRPC 응답으로 변환합니다. + * + * @param statusList 변환할 상태 응답 리스트 + * @return gRPC 상태 리스트 응답 + */ + fun toGetStatusListResponse(statusList: List): StatusServiceProto.GetStatusListResponse { + return StatusServiceProto.GetStatusListResponse.newBuilder() + .addAllStatusList(statusList.map { toStatusInfoElement(it) }) + .build() + } + + /** + * 단일 상태를 gRPC 응답으로 변환합니다. + * + * @param response 변환할 상태 응답 + * @return gRPC 상태 조회 응답 + */ + fun toGetStatusByReceiptCodeResponse(response: InternalStatusResponse): StatusServiceProto.GetStatusByReceiptCodeResponse { + return StatusServiceProto.GetStatusByReceiptCodeResponse.newBuilder() + .setStatus(toStatusInfoElement(response)) + .build() + } + + /** + * 상태 응답을 gRPC 상태 정보 요소로 변환합니다. + * + * @param response 변환할 상태 응답 + * @return gRPC 상태 정보 요소 + */ + private fun toStatusInfoElement(response: InternalStatusResponse): StatusServiceProto.StatusInfoElement { + return StatusServiceProto.StatusInfoElement.newBuilder() + .setId(response.id) + .setApplicationStatus(toProtoApplicationStatus(response.applicationStatus)) + .setExamCode(response.examCode) + .setIsFirstRoundPass(response.isFirstRoundPass) + .setIsSecondRoundPass(response.isSecondRoundPass) + .setReceiptCode(response.receiptCode) + .build() + } + + /** + * 도메인 지원 상태를 gRPC 프로토콜 지원 상태로 변환합니다. + * + * @param applicationStatus 변환할 도메인 지원 상태 + * @return gRPC 프로토콜 지원 상태 + */ + private fun toProtoApplicationStatus(applicationStatus: ApplicationStatus): StatusServiceProto.ApplicationStatus { + return when (applicationStatus){ + ApplicationStatus.NOT_APPLIED -> StatusServiceProto.ApplicationStatus.NOT_APPLIED + ApplicationStatus.SUBMITTED -> StatusServiceProto.ApplicationStatus.SUBMITTED + ApplicationStatus.WRITING -> StatusServiceProto.ApplicationStatus.WRITING + ApplicationStatus.WAITING_DOCUMENTS -> StatusServiceProto.ApplicationStatus.WAITING_DOCUMENTS + ApplicationStatus.DOCUMENTS_RECEIVED -> StatusServiceProto.ApplicationStatus.DOCUMENTS_RECEIVED + ApplicationStatus.SCREENING_IN_PROGRESS -> StatusServiceProto.ApplicationStatus.SCREENING_IN_PROGRESS + ApplicationStatus.RESULT_ANNOUNCED -> StatusServiceProto.ApplicationStatus.RESULT_ANNOUNCED + } + } +} diff --git a/casper-status/src/main/proto/status.proto b/casper-status/src/main/proto/status.proto new file mode 100644 index 0000000..6e93aee --- /dev/null +++ b/casper-status/src/main/proto/status.proto @@ -0,0 +1,52 @@ +syntax ="proto3"; + +import "google/protobuf/empty.proto"; + +package status.proto; + +option java_package = "hs.kr.entrydsm.casper.status.proto"; +option java_outer_classname = "StatusServiceProto"; + +service StatusService{ + rpc getStatusList(google.protobuf.Empty) returns (GetStatusListResponse); + rpc getStatusByReceiptCode(GetStatusByReceiptCodeRequest) returns (GetStatusByReceiptCodeResponse); + rpc updateExamCode(GetExamCodeRequest) returns (google.protobuf.Empty); +} + + +message GetStatusListResponse { + repeated StatusInfoElement status_list = 1; +} + +message GetStatusByReceiptCodeRequest{ + int64 receipt_code = 1; +} + +message GetStatusByReceiptCodeResponse{ + StatusInfoElement status = 1; +} + +message GetExamCodeRequest{ + int64 receipt_code = 1; + string examCode = 2; +} + +message StatusInfoElement{ + int64 id = 1; + ApplicationStatus applicationStatus = 2; + string examCode = 3; + bool isFirstRoundPass = 4; + bool isSecondRoundPass = 5; + int64 receiptCode = 6; +} + +enum ApplicationStatus { + UNSPECIFIED = 0; + NOT_APPLIED = 1; + WRITING = 2; + SUBMITTED = 3; + WAITING_DOCUMENTS = 4; + DOCUMENTS_RECEIVED = 5; + SCREENING_IN_PROGRESS = 6; + RESULT_ANNOUNCED = 7; +}