Compare commits

..

No commits in common. "5a56990d0b1ef58a1f0206a0bac748498f84404c" and "3cac42b5b999e0496cdb5f870c4d446be789b798" have entirely different histories.

5 changed files with 121 additions and 168 deletions

View File

@ -223,9 +223,10 @@ class LiveRoomController(private val service: LiveRoomService) {
@PostMapping("/quit") @PostMapping("/quit")
fun quitRoom( fun quitRoom(
@RequestParam("id") roomId: Long,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run { ) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.") if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.quitRoom(member)) ApiResponse.ok(service.quitRoom(roomId, member))
} }
} }

View File

@ -53,8 +53,6 @@ import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.Date import java.util.Date
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.write
@Service @Service
@Transactional(readOnly = true) @Transactional(readOnly = true)
@ -90,8 +88,6 @@ class LiveRoomService(
@Value("\${cloud.aws.cloud-front.host}") @Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String private val cloudFrontHost: String
) { ) {
private val tokenLocks: MutableMap<Long, ReentrantReadWriteLock> = mutableMapOf()
fun getRoomList( fun getRoomList(
dateString: String?, dateString: String?,
status: LiveRoomStatus, status: LiveRoomStatus,
@ -419,52 +415,49 @@ class LiveRoomService(
throw SodaException("비밀번호가 일치하지 않습니다.\n다시 확인 후 입력해주세요.") throw SodaException("비밀번호가 일치하지 않습니다.\n다시 확인 후 입력해주세요.")
} }
val lock = getOrCreateLock(memberId = member.id!!) var roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
lock.write { if (roomInfo == null) {
var roomInfo = roomInfoRepository.findByIdOrNull(request.roomId) roomInfo = roomInfoRepository.save(LiveRoomInfo(roomId = request.roomId))
if (roomInfo == null) {
roomInfo = roomInfoRepository.save(LiveRoomInfo(roomId = request.roomId))
}
if (roomInfo.speakerCount + roomInfo.listenerCount + roomInfo.managerCount >= room.numberOfPeople) {
throw SodaException("방이 가득찼습니다.")
}
if (
room.price > 0 &&
room.member!!.id!! != member.id!! &&
canRepository.isExistPaidLiveRoom(memberId = member.id!!, roomId = request.roomId) == null
) {
val findMember = memberRepository.findByIdOrNull(id = member.id!!)
?: throw SodaException("로그인 정보를 확인해 주세요.")
val totalCan = findMember.getChargeCan(request.container) + findMember.getRewardCan(request.container)
if (totalCan < room.price) {
throw SodaException("${room.price - totalCan}캔이 부족합니다. 충전 후 이용해 주세요.")
}
canPaymentService.spendCan(
memberId = member.id!!,
needCan = room.price,
canUsage = CanUsage.LIVE,
liveRoom = room,
container = request.container
)
}
roomInfo.removeListener(member)
roomInfo.removeSpeaker(member)
roomInfo.removeManager(member)
if (room.member!!.id == member.id) {
roomInfo.addSpeaker(member, cloudFrontHost)
} else {
roomInfo.addListener(member, cloudFrontHost)
}
roomInfoRepository.save(roomInfo)
roomVisitService.roomVisit(room, member)
} }
if (roomInfo.speakerCount + roomInfo.listenerCount + roomInfo.managerCount >= room.numberOfPeople) {
throw SodaException("방이 가득찼습니다.")
}
if (
room.price > 0 &&
room.member!!.id!! != member.id!! &&
canRepository.isExistPaidLiveRoom(memberId = member.id!!, roomId = request.roomId) == null
) {
val findMember = memberRepository.findByIdOrNull(id = member.id!!)
?: throw SodaException("로그인 정보를 확인해 주세요.")
val totalCan = findMember.getChargeCan(request.container) + findMember.getRewardCan(request.container)
if (totalCan < room.price) {
throw SodaException("${room.price - totalCan}캔이 부족합니다. 충전 후 이용해 주세요.")
}
canPaymentService.spendCan(
memberId = member.id!!,
needCan = room.price,
canUsage = CanUsage.LIVE,
liveRoom = room,
container = request.container
)
}
roomInfo.removeListener(member)
roomInfo.removeSpeaker(member)
roomInfo.removeManager(member)
if (room.member!!.id == member.id) {
roomInfo.addSpeaker(member, cloudFrontHost)
} else {
roomInfo.addListener(member, cloudFrontHost)
}
roomInfoRepository.save(roomInfo)
roomVisitService.roomVisit(room, member)
} }
fun getRecentRoomInfo(member: Member): GetRecentRoomInfoResponse { fun getRecentRoomInfo(member: Member): GetRecentRoomInfoResponse {
@ -628,21 +621,18 @@ class LiveRoomService(
} }
fun deleteDonationMessage(request: DeleteLiveRoomDonationMessage, member: Member) { fun deleteDonationMessage(request: DeleteLiveRoomDonationMessage, member: Member) {
val lock = getOrCreateLock(memberId = member.id!!) val room = repository.findByIdOrNull(request.roomId)
lock.write { ?: throw SodaException("해당하는 라이브가 없습니다.")
val room = repository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브가 없습니다.")
if (member.id!! != room.member!!.id!!) { if (member.id!! != room.member!!.id!!) {
throw SodaException("잘못된 요청입니다.") throw SodaException("잘못된 요청입니다.")
}
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
roomInfo.removeDonationMessage(request.messageUUID)
roomInfoRepository.save(roomInfo)
} }
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
roomInfo.removeDonationMessage(request.messageUUID)
roomInfoRepository.save(roomInfo)
} }
fun getUserProfile(roomId: Long, userId: Long, member: Member): GetLiveRoomUserProfileResponse { fun getUserProfile(roomId: Long, userId: Long, member: Member): GetLiveRoomUserProfileResponse {
@ -711,73 +701,64 @@ class LiveRoomService(
} }
fun setSpeaker(request: SetManagerOrSpeakerOrAudienceRequest) { fun setSpeaker(request: SetManagerOrSpeakerOrAudienceRequest) {
val lock = getOrCreateLock(memberId = request.memberId) val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
lock.write { ?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val member = memberRepository.findByIdOrNull(request.memberId) val account = memberRepository.findByIdOrNull(request.accountId)
?: throw SodaException("로그인 정보를 확인해 주세요.") ?: throw SodaException("로그인 정보를 확인해 주세요.")
if (roomInfo.speakerCount > 9) { if (roomInfo.speakerCount > 9) {
throw SodaException("스피커 정원이 초과하였습니다.") throw SodaException("스피커 정원이 초과하였습니다.")
}
roomInfo.removeListener(member)
roomInfo.removeManager(member)
roomInfo.addSpeaker(member, cloudFrontHost)
roomInfoRepository.save(roomInfo)
} }
roomInfo.removeListener(account)
roomInfo.removeManager(account)
roomInfo.addSpeaker(account, cloudFrontHost)
roomInfoRepository.save(roomInfo)
} }
fun setListener(request: SetManagerOrSpeakerOrAudienceRequest) { fun setListener(request: SetManagerOrSpeakerOrAudienceRequest) {
val lock = getOrCreateLock(memberId = request.memberId) val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
lock.write { ?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val member = memberRepository.findByIdOrNull(request.memberId) val member = memberRepository.findByIdOrNull(request.accountId)
?: throw SodaException("로그인 정보를 확인해 주세요.") ?: throw SodaException("로그인 정보를 확인해 주세요.")
roomInfo.removeSpeaker(member) roomInfo.removeSpeaker(member)
roomInfo.removeManager(member) roomInfo.removeManager(member)
roomInfo.addListener(member, cloudFrontHost) roomInfo.addListener(member, cloudFrontHost)
roomInfoRepository.save(roomInfo) roomInfoRepository.save(roomInfo)
}
} }
fun setManager(request: SetManagerOrSpeakerOrAudienceRequest, member: Member) { fun setManager(request: SetManagerOrSpeakerOrAudienceRequest, member: Member) {
val lock = getOrCreateLock(memberId = member.id!!) val room = repository.getLiveRoom(request.roomId) ?: throw SodaException("잘못된 요청입니다.")
lock.write { if (room.member!!.id!! != member.id!!) {
val room = repository.getLiveRoom(request.roomId) ?: throw SodaException("잘못된 요청입니다.") throw SodaException("권한이 없습니다.")
if (room.member!!.id!! != member.id!!) {
throw SodaException("권한이 없습니다.")
}
val user = memberRepository.findByIdOrNull(request.memberId) ?: throw SodaException("해당하는 유저가 없습니다.")
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val roomAccountResponse = LiveRoomMember(member = user, cloudFrontHost)
if (roomInfo.managerList.contains(roomAccountResponse)) {
throw SodaException("이미 매니저 입니다.")
}
if (
!roomInfo.speakerList.contains(roomAccountResponse) &&
!roomInfo.listenerList.contains(roomAccountResponse)
) {
throw SodaException("해당하는 유저가 없습니다.")
}
roomInfo.removeListener(user)
roomInfo.removeSpeaker(user)
roomInfo.addManager(user, cloudFrontHost)
roomInfoRepository.save(roomInfo)
} }
val user = memberRepository.findByIdOrNull(request.accountId) ?: throw SodaException("해당하는 유저가 없습니다.")
val roomInfo = roomInfoRepository.findByIdOrNull(request.roomId)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val roomAccountResponse = LiveRoomMember(member = user, cloudFrontHost)
if (roomInfo.managerList.contains(roomAccountResponse)) {
throw SodaException("이미 매니저 입니다.")
}
if (
!roomInfo.speakerList.contains(roomAccountResponse) &&
!roomInfo.listenerList.contains(roomAccountResponse)
) {
throw SodaException("해당하는 유저가 없습니다.")
}
roomInfo.removeListener(user)
roomInfo.removeSpeaker(user)
roomInfo.addManager(user, cloudFrontHost)
roomInfoRepository.save(roomInfo)
} }
@Transactional @Transactional
@ -800,19 +781,16 @@ class LiveRoomService(
) )
if (request.message.isNotBlank()) { if (request.message.isNotBlank()) {
val lock = getOrCreateLock(memberId = member.id!!) val roomInfo = roomInfoRepository.findByIdOrNull(room.id!!)
lock.write { ?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
val roomInfo = roomInfoRepository.findByIdOrNull(room.id!!)
?: throw SodaException("해당하는 라이브의 정보가 없습니다.")
roomInfo.addDonationMessage( roomInfo.addDonationMessage(
nickname = member.nickname, nickname = member.nickname,
can = request.can, can = request.can,
donationMessage = request.message donationMessage = request.message
) )
roomInfoRepository.save(roomInfo) roomInfoRepository.save(roomInfo)
}
} }
} }
@ -865,32 +843,20 @@ class LiveRoomService(
) )
} }
fun quitRoom(member: Member) { fun quitRoom(roomId: Long, member: Member) {
val roomVisit = roomVisitService.getLatestRoomVisit(member.id!!) val room = repository.getLiveRoom(roomId)
val roomInfo = roomInfoRepository.findByIdOrNull(roomId)
val roomId = roomVisit?.room?.id if (roomInfo != null) {
if (roomId != null) { if (room?.member != null && room.member!! == member) {
val lock = getOrCreateLock(memberId = member.id!!) room.isActive = false
lock.write { kickOutService.deleteKickOutData(roomId = room.id!!)
val roomInfo = roomInfoRepository.findByIdOrNull(roomId) roomInfoRepository.deleteById(roomInfo.roomId)
if (roomInfo != null) { } else {
val room = repository.getLiveRoom(roomId) ?: return roomInfo.removeSpeaker(member)
if (room.member != null && room.member!! == member) { roomInfo.removeListener(member)
room.isActive = false roomInfo.removeManager(member)
kickOutService.deleteKickOutData(roomId = room.id!!) roomInfoRepository.save(roomInfo)
roomInfoRepository.deleteById(roomInfo.roomId)
} else {
roomInfo.removeSpeaker(member)
roomInfo.removeListener(member)
roomInfo.removeManager(member)
roomInfoRepository.save(roomInfo)
}
}
} }
} }
} }
private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock {
return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() }
}
} }

View File

@ -2,5 +2,5 @@ package kr.co.vividnext.sodalive.live.room
data class SetManagerOrSpeakerOrAudienceRequest( data class SetManagerOrSpeakerOrAudienceRequest(
val roomId: Long, val roomId: Long,
val memberId: Long val accountId: Long
) )

View File

@ -13,7 +13,6 @@ interface LiveRoomVisitRepository : JpaRepository<LiveRoomVisit, Long>, LiveRoom
interface LiveRoomVisitQueryRepository { interface LiveRoomVisitQueryRepository {
fun findByRoomIdAndMemberId(roomId: Long, memberId: Long): LiveRoomVisit? fun findByRoomIdAndMemberId(roomId: Long, memberId: Long): LiveRoomVisit?
fun findFirstByMemberIdOrderByUpdatedAtDesc(memberId: Long): LiveRoomVisit? fun findFirstByMemberIdOrderByUpdatedAtDesc(memberId: Long): LiveRoomVisit?
fun getLatestRoomVisit(memberId: Long): LiveRoomVisit?
} }
@Repository @Repository
@ -39,13 +38,4 @@ class LiveRoomVisitQueryRepositoryImpl(private val queryFactory: JPAQueryFactory
.orderBy(liveRoomVisit.updatedAt.desc()) .orderBy(liveRoomVisit.updatedAt.desc())
.fetchFirst() .fetchFirst()
} }
override fun getLatestRoomVisit(memberId: Long): LiveRoomVisit? {
return queryFactory
.selectFrom(liveRoomVisit)
.innerJoin(liveRoomVisit.member, member)
.where(member.id.eq(memberId))
.orderBy(liveRoomVisit.updatedAt.desc())
.fetchFirst()
}
} }

View File

@ -22,8 +22,4 @@ class LiveRoomVisitService(private val repository: LiveRoomVisitRepository) {
repository.save(roomVisit) repository.save(roomVisit)
} }
fun getLatestRoomVisit(memberId: Long): LiveRoomVisit? {
return repository.getLatestRoomVisit(memberId)
}
} }