Skip to content

Commit c8991ff

Browse files
author
EpicFn
committed
new : emitter 관리 service, controller 생성
1 parent 860d3c3 commit c8991ff

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.tuna.zoopzoop.backend.domain.SSE.controller;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.security.core.Authentication;
5+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
10+
import org.tuna.zoopzoop.backend.domain.SSE.service.EmitterService;
11+
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
12+
13+
@RestController
14+
@RequestMapping("/api/v1/notifications")
15+
@RequiredArgsConstructor
16+
public class ApiV1NotificationController {
17+
private final EmitterService emitterService;
18+
19+
/**
20+
* SSE 구독 엔드포인트
21+
* @param userDetails - 현재 인증된 사용자 정보
22+
* @return SseEmitter - 클라이언트와의 SSE 연결을 관리하는 객체
23+
*/
24+
@GetMapping(value = "/subscribe", produces = "text/event-stream")
25+
public SseEmitter subscribe(
26+
@AuthenticationPrincipal CustomUserDetails userDetails
27+
) {
28+
// 1. 현재 로그인한 사용자의 ID를 가져옴
29+
Long memberId = (long) userDetails.getMember().getId();
30+
31+
// 2. EmitterService를 통해 Emitter를 생성하고 반환
32+
return emitterService.addEmitter(memberId);
33+
}
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.tuna.zoopzoop.backend.domain.SSE.service;
2+
3+
import org.springframework.stereotype.Service;
4+
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
5+
6+
import java.io.IOException;
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentHashMap;
9+
10+
@Service
11+
public class EmitterService {
12+
// 1. 모든 Emitter를 저장하는 ConcurrentHashMap
13+
private final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
14+
15+
/**
16+
* 새로운 Emitter 생성 및 저장
17+
* @param memberId - 사용자 ID
18+
* @return SseEmitter - 생성된 Emitter 객체
19+
*/
20+
public SseEmitter addEmitter(Long memberId) {
21+
// 1시간 타임아웃 설정
22+
SseEmitter emitter = new SseEmitter(3600L * 1000);
23+
this.emitters.put(memberId, emitter);
24+
25+
// Emitter 완료 또는 타임아웃 시 Map에서 삭제
26+
emitter.onCompletion(() -> this.emitters.remove(memberId));
27+
emitter.onTimeout(() -> this.emitters.remove(memberId));
28+
29+
// 503 에러 방지를 위한 더미 이벤트 전송
30+
try {
31+
emitter.send(SseEmitter.event().name("connect").data("SSE connected!"));
32+
} catch (IOException e) {
33+
// 예외 처리
34+
}
35+
36+
return emitter;
37+
}
38+
39+
/**
40+
* 특정 사용자에게 이벤트 전송
41+
* @param memberId - 사용자 ID
42+
* @param eventName - 이벤트 이름
43+
* @param data - 전송할 데이터 객체
44+
*/
45+
public void sendNotification(Long memberId, String eventName, Object data) {
46+
SseEmitter emitter = this.emitters.get(memberId);
47+
if (emitter != null) {
48+
try {
49+
// data 객체를 JSON 문자열로 변환하여 전송해야 함 (Controller에서는 자동 변환)
50+
emitter.send(SseEmitter.event().name(eventName).data(data));
51+
} catch (IOException e) {
52+
this.emitters.remove(memberId);
53+
}
54+
}
55+
}
56+
}

src/main/java/org/tuna/zoopzoop/backend/domain/space/space/controller/ApiV1SpaceController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ public RsData<ResBodyForSpaceInfo> getSpace(
220220
@Operation(summary = "Liveblocks 접속 토큰 발급")
221221
public ResponseEntity<RsData<ResBodyForAuthToken>> getAuthToken(
222222
@PathVariable Integer spaceId,
223-
@AuthenticationPrincipal CustomUserDetails userDetails) throws AccessDeniedException {
224-
223+
@AuthenticationPrincipal CustomUserDetails userDetails
224+
) throws AccessDeniedException {
225225
Member member = userDetails.getMember();
226226
String token = dashboardService.getAuthTokenForSpace(spaceId, member);
227227

0 commit comments

Comments
 (0)