Skip to content

Commit 2604aee

Browse files
committed
Merge remote-tracking branch 'origin/dev' into feat/21
# Conflicts: # backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java
2 parents d8e82fe + cf25ffa commit 2604aee

32 files changed

+421
-109
lines changed

.github/workflows/bump-version.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: release
2+
on:
3+
pull_request:
4+
types:
5+
- labeled
6+
7+
jobs:
8+
release:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: haya14busa/action-bumpr@v1

.github/workflows/release.yml

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,52 @@ on:
33
push:
44
branches:
55
- main
6-
pull_request:
7-
types:
8-
- labeled
6+
7+
env:
8+
REGISTRY: ghcr.io
9+
IMAGE_NAME: ${{ github.repository }}
910

1011
jobs:
1112
release:
1213
runs-on: ubuntu-latest
14+
outputs:
15+
next_version: ${{ steps.bump.outputs.next_version }}
1316
steps:
1417
- uses: actions/checkout@v4
1518
- uses: haya14busa/action-bumpr@v1
19+
id: bump
20+
21+
package:
22+
runs-on: ubuntu-latest
23+
needs: release
24+
25+
permissions:
26+
contents: read
27+
packages: write
28+
attestations: write
29+
id-token: write
30+
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
41+
- uses: docker/metadata-action@v5
42+
id: meta
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
type=raw,value=latest
47+
type=raw,value=${{ needs.release.outputs.next_version }}
48+
49+
- uses: docker/build-push-action@v6
50+
with:
51+
context: ./backend
52+
push: true
53+
tags: ${{ steps.meta.outputs.tags }}
54+
labels: ${{ steps.meta.outputs.labels }}

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ jobs:
99
contents: read
1010
env:
1111
PROJECT_DIR: backend
12+
KAKAO_CLIENT: ${{ secrets.KAKAO_CLIENT }}
13+
KAKAO_SECRET: ${{ secrets.KAKAO_SECRET }}
1214
steps:
1315
- uses: actions/checkout@v4
1416

backend/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM gradle:jdk21 AS builder
2+
WORKDIR /app
3+
COPY . .
4+
RUN ./gradlew clean build -x test
5+
6+
FROM openjdk:21-slim
7+
WORKDIR /app
8+
COPY --from=builder /app/build/libs/*.jar app.jar
9+
ENTRYPOINT ["java", "-jar", "app.jar"]

backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
package io.f1.backend.domain.game.app;
22

3-
import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSettingResponse;
4-
import static io.f1.backend.domain.game.mapper.RoomMapper.toPlayerListResponse;
5-
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomResponse;
6-
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSetting;
7-
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSettingResponse;
3+
import static io.f1.backend.domain.game.mapper.RoomMapper.*;
84

95
import io.f1.backend.domain.game.dto.RoomExitData;
106
import io.f1.backend.domain.game.dto.RoomInitialData;
@@ -18,15 +14,23 @@
1814
import io.f1.backend.domain.game.dto.response.RoomResponse;
1915
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
2016
import io.f1.backend.domain.game.dto.response.SystemNoticeResponse;
17+
import io.f1.backend.domain.game.event.RoomCreatedEvent;
2118
import io.f1.backend.domain.game.model.GameSetting;
2219
import io.f1.backend.domain.game.model.Player;
2320
import io.f1.backend.domain.game.model.Room;
2421
import io.f1.backend.domain.game.model.RoomSetting;
2522
import io.f1.backend.domain.game.model.RoomState;
2623
import io.f1.backend.domain.game.store.RoomRepository;
24+
import io.f1.backend.domain.quiz.app.QuizService;
2725
import io.f1.backend.domain.quiz.entity.Quiz;
2826
import io.f1.backend.domain.user.entity.User;
2927
import java.time.LocalDateTime;
28+
29+
import lombok.RequiredArgsConstructor;
30+
31+
import org.springframework.context.ApplicationEventPublisher;
32+
import org.springframework.stereotype.Service;
33+
3034
import java.util.List;
3135
import java.util.Map;
3236
import java.util.Optional;
@@ -38,8 +42,10 @@
3842
@RequiredArgsConstructor
3943
public class RoomService {
4044

45+
private final QuizService quizService;
4146
private final RoomRepository roomRepository;
4247
private final AtomicLong roomIdGenerator = new AtomicLong(0);
48+
private final ApplicationEventPublisher eventPublisher;
4349

4450
public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object> loginUser) {
4551

@@ -51,7 +57,14 @@ public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object
5157

5258
Long newId = roomIdGenerator.incrementAndGet();
5359

54-
roomRepository.saveRoom(new Room(newId, roomSetting, gameSetting, host));
60+
Room room = new Room(newId, roomSetting, gameSetting, host);
61+
62+
roomRepository.saveRoom(room);
63+
64+
Long quizId = room.getGameSetting().getQuizId();
65+
Quiz quiz = quizService.getQuizById(quizId);
66+
67+
eventPublisher.publishEvent(new RoomCreatedEvent(room, quiz));
5568

5669
return new RoomCreateResponse(newId);
5770
}
@@ -74,17 +87,17 @@ public void validateRoom(RoomValidationRequest request) {
7487
}
7588

7689
if (room.getRoomSetting().locked()
77-
&& !room.getRoomSetting().password().equals(request.password())) {
90+
&& !room.getRoomSetting().password().equals(request.password())) {
7891
throw new IllegalArgumentException("401 비밀번호가 일치하지 않습니다.");
7992
}
8093
}
8194

8295
public RoomInitialData enterRoom(Long roomId, String sessionId) {
8396

8497
Room room =
85-
roomRepository
86-
.findRoom(roomId)
87-
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
98+
roomRepository
99+
.findRoom(roomId)
100+
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
88101

89102
// todo security
90103
Player player = new Player(1L, "빵야빵야");
@@ -142,26 +155,18 @@ public RoomExitData exitRoom(Long roomId, String sessionId) {
142155
return new RoomExitData(destination,playerListResponse, systemNoticeResponse, false);
143156
}
144157

145-
// todo quizService에서 퀴즈 조회 메서드로 변경
146158
public RoomListResponse getAllRooms() {
147159
List<Room> rooms = roomRepository.findAll();
148160
List<RoomResponse> roomResponses =
149-
rooms.stream()
150-
.map(
151-
room -> {
152-
User user = new User(); // 임시 유저 객체
153-
user.setNickname("임시 유저 닉네임");
154-
155-
Quiz quiz = new Quiz(); // 임시 퀴즈 객체
156-
quiz.setTitle("임시 퀴즈 제목");
157-
quiz.setDescription("임시 퀴즈 설명");
158-
quiz.setThumbnailUrl("임시 이미지");
159-
quiz.setQuestions(List.of());
160-
quiz.setCreator(user);
161-
162-
return toRoomResponse(room, quiz);
163-
})
164-
.toList();
161+
rooms.stream()
162+
.map(
163+
room -> {
164+
Long quizId = room.getGameSetting().getQuizId();
165+
Quiz quiz = quizService.getQuizById(quizId);
166+
167+
return toRoomResponse(room, quiz);
168+
})
169+
.toList();
165170
return new RoomListResponse(roomResponses);
166171
}
167172

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.f1.backend.domain.game.event;
2+
3+
import io.f1.backend.domain.game.model.Room;
4+
import io.f1.backend.domain.quiz.entity.Quiz;
5+
6+
public record RoomCreatedEvent(Room room, Quiz quiz) {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package io.f1.backend.domain.game.event;
2+
3+
public record RoomDeletedEvent(Long roomId) {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.f1.backend.domain.game.event;
2+
3+
import io.f1.backend.domain.game.model.Room;
4+
import io.f1.backend.domain.quiz.entity.Quiz;
5+
6+
public record RoomUpdatedEvent(Room room, Quiz quiz) {}

backend/src/main/java/io/f1/backend/domain/game/sse/app/SseService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.f1.backend.domain.game.sse.app;
22

3+
import io.f1.backend.domain.game.sse.dto.LobbySseEvent;
34
import io.f1.backend.domain.game.sse.store.SseEmitterRepository;
45

56
import lombok.RequiredArgsConstructor;
@@ -28,4 +29,15 @@ public SseEmitter subscribe() {
2829
}
2930
return emitter;
3031
}
32+
33+
// 로비로 SSE 메시지를 쏘기위한 메서드
34+
public <T> void notifyLobbyUpdate(LobbySseEvent<T> event) {
35+
for (SseEmitter emitter : emitterRepository.getAll()) {
36+
try {
37+
emitter.send(SseEmitter.event().name(event.type()).data(event));
38+
} catch (IOException e) {
39+
emitterRepository.remove(emitter);
40+
}
41+
}
42+
}
3143
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package io.f1.backend.domain.game.sse.dto;
2+
3+
public record LobbySseEvent<T>(String type, T payload) {}

0 commit comments

Comments
 (0)