Skip to content

Commit

Permalink
feat: ✨ 분산 코디네이션 도입을 고려한 서비스 탐색 서비스 API (#162)
Browse files Browse the repository at this point in the history
* chore: 분산 코디네이션 설정 - 채팅 서버 url 고정값 설정

* chore: 분산 코디네이터 의존성 api 모듈 제어권 설정

* feat: 유효한 채팅 서버 url을 반환하기 위한 dto 정의

* feat: infra 모듈 내, 분산 코디네이션 인터페이스 및 기본 구현체 정의

* docs: 서비스 탐색 api 문서 정의

* feat: 채팅 서버 url 반환 usecase 구현

* feat: 채팅 서버 탐색 컨트롤러 구현

* fix: swagger config group에 서비스 탐색 서비스 항목 추가

* fix: 소켓 usecase와 채팅 서버 탐색 서비스 분리
  • Loading branch information
psychology50 authored Oct 8, 2024
1 parent d1ae456 commit f860e57
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package kr.co.pennyway.api.apis.socket.api;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.SchemaProperty;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;

@Tag(name = "[서비스 탐색 API]")
public interface SocketApi {
@Operation(summary = "연결 가능한 채팅 서버 정보 조회", description = "요청 헤더, 바디를 기반으로 연결 가능한 채팅 서버 정보를 조회한 후, 채팅 서버 정보를 반환합니다.")
@ApiResponse(responseCode = "200", description = "연결 가능한 채팅 서버 정보 조회 성공", content = @Content(schemaProperties = @SchemaProperty(name = "url", schema = @Schema(type = "string", description = "채팅 서버 URL"))))
ResponseEntity<?> getChatServerInfo();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package kr.co.pennyway.api.apis.socket.controller;

import kr.co.pennyway.api.apis.socket.api.SocketApi;
import kr.co.pennyway.api.apis.socket.usecase.SocketUseCase;
import kr.co.pennyway.api.common.response.SuccessResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/v2/socket")
public class SocketController implements SocketApi {
private static final String CHAT_SERVER_URL = "chatServerUrl";
private final SocketUseCase socketUseCase;

@Override
@GetMapping("/chat")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> getChatServerInfo() {
return ResponseEntity.ok(SuccessResponse.from(CHAT_SERVER_URL, socketUseCase.getChatServerUrl()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.co.pennyway.api.apis.socket.service;

import kr.co.pennyway.infra.client.coordinator.CoordinatorService;
import kr.co.pennyway.infra.client.coordinator.WebSocket;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class ChatServerSearchService {
private final CoordinatorService defaultCoordinatorService;

public String getChatServerUrl() {
WebSocket.ChatServerUrl response = defaultCoordinatorService.readChatServerUrl(null, null);

return response.url();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.co.pennyway.api.apis.socket.usecase;

import kr.co.pennyway.api.apis.socket.service.ChatServerSearchService;
import kr.co.pennyway.common.annotation.UseCase;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@UseCase
@RequiredArgsConstructor
public class SocketUseCase {
private final ChatServerSearchService chatServerSearchService;

public String getChatServerUrl() {
return chatServerSearchService.getChatServerUrl();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
KakaoOidcProperties.class
})
@EnablePennywayInfraConfig({
PennywayInfraConfigGroup.FCM
PennywayInfraConfigGroup.FCM,
PennywayInfraConfigGroup.DistributedCoordinationConfig
})
public class InfraConfig {
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ public GroupedOpenApi ledgerApi() {
.build();
}

@Bean
public GroupedOpenApi socketApi() {
String[] targets = {"kr.co.pennyway.api.apis.socket"};

return GroupedOpenApi.builder()
.packagesToScan(targets)
.group("서비스 탐색 서비스")
.addOperationCustomizer(customizer())
.build();
}

@Bean
public GroupedOpenApi backOfficeApi() {
String[] targets = {"kr.co.pennyway.api.apis.question"};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kr.co.pennyway.infra.client.coordinator;

import java.util.Map;

public interface CoordinatorService {
/**
* 채팅 서버에 연결하려는 클라이언트에게 유효한 채팅 서버의 URL을 반환합니다.
* 이 메서드는 다양한 방식으로 구현될 수 있습니다.
* 예를 들어, 단일 채팅 서버 환경에서는 고정된 채팅 서버 URL을 반환할 수 있습니다.
* 분산 채팅 서버 환경이라면, 분산 코디네이션과 같은 서비스를 통해 사용자의 지리적 위치, 채팅 서버의 부하 상태 등을 고려하여 적절한 채팅 서버 URL을 반환할 수 있습니다.
*/
WebSocket.ChatServerUrl readChatServerUrl(Map<String, String> headers, Object payload);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.co.pennyway.infra.client.coordinator;

import java.util.Map;

/**
* 이 클래스는 단일 채팅 서버 환경에서 사용할 수 있는 기본적인 {@link CoordinatorService} 구현체입니다.
* 미리 정의된 채팅 서버 URL을 반환합니다.
*/
public class DefaultCoordinatorService implements CoordinatorService {
private final String chatServerUrl;

public DefaultCoordinatorService(String chatServerUrl) {
this.chatServerUrl = chatServerUrl;
}

@Override
public WebSocket.ChatServerUrl readChatServerUrl(Map<String, String> headers, Object payload) {
return WebSocket.ChatServerUrl.of(chatServerUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.co.pennyway.infra.client.coordinator;

import java.util.Objects;

public final class WebSocket {
public record ChatServerUrl(String url) {
public ChatServerUrl {
Objects.requireNonNull(url, "url must not be null");
}

public static ChatServerUrl of(String url) {
return new ChatServerUrl(url);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package kr.co.pennyway.infra.common.importer;

import kr.co.pennyway.infra.config.DistributedCoordinationConfig;
import kr.co.pennyway.infra.config.FcmConfig;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum PennywayInfraConfigGroup {
FCM(FcmConfig.class);
FCM(FcmConfig.class),
DistributedCoordinationConfig(DistributedCoordinationConfig.class);

private final Class<? extends PennywayInfraConfig> configClass;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.co.pennyway.infra.config;

import kr.co.pennyway.infra.client.coordinator.CoordinatorService;
import kr.co.pennyway.infra.client.coordinator.DefaultCoordinatorService;
import kr.co.pennyway.infra.common.importer.PennywayInfraConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

public class DistributedCoordinationConfig implements PennywayInfraConfig {
private final String chatServerUrl;

public DistributedCoordinationConfig(@Value("${distributed-coordination.chat-server.url}") String chatServerUrl) {
this.chatServerUrl = chatServerUrl;
}

@Bean
public CoordinatorService defaultCoordinatorService() {
return new DefaultCoordinatorService(chatServerUrl);
}
}
4 changes: 4 additions & 0 deletions pennyway-infra/src/main/resources/application-infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ oauth2:
jwks-uri: ${APPLE_JWKS_URI:http://localhost}
secret: ${APPLE_CLIENT_SECRET:pennyway-jayang-was}

distributed-coordination:
chat-server:
url: ${CHAT_SERVER_URL:ws://localhost:8000/chat}

---
spring:
config:
Expand Down

0 comments on commit f860e57

Please sign in to comment.