4
4
import java .util .List ;
5
5
import java .util .Optional ;
6
6
import lombok .RequiredArgsConstructor ;
7
+ import lombok .extern .slf4j .Slf4j ;
7
8
import org .springframework .context .ApplicationEventPublisher ;
9
+ import org .springframework .data .redis .listener .ChannelTopic ;
10
+ import org .springframework .data .redis .listener .RedisMessageListenerContainer ;
8
11
import org .springframework .stereotype .Service ;
9
12
import org .springframework .transaction .annotation .Transactional ;
13
+ import yeonba .be .chatting .dto .request .ChatPublishRequest ;
14
+ import yeonba .be .chatting .dto .response .ChatMessageResponse ;
10
15
import yeonba .be .chatting .dto .response .ChatRoomResponse ;
11
16
import yeonba .be .chatting .entity .ChatMessage ;
12
17
import yeonba .be .chatting .entity .ChatRoom ;
15
20
import yeonba .be .chatting .repository .chatroom .ChatRoomCommand ;
16
21
import yeonba .be .chatting .repository .chatroom .ChatRoomQuery ;
17
22
import yeonba .be .exception .BlockException ;
23
+ import yeonba .be .exception .ChatException ;
18
24
import yeonba .be .exception .GeneralException ;
19
25
import yeonba .be .exception .NotificationException ;
20
26
import yeonba .be .notification .entity .Notification ;
26
32
import yeonba .be .user .repository .block .BlockQuery ;
27
33
import yeonba .be .user .repository .user .UserQuery ;
28
34
35
+ @ Slf4j
29
36
@ Service
30
37
@ RequiredArgsConstructor
31
38
public class ChatService {
@@ -36,9 +43,47 @@ public class ChatService {
36
43
private final ChatMessageQuery chatMessageQuery ;
37
44
private final UserQuery userQuery ;
38
45
private final BlockQuery blockQuery ;
39
- private final NotificationQuery notificationQuey ;
46
+ private final NotificationQuery notificationQuery ;
40
47
41
48
private final ApplicationEventPublisher eventPublisher ;
49
+ private final RedisChattingPublisher redisChattingPublisher ;
50
+ private final RedisChattingSubscriber adapter ;
51
+ private final RedisMessageListenerContainer container ;
52
+
53
+ @ Transactional
54
+ public void publish (ChatPublishRequest request ) {
55
+
56
+ ChatRoom chatRoom = chatRoomQuery .findById (request .getRoomId ());
57
+ User sender = userQuery .findById (request .getUserId ());
58
+ User receiver = chatRoom .getSender ().equals (sender ) ? chatRoom .getReceiver ()
59
+ : chatRoom .getSender ();
60
+
61
+ // TODO: 메시지 Pub/Sub과 메시지 저장 로직 비동기 처리(id, user 등 request, response 변경 가능)
62
+ redisChattingPublisher .publish (new ChannelTopic (String .valueOf (request .getRoomId ())),
63
+ request );
64
+ chatMessageCommand .save (
65
+ new ChatMessage (chatRoom , sender , receiver , request .getContent (), request .getSentAt ()));
66
+ }
67
+
68
+ @ Transactional (readOnly = true )
69
+ public List <ChatMessageResponse > getChatMessages (long userId , long roomId ) {
70
+
71
+ User user = userQuery .findById (userId );
72
+
73
+ ChatRoom chatRoom = chatRoomQuery .findById (roomId );
74
+
75
+ if (!user .equals (chatRoom .getSender ()) && !user .equals (chatRoom .getReceiver ())) {
76
+ throw new GeneralException (ChatException .NOT_YOUR_CHAT_ROOM );
77
+ }
78
+
79
+ List <ChatMessage > chatMessages = chatMessageQuery .findAllByChatRoom (chatRoom );
80
+
81
+ return chatMessages .stream ()
82
+ .map (chatMessage -> new ChatMessageResponse (chatMessage .getSender ().getId (),
83
+ chatMessage .getSender ().getNickname (),
84
+ chatMessage .getContent (), chatMessage .getSentAt ()))
85
+ .toList ();
86
+ }
42
87
43
88
@ Transactional (readOnly = true )
44
89
public List <ChatRoomResponse > getChatRooms (long userId ) {
@@ -79,6 +124,13 @@ public void requestChat(long senderId, long receiverId) {
79
124
throw new GeneralException (BlockException .ALREADY_BLOCKED_USER );
80
125
}
81
126
127
+ // 이미 채팅 중인 사용자인 지 검증
128
+ boolean chatRoomExist =
129
+ chatRoomQuery .existsBy (sender , receiver ) || chatRoomQuery .existsBy (receiver , sender );
130
+ if (chatRoomExist ) {
131
+ throw new GeneralException (ChatException .ALREADY_CHAT_USER );
132
+ }
133
+
82
134
// 비활성화된 채팅방 생성
83
135
chatRoomCommand .createChatRoom (new ChatRoom (sender , receiver ));
84
136
@@ -89,9 +141,10 @@ public void requestChat(long senderId, long receiverId) {
89
141
eventPublisher .publishEvent (notificationSendEvent );
90
142
}
91
143
144
+ @ Transactional
92
145
public void acceptRequestedChat (long userId , long notificationId ) {
93
146
94
- Notification notification = notificationQuey .findById (notificationId );
147
+ Notification notification = notificationQuery .findById (notificationId );
95
148
96
149
// 채팅 요청 알림인지 검증
97
150
if (!notification .getType ().isChattingRequest ()) {
@@ -105,15 +158,22 @@ public void acceptRequestedChat(long userId, long notificationId) {
105
158
// 본인에게 온 채팅 요청인지 검증
106
159
if (receiver .equals (userQuery .findById (userId ))) {
107
160
108
- throw new GeneralException (NotificationException .NOT_YOUR_CHATTING_REQUEST_NOTIFICATION );
161
+ throw new GeneralException (
162
+ NotificationException .NOT_YOUR_CHATTING_REQUEST_NOTIFICATION );
109
163
}
110
164
111
165
// 채팅방 활성화
112
166
ChatRoom chatRoom = chatRoomQuery .findBy (sender , receiver );
113
167
chatRoom .activeRoom ();
114
168
115
- String activeRoom = "채팅방이 활성화되었습니다." ;
116
- chatMessageCommand .createChatMessage (new ChatMessage (chatRoom , sender , receiver , activeRoom ));
169
+ String activeRoom = "채팅방이 생성되었습니다." ;
170
+
171
+ chatMessageCommand .save (
172
+ new ChatMessage (chatRoom , sender , receiver , activeRoom , LocalDateTime .now ()));
173
+
174
+ // 메시지 수신을 위한 Redis Pub/Sub 구독
175
+ container .addMessageListener (adapter , new ChannelTopic (String .valueOf (chatRoom .getId ())));
176
+ log .info ("channel topic 생성 {}" , chatRoom .getId ());
117
177
118
178
NotificationSendEvent notificationSendEvent = new NotificationSendEvent (
119
179
NotificationType .CHATTING_REQUEST_ACCEPTED , receiver , sender ,
0 commit comments