728x90
조건
- 매칭은 Queue (First in First Out) 구조로 이루어 져야 한다.
- 유저가 접속하면 유저의 매칭취소 / 이탈을 감지 해야 한다.
- 매칭은 게임과 인원수를 알고 있어야 한다.
- 매칭이 완료되면 Discord url을 각 유저들 에게 뿌린다
Controller
- DeferredResult로 타임아웃 , 캔슬 , 에러 상황을 감지하고 매칭을 캔슬을 해준다
Service
- key = 게임이름+매칭인원 으로 해주었다. (키는 공유로 사용되어야 하고 벨류는 같은 키값을 바라보고있어야 했기 때문)
- Lock 걸어 매칭이 완료 되지 않는 유저를 대기 시킨다.
- DeferredResult 로 비동기 처리를 한 후 대기인원들을 웨이팅 큐에 넣는다.
- 채팅 요청 (Async : DeferredResult로 응답)
- 웨이팅 큐에 정원이 차지 않을경우 return 을 해준다. (비동기로 대기)
- 정원이 차면 웨이팅큐에 있는 유저를 뺀다
- JDA(Jave Discord Api)로 디스코드 채널을 생성하여 URL 을 만들고 response객체를 만들어주고.
- 대기하고 있는 유저들의 lock을 풀어준다.
@GetMapping("/join")//채팅방 요청.
@ResponseBody
public DeferredResult<MatchingResponse> joinRequest(@RequestParam String gameName,
@RequestParam String peopleLimit, @RequestParam String discordId, @RequestParam String uid) {
String sessionId = ServletUtil.getSession().getId();
logger.info(">> Join request. session id : {}", sessionId);
final MatchingRequest user = new MatchingRequest(sessionId,gameName,peopleLimit,discordId,uid);
final DeferredResult<MatchingResponse> deferredResult = new DeferredResult<>(null); //비동기 프로세스 생성.
matchingService.joinChatRoom(user, deferredResult);
deferredResult.onCompletion(() -> matchingService.cancelChatRoom(user));//에러 확인되면 채팅룸 닫기.
deferredResult.onError((throwable) -> matchingService.cancelChatRoom(user));
deferredResult.onTimeout(() -> matchingService.timeout(user));
return deferredResult;
}
@Async("asyncThreadPool")
public void cratedMatchingRoom(RequestMatching request) {
try {
logger.debug("현재 대기 유저 : " + waitingQueue.get(request.getKey()).size());
lock.readLock().lock();
if (waitingQueue.get(request.getKey()).size() < Integer.parseInt(request.getMemberNumbers())) {
return;
}
Iterator<RequestMatching> itr = waitingQueue.get(request.getKey()).keySet().iterator();
List<RequestMatching> roomUserKey = new ArrayList<>();
List<DeferredResult<ResponseMatching>> roomUserValue = new ArrayList<>();
for (int i = 0; i < Integer.parseInt(request.getMemberNumbers()); i++) {
roomUserKey.add(itr.next());
}
List<String> discordIdList = new ArrayList<>();
for (RequestMatching matchingRequest : roomUserKey) {
discordIdList.add(matchingRequest.getDiscordId());
}
// 방을 생성하고 초대코드를 가져온다
Optional<String> getUrl = discordService.createChannel(request.getGameMode(),discordIdList);
String url = "";
if (getUrl.isPresent()) {
System.out.println(url);
url = getUrl.get();
} else {
return;
}
for (int i = 0; i < Integer.parseInt(request.getMemberNumbers()); i++) {
roomUserValue.add(waitingQueue.get(request.getKey()).remove(roomUserKey.get(i)));
}
for (int i = 0; i < Integer.parseInt(request.getMemberNumbers()); i++) {
roomUserValue.get(i).setResult(
ResponseMatching.builder()
.metchingEunm(MatchingStatusEnum.SUCCESS)
.playMode(request.getGameMode())
.gameName(request.getGameMode())
.memberNumbers(request.getMemberNumbers())
.discordUrl(url)
.members(roomUserKey)
.build());}
} catch (Exception e) {
logger.warn("Exception occur while checking waiting users", e);
} finally {
lock.readLock().unlock();
}
}
728x90
'개-발 > Java + Spring + Kotlin' 카테고리의 다른 글
[Spring] JDA(Java Discord Api)를 이용한 자동 방 생성 (0) | 2023.03.09 |
---|---|
[Spring] Redis를 활용한 대기열 구현 (0) | 2023.03.09 |
[Spring] 트랜잭션 @transational 어노테이션 (0) | 2023.03.03 |
[Spring] Custom Query 사용 전 ! (0) | 2023.01.27 |
[Spring] jwt토큰을 더 안전하게 ! (RefreshToken , Cookie) (9) | 2023.01.10 |