Skip to content

Commit 9c54e85

Browse files
authored
Merge pull request #54 from Geumpumta/ip
feat: 최대 집중시간 제한(3시간) 설정 및 좀비 세션 스케줄러 삭제
2 parents 8b9f8e5 + a29fdb1 commit 9c54e85

File tree

5 files changed

+23
-50
lines changed

5 files changed

+23
-50
lines changed

src/main/java/com/gpt/geumpumtabackend/study/api/StudySessionApi.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.gpt.geumpumtabackend.study.dto.request.HeartBeatRequest;
1010
import com.gpt.geumpumtabackend.study.dto.request.StudyEndRequest;
1111
import com.gpt.geumpumtabackend.study.dto.request.StudyStartRequest;
12+
import com.gpt.geumpumtabackend.study.dto.response.HeartBeatResponse;
1213
import com.gpt.geumpumtabackend.study.dto.response.StudySessionResponse;
1314
import com.gpt.geumpumtabackend.study.dto.response.StudyStartResponse;
1415
import io.swagger.v3.oas.annotations.Operation;
@@ -147,8 +148,9 @@ ResponseEntity<ResponseBody<Void>> endStudySession(
147148
🔄 **동작 원리:**
148149
1. Wi-Fi 연결 상태 재검증 (Gateway IP + IP 대역 확인)
149150
2. 클라이언트 실제 IP 주소 재확인 (서버에서 추출)
150-
3. 세션의 lastHeartBeatAt 시간 업데이트
151-
4. 90초 이상 하트비트 없으면 좀비 세션으로 분류
151+
1. Wi-Fi 연결 상태 재검증 (Gateway IP + IP 대역 확인)
152+
2. 클라이언트 실제 IP 주소 재확인 (서버에서 추출)
153+
3. 최대 집중 시간(3시간) 초과 여부 확인 및 자동 세션 종료
152154
153155
🚨 **실패 시 대응:**
154156
- Wi-Fi 연결 끊김: 재연결 후 다시 `/start` 호출
@@ -170,7 +172,7 @@ ResponseEntity<ResponseBody<Void>> endStudySession(
170172
@PostMapping("/heart-beat")
171173
@AssignUserId
172174
@PreAuthorize("isAuthenticated() and hasRole('USER')")
173-
ResponseEntity<ResponseBody<Void>> processHeartBeat(
175+
ResponseEntity<ResponseBody<HeartBeatResponse>> processHeartBeat(
174176
@Valid @RequestBody HeartBeatRequest heartBeatRequest,
175177
@Parameter(hidden = true) Long userId);
176178
}

src/main/java/com/gpt/geumpumtabackend/study/controller/StudySessionController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.gpt.geumpumtabackend.study.dto.request.HeartBeatRequest;
88
import com.gpt.geumpumtabackend.study.dto.request.StudyEndRequest;
99
import com.gpt.geumpumtabackend.study.dto.request.StudyStartRequest;
10+
import com.gpt.geumpumtabackend.study.dto.response.HeartBeatResponse;
1011
import com.gpt.geumpumtabackend.study.dto.response.StudySessionResponse;
1112
import com.gpt.geumpumtabackend.study.dto.response.StudyStartResponse;
1213
import com.gpt.geumpumtabackend.study.service.StudySessionService;
@@ -64,8 +65,7 @@ public ResponseEntity<ResponseBody<Void>> endStudySession(@Valid @RequestBody St
6465
@PostMapping("/heart-beat")
6566
@PreAuthorize("isAuthenticated() and hasRole('USER')")
6667
@AssignUserId
67-
public ResponseEntity<ResponseBody<Void>> processHeartBeat(@Valid @RequestBody HeartBeatRequest heartBeatRequest, Long userId){
68-
studySessionService.updateHeartBeat(heartBeatRequest, userId);
69-
return ResponseEntity.ok(ResponseUtil.createSuccessResponse());
68+
public ResponseEntity<ResponseBody<HeartBeatResponse>> processHeartBeat(@Valid @RequestBody HeartBeatRequest heartBeatRequest, Long userId){
69+
return ResponseEntity.ok(ResponseUtil.createSuccessResponse(studySessionService.updateHeartBeat(heartBeatRequest, userId)));
7070
}
7171
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.gpt.geumpumtabackend.study.dto.response;
2+
3+
public record HeartBeatResponse(boolean sessionActive, String message) {
4+
}

src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionSchedulerService.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/main/java/com/gpt/geumpumtabackend/study/service/StudySessionService.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.gpt.geumpumtabackend.study.dto.request.HeartBeatRequest;
77
import com.gpt.geumpumtabackend.study.dto.request.StudyEndRequest;
88
import com.gpt.geumpumtabackend.study.dto.request.StudyStartRequest;
9+
import com.gpt.geumpumtabackend.study.dto.response.HeartBeatResponse;
910
import com.gpt.geumpumtabackend.study.dto.response.StudySessionResponse;
1011
import com.gpt.geumpumtabackend.study.dto.response.StudyStartResponse;
1112
import com.gpt.geumpumtabackend.study.repository.StudySessionRepository;
@@ -19,6 +20,7 @@
1920
import org.springframework.stereotype.Service;
2021
import org.springframework.transaction.annotation.Transactional;
2122

23+
import java.time.Duration;
2224
import java.time.LocalDate;
2325
import java.time.LocalDateTime;
2426

@@ -30,7 +32,7 @@ public class StudySessionService {
3032
private final StudySessionRepository studySessionRepository;
3133
private final UserRepository userRepository;
3234
private final CampusWiFiValidationService wifiValidationService;
33-
35+
private static final Integer MAX_FOCUS_TIME = 3;
3436
/*
3537
메인 홈
3638
*/
@@ -81,7 +83,7 @@ public void endStudySession(StudyEndRequest request, Long userId) {
8183
하트비트 처리
8284
*/
8385
@Transactional
84-
public void updateHeartBeat(HeartBeatRequest heartBeatRequest, Long userId) {
86+
public HeartBeatResponse updateHeartBeat(HeartBeatRequest heartBeatRequest, Long userId) {
8587
Long sessionId = heartBeatRequest.sessionId();
8688

8789
// Wi-Fi 검증 (캐시 우선 사용)
@@ -98,7 +100,14 @@ public void updateHeartBeat(HeartBeatRequest heartBeatRequest, Long userId) {
98100
// 유효하면 해당 세션의 lastHeartBeatAt 시간을 now()로 갱신한다.
99101
StudySession studySession = studySessionRepository.findByIdAndUser_Id(sessionId, userId)
100102
.orElseThrow(()->new BusinessException(ExceptionType.STUDY_SESSION_NOT_FOUND));
103+
104+
Duration elapsed = Duration.between(studySession.getStartTime(), LocalDateTime.now());
105+
if(elapsed.compareTo(Duration.ofHours(MAX_FOCUS_TIME)) >= 0) {
106+
studySession.endStudySession(studySession.getStartTime().plusHours(MAX_FOCUS_TIME));
107+
return new HeartBeatResponse(false, "최대 집중시간은 3시간입니다.");
108+
}
101109
studySession.updateHeartBeatAt(LocalDateTime.now());
110+
return new HeartBeatResponse(true,"정상 세션");
102111
}
103112

104113
private BusinessException mapWiFiValidationException(WiFiValidationResult result) {

0 commit comments

Comments
 (0)