-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DRAW-287 MafiaGameInfo 메모리 -> Redis 저장소 이관 #101
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
939c650
DRAW-287 chore: redis 세팅
SunwoongH ce15502
DRAW-287 feat: job 저장소 구현
SunwoongH d27d6a6
DRAW-287 refactor: timer repository 의존하도록 리팩터링
SunwoongH 3abeb8f
DRAW-287 refactor: job key 의존하도록 리팩터링
SunwoongH c46fdf5
DRAW-287 chore: redis 의존성 추가
SunwoongH b1ff41e
DRAW-287 chore: core 모듈 redis 의존성 추가
SunwoongH 9150e09
DRAW-287 feat: 마피아 게임 레디스 adapter 구현
SunwoongH f779021
DRAW-287 feat: 레디스 마피아 게임 정보 저장 클래스 구현
SunwoongH 6d317d9
DRAW-287 refactor: 레디스 마피아 게임 정보 저장 클래스 분리
SunwoongH 1d67ea0
DRAW-287 refactor: 코드 정리
SunwoongH 3f68b3b
Merge branch 'refs/heads/develop' into feature/DRAW-287
SunwoongH 3d3c061
DRAW-287 chore: redis 설정 추가
SunwoongH 3b5f7fa
DRAW-287 fix: ktlint 오류 수정
SunwoongH 5f4ddfb
DRAW-287 refactor: 코드 리뷰 반영
SunwoongH 433fcaf
Merge branch 'refs/heads/feature/DRAW-347' into feature/DRAW-287
SunwoongH c83bcc8
DRAW-287 fix: merge conflict
SunwoongH File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +0,0 @@ | ||
package com.xorker.draw.mafia | ||
|
||
import com.xorker.draw.room.Room | ||
import com.xorker.draw.room.RoomId | ||
import com.xorker.draw.room.RoomRepository | ||
import com.xorker.draw.support.metric.MetricManager | ||
import com.xorker.draw.user.UserId | ||
import java.util.concurrent.ConcurrentHashMap | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
internal class MafiaGameAdapter( | ||
private val metricManager: MetricManager, | ||
) : MafiaGameRepository, RoomRepository { | ||
private val data = ConcurrentHashMap<RoomId, MafiaGameInfo>() | ||
private val userData = ConcurrentHashMap<UserId, RoomId>() | ||
|
||
override fun saveGameInfo(gameInfo: MafiaGameInfo) { | ||
val room = gameInfo.room | ||
if (room.isEmpty()) { | ||
removeGameInfo(gameInfo) | ||
} else { | ||
if (data.containsKey(room.id).not()) { | ||
metricManager.increaseGameCount() | ||
} | ||
data[room.id] = gameInfo | ||
room.players.forEach { | ||
userData[it.userId] = room.id | ||
} | ||
} | ||
} | ||
|
||
override fun removeGameInfo(gameInfo: MafiaGameInfo) { | ||
metricManager.decreaseGameCount() | ||
gameInfo.room.players | ||
.map { it.userId } | ||
.forEach { removePlayer(it) } | ||
|
||
val phase = gameInfo.phase | ||
if (phase is MafiaPhaseWithTimer) { | ||
phase.job.cancel() | ||
} | ||
|
||
data.remove(gameInfo.room.id) | ||
} | ||
|
||
override fun getGameInfo(roomId: RoomId?): MafiaGameInfo? { | ||
return data[roomId] | ||
} | ||
|
||
override fun getRoom(roomId: RoomId): Room<MafiaPlayer>? { | ||
return data[roomId]?.room | ||
} | ||
|
||
override fun getGameInfo(userId: UserId): MafiaGameInfo? { | ||
val roomId = userData[userId] ?: return null | ||
return data[roomId] | ||
} | ||
|
||
override fun removePlayer(userId: UserId) { | ||
userData.remove(userId) | ||
} | ||
} | ||
37 changes: 24 additions & 13 deletions
37
adapter/memory/src/main/kotlin/com/xorker/draw/timer/TimerAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,45 @@ | ||
package com.xorker.draw.timer | ||
|
||
import com.xorker.draw.exception.UnSupportedException | ||
import com.xorker.draw.mafia.event.JobWithStartTime | ||
import com.xorker.draw.room.RoomId | ||
import java.time.Duration | ||
import java.time.LocalDateTime | ||
import java.util.concurrent.ConcurrentHashMap | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.delay | ||
import kotlinx.coroutines.launch | ||
import org.springframework.context.ApplicationEventPublisher | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
internal class TimerAdapter( | ||
private val eventPublisher: ApplicationEventPublisher, | ||
) : TimerRepository { | ||
internal class TimerAdapter : TimerRepository { | ||
private val jobs = ConcurrentHashMap<RoomId, JobWithStartTime>() | ||
|
||
override fun <T : Any> startTimer(interval: Duration, event: T): JobWithStartTime { | ||
override fun startTimer(roomId: RoomId, interval: Duration, callback: () -> Unit): JobWithStartTime { | ||
val job = JobWithStartTime() | ||
CoroutineScope(Dispatchers.IO + job).launch { | ||
delay(interval.toMillis()) | ||
eventPublisher.publishEvent(event) | ||
} | ||
return job | ||
} | ||
|
||
override fun startTimer(interval: Duration, callback: () -> Unit): JobWithStartTime { | ||
val job = JobWithStartTime() | ||
saveJob(roomId, job) | ||
|
||
CoroutineScope(Dispatchers.IO + job).launch { | ||
delay(interval.toMillis()) | ||
callback.invoke() | ||
} | ||
return job | ||
} | ||
|
||
override fun cancelTimer(roomId: RoomId) { | ||
jobs[roomId]?.cancel() | ||
jobs.remove(roomId) | ||
} | ||
|
||
override fun getTimerStartTime(roomId: RoomId): LocalDateTime { | ||
val job = jobs[roomId] ?: throw UnSupportedException | ||
|
||
return job.startTime | ||
} | ||
|
||
private fun saveJob(roomId: RoomId, job: JobWithStartTime) { | ||
jobs[roomId] = job | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import org.springframework.boot.gradle.tasks.bundling.BootJar | ||
|
||
plugins { | ||
kotlin("plugin.spring") | ||
} | ||
|
||
dependencies { | ||
implementation(project(":domain")) | ||
implementation(project(":support:metric")) | ||
|
||
implementation("org.springframework.boot:spring-boot-starter-data-redis:${Versions.SPRING_BOOT}") | ||
} | ||
|
||
tasks { | ||
withType<Jar> { enabled = true } | ||
withType<BootJar> { enabled = false } | ||
} |
57 changes: 57 additions & 0 deletions
57
adapter/redis/src/main/kotlin/com/xorker/draw/config/RedisConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.xorker.draw.config | ||
|
||
import com.xorker.draw.mafia.dto.RedisMafiaGameInfo | ||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.data.redis.connection.RedisConnectionFactory | ||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration | ||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory | ||
import org.springframework.data.redis.core.RedisTemplate | ||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer | ||
import org.springframework.data.redis.serializer.StringRedisSerializer | ||
|
||
@Configuration | ||
internal class RedisConfig { | ||
|
||
@Value("\${spring.data.redis.host}") | ||
lateinit var host: String | ||
|
||
@Value("\${spring.data.redis.password}") | ||
lateinit var password: String | ||
|
||
@Value("\${spring.data.redis.port}") | ||
lateinit var port: String | ||
|
||
@Bean | ||
fun redisConnectionFactory(): RedisConnectionFactory { | ||
val config = RedisStandaloneConfiguration(host, port.toInt()) | ||
config.setPassword(password) | ||
|
||
return LettuceConnectionFactory(config) | ||
} | ||
|
||
@Bean | ||
fun redisTemplateWithObject(connectionFactory: RedisConnectionFactory): RedisTemplate<String, RedisMafiaGameInfo> { | ||
val template = RedisTemplate<String, RedisMafiaGameInfo>() | ||
|
||
template.connectionFactory = connectionFactory | ||
|
||
template.keySerializer = StringRedisSerializer() | ||
template.valueSerializer = Jackson2JsonRedisSerializer(RedisMafiaGameInfo::class.java) | ||
|
||
return template | ||
} | ||
|
||
@Bean | ||
fun redisTemplate(connectionFactory: RedisConnectionFactory): RedisTemplate<String, String> { | ||
val template = RedisTemplate<String, String>() | ||
|
||
template.connectionFactory = connectionFactory | ||
|
||
template.keySerializer = StringRedisSerializer() | ||
template.valueSerializer = StringRedisSerializer() | ||
|
||
return template | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
adapter/redis/src/main/kotlin/com/xorker/draw/mafia/MafiaGameAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package com.xorker.draw.mafia | ||
|
||
import com.xorker.draw.mafia.dto.RedisMafiaGameInfo | ||
import com.xorker.draw.mafia.dto.toRedisMafiaGameInfo | ||
import com.xorker.draw.room.Room | ||
import com.xorker.draw.room.RoomId | ||
import com.xorker.draw.room.RoomRepository | ||
import com.xorker.draw.support.metric.MetricManager | ||
import com.xorker.draw.timer.TimerRepository | ||
import com.xorker.draw.user.UserId | ||
import org.springframework.data.redis.core.RedisTemplate | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
internal class MafiaGameAdapter( | ||
private val metricManager: MetricManager, | ||
private val redisTemplateWithObject: RedisTemplate<String, RedisMafiaGameInfo>, | ||
private val redisTemplate: RedisTemplate<String, String>, | ||
private val timerRepository: TimerRepository, | ||
) : MafiaGameRepository, RoomRepository { | ||
|
||
override fun saveGameInfo(gameInfo: MafiaGameInfo) { | ||
val room = gameInfo.room | ||
if (room.isEmpty()) { | ||
removeGameInfo(gameInfo) | ||
} else { | ||
val findGameInfo = redisTemplateWithObject | ||
.opsForValue() | ||
.get(room.id.value) | ||
|
||
if (findGameInfo == null) { | ||
metricManager.increaseGameCount() | ||
} | ||
|
||
redisTemplateWithObject | ||
.opsForValue() | ||
.set(room.id.value, gameInfo.toRedisMafiaGameInfo()) | ||
|
||
room.players.forEach { | ||
redisTemplate | ||
.opsForValue() | ||
.set(it.userId.value.toString(), room.id.value) | ||
} | ||
} | ||
} | ||
|
||
override fun removeGameInfo(gameInfo: MafiaGameInfo) { | ||
metricManager.decreaseGameCount() | ||
|
||
val room = gameInfo.room | ||
|
||
room.players | ||
.map { it.userId } | ||
.forEach { removePlayer(it) } | ||
|
||
val phase = gameInfo.phase | ||
|
||
if (phase is MafiaPhaseWithTimer) { | ||
timerRepository.cancelTimer(room.id) | ||
} | ||
|
||
redisTemplateWithObject.delete(room.id.value) | ||
} | ||
|
||
override fun getGameInfo(roomId: RoomId): MafiaGameInfo? { | ||
return redisTemplateWithObject | ||
.opsForValue() | ||
.get(roomId.value) | ||
?.toMafiaGameInfo() | ||
} | ||
|
||
override fun getGameInfo(userId: UserId): MafiaGameInfo? { | ||
val roomId = redisTemplate | ||
.opsForValue() | ||
.get(userId.value.toString()) ?: return null | ||
|
||
return redisTemplateWithObject | ||
.opsForValue() | ||
.get(roomId) | ||
?.toMafiaGameInfo() | ||
} | ||
|
||
override fun removePlayer(userId: UserId) { | ||
redisTemplate.delete(userId.value.toString()) | ||
} | ||
|
||
override fun getRoom(roomId: RoomId): Room<MafiaPlayer>? { | ||
return redisTemplateWithObject | ||
.opsForValue() | ||
.get(roomId.value) | ||
?.toMafiaGameInfo() | ||
?.room | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
adapter/redis/src/main/kotlin/com/xorker/draw/mafia/dto/RedisMafiaGameInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.xorker.draw.mafia.dto | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator | ||
import com.fasterxml.jackson.annotation.JsonProperty | ||
import com.xorker.draw.mafia.MafiaGameInfo | ||
|
||
data class RedisMafiaGameInfo @JsonCreator constructor( | ||
@JsonProperty("room") val room: RedisMafiaRoom, | ||
@JsonProperty("phase") val phase: RedisMafiaPhase, | ||
@JsonProperty("gameOption") val gameOption: RedisMafiaGameOption, | ||
) { | ||
fun toMafiaGameInfo(): MafiaGameInfo = MafiaGameInfo( | ||
room = room.toRoom(), | ||
phase = phase.toMafiaPhase(), | ||
gameOption = gameOption.toGameOption(), | ||
) | ||
} | ||
|
||
fun MafiaGameInfo.toRedisMafiaGameInfo(): RedisMafiaGameInfo = RedisMafiaGameInfo( | ||
room = RedisMafiaRoom( | ||
id = room.id.value, | ||
locale = room.locale, | ||
owner = RedisMafiaPlayer( | ||
id = room.owner.userId.value, | ||
nickname = room.owner.nickname, | ||
color = room.owner.color, | ||
isConnect = room.owner.isConnect(), | ||
), | ||
maxMemberNum = room.maxMemberNum, | ||
players = room.players.map { player -> | ||
RedisMafiaPlayer( | ||
id = player.userId.value, | ||
nickname = player.nickname, | ||
color = player.color, | ||
isConnect = player.isConnect(), | ||
) | ||
}, | ||
isRandomMatching = room.isRandomMatching, | ||
), | ||
phase = phase.toRedisMafiaPhase(), | ||
gameOption = RedisMafiaGameOption( | ||
minimum = gameOption.minimum, | ||
maximum = gameOption.maximum, | ||
readyTime = gameOption.readyTime.toMillis(), | ||
introAnimationTime = gameOption.introAnimationTime.toMillis(), | ||
roundAnimationTime = gameOption.roundAnimationTime.toMillis(), | ||
round = gameOption.round, | ||
turnTime = gameOption.turnTime.toMillis(), | ||
turnCount = gameOption.turnCount, | ||
voteTime = gameOption.voteTime.toMillis(), | ||
answerTime = gameOption.answerTime.toMillis(), | ||
endTime = gameOption.endTime.toMillis(), | ||
), | ||
) |
34 changes: 34 additions & 0 deletions
34
adapter/redis/src/main/kotlin/com/xorker/draw/mafia/dto/RedisMafiaGameOption.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.xorker.draw.mafia.dto | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator | ||
import com.fasterxml.jackson.annotation.JsonProperty | ||
import com.xorker.draw.mafia.MafiaGameOption | ||
import java.time.Duration | ||
|
||
data class RedisMafiaGameOption @JsonCreator constructor( | ||
@JsonProperty("minimum") val minimum: Int, | ||
@JsonProperty("maximum") val maximum: Int, | ||
@JsonProperty("readyTime") val readyTime: Long, | ||
@JsonProperty("introAnimationTime") val introAnimationTime: Long, | ||
@JsonProperty("roundAnimationTime") val roundAnimationTime: Long, | ||
@JsonProperty("round") val round: Int, | ||
@JsonProperty("turnTime") val turnTime: Long, | ||
@JsonProperty("turnCount") val turnCount: Int, | ||
@JsonProperty("voteTime") val voteTime: Long, | ||
@JsonProperty("answerTime") val answerTime: Long, | ||
@JsonProperty("endTime") val endTime: Long, | ||
) | ||
|
||
fun RedisMafiaGameOption.toGameOption(): MafiaGameOption = MafiaGameOption( | ||
minimum = this.minimum, | ||
maximum = this.maximum, | ||
readyTime = Duration.ofMillis(this.readyTime), | ||
introAnimationTime = Duration.ofMillis(this.introAnimationTime), | ||
roundAnimationTime = Duration.ofMillis(this.roundAnimationTime), | ||
round = this.round, | ||
turnTime = Duration.ofMillis(this.turnTime), | ||
turnCount = this.turnCount, | ||
voteTime = Duration.ofMillis(this.voteTime), | ||
answerTime = Duration.ofMillis(this.answerTime), | ||
endTime = Duration.ofMillis(this.endTime), | ||
) |
15 changes: 15 additions & 0 deletions
15
adapter/redis/src/main/kotlin/com/xorker/draw/mafia/dto/RedisMafiaKeyword.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.xorker.draw.mafia.dto | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator | ||
import com.fasterxml.jackson.annotation.JsonProperty | ||
import com.xorker.draw.mafia.MafiaKeyword | ||
|
||
data class RedisMafiaKeyword @JsonCreator constructor( | ||
@JsonProperty("category") val category: String, | ||
@JsonProperty("answer") val answer: String, | ||
) | ||
|
||
fun RedisMafiaKeyword.toMafiaKeyword(): MafiaKeyword = MafiaKeyword( | ||
answer = this.answer, | ||
category = this.category, | ||
) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p4. NotFound Exception 을 만들면 좋을 것 같아요.