From 8dde66c06926102e8c43fe8378cedaf06334248d Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:53:37 +0900 Subject: [PATCH 1/3] add Session flows - songlist page to changed. --- .../chzzk_bot/chatbot/chzzk/MessageHandler.kt | 4 +- .../mori/chzzk_bot/common/models/User.kt | 2 + .../common/services/SongConfigService.kt | 25 ---------- .../chzzk_bot/common/services/UserService.kt | 8 ++++ .../chzzk_bot/webserver/routes/ApiRoutes.kt | 48 ++++++++----------- .../webserver/routes/WSSongListRoutes.kt | 39 ++++++++------- 6 files changed, 51 insertions(+), 75 deletions(-) diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt index c29a92b..d96943e 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt @@ -285,12 +285,10 @@ class MessageHandler( val session = "${UUID.randomUUID()}${UUID.randomUUID()}".replace("-", "") - SongConfigService.updateSession(user, session) - bot.retrieveUserById(user.discord).queue { discordUser -> discordUser?.openPrivateChannel()?.queue { channel -> - channel.sendMessage("여기로 접속해주세요! ||https://nabot.mori.space/songlist/${session}||.\n주소가 노출될 경우 방송을 다시 켜셔야 합니다!") + channel.sendMessage("여기로 접속해주세요! ||https://nabot.mori.space/songlist||.") .queue() } } diff --git a/common/src/main/kotlin/space/mori/chzzk_bot/common/models/User.kt b/common/src/main/kotlin/space/mori/chzzk_bot/common/models/User.kt index cee84c3..334a10f 100644 --- a/common/src/main/kotlin/space/mori/chzzk_bot/common/models/User.kt +++ b/common/src/main/kotlin/space/mori/chzzk_bot/common/models/User.kt @@ -10,6 +10,7 @@ object Users: IntIdTable("users") { val username = varchar("username", 255) val token = varchar("token", 64) val discord = long("discord") + val naverId = long("naver_id") val liveAlertGuild = long("live_alert_guild").nullable() val liveAlertChannel = long("live_alert_channel").nullable() val liveAlertMessage = text("live_alert_message").nullable() @@ -21,6 +22,7 @@ class User(id: EntityID) : IntEntity(id) { var username by Users.username var token by Users.token var discord by Users.discord + var naverId by Users.naverId var liveAlertGuild by Users.liveAlertGuild var liveAlertChannel by Users.liveAlertChannel var liveAlertMessage by Users.liveAlertMessage diff --git a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/SongConfigService.kt b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/SongConfigService.kt index 5722b87..c2e6b54 100644 --- a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/SongConfigService.kt +++ b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/SongConfigService.kt @@ -26,19 +26,6 @@ object SongConfigService { } - fun getConfig(token: String): SongConfig? { - return transaction { - SongConfig.find(SongConfigs.token eq token).firstOrNull() - } - } - fun getUserByToken(token: String): User? { - return transaction { - val songConfig = SongConfig.find(SongConfigs.token eq token).firstOrNull() - if(songConfig == null) null - else UserService.getUser(songConfig.user.discord) - } - } - fun updatePersonalLimit(user: User, limit: Int): SongConfig { return transaction { var songConfig = SongConfig.find(SongConfigs.user eq user.id).firstOrNull() @@ -60,18 +47,6 @@ object SongConfigService { } } - fun updateSession(user: User, token: String?): SongConfig { - return transaction { - var songConfig = SongConfig.find(SongConfigs.user eq user.id).firstOrNull() - if (songConfig == null) { - songConfig = initConfig(user) - } - songConfig.token = token - - songConfig - } - } - fun updateStreamerOnly(user: User, config: Boolean): SongConfig { return transaction { var songConfig = SongConfig.find(SongConfigs.user eq user.id).firstOrNull() diff --git a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt index 1e275c5..3863851 100644 --- a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt +++ b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt @@ -47,6 +47,14 @@ object UserService { } } + fun getUserWithNaverId(naverId: Long): User? { + return transaction { + val users = User.find(Users.naverId eq naverId) + + users.firstOrNull() + } + } + fun getAllUsers(): List { return transaction { User.all().toList() diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiRoutes.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiRoutes.kt index fd0c8cf..b9d50d8 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiRoutes.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiRoutes.kt @@ -4,9 +4,12 @@ import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.ktor.server.sessions.* import kotlinx.serialization.Serializable import space.mori.chzzk_bot.common.services.SongConfigService +import space.mori.chzzk_bot.common.services.UserService import space.mori.chzzk_bot.common.utils.getStreamInfo +import space.mori.chzzk_bot.webserver.UserSession @Serializable data class GetUserDTO( @@ -63,38 +66,29 @@ fun Routing.apiRoutes() { } route("/user") { get { - call.respondText("Require UID", status = HttpStatusCode.NotFound) - } - } - route("/session/{sid}") { - get { - val sid = call.parameters["sid"] - if(sid == null) { - call.respondText("Require SID", status = HttpStatusCode.NotFound) + val session = call.sessions.get() + + if(session == null) { + call.respondText("No session found", status = HttpStatusCode.NotFound) return@get } - val user = SongConfigService.getUserByToken(sid) - val session = SongConfigService.getConfig(sid) + val user = UserService.getUserWithNaverId(session.id.toLong()) if(user == null) { - call.respondText("User not found", status = HttpStatusCode.NotFound) + call.respondText("No session found", status = HttpStatusCode.NotFound) return@get - } else { - val chzzkUser = getStreamInfo(user.token) - call.respond(HttpStatusCode.OK, GetSessionDTO( - chzzkUser.content!!.channel.channelId, - chzzkUser.content!!.channel.channelName, - chzzkUser.content!!.status == "OPEN", - chzzkUser.content!!.channel.channelImageUrl, - session!!.queueLimit, - session.personalLimit, - session.streamerOnly - )) } - } - } - route("/session") { - get { - call.respondText("Require SID", status = HttpStatusCode.NotFound) + val songConfig = SongConfigService.getConfig(user) + val status = getStreamInfo(user.token) + + call.respond(HttpStatusCode.OK, GetSessionDTO( + status.content!!.channel.channelId, + status.content!!.channel.channelName, + status.content!!.status == "OPEN", + status.content!!.channel.channelImageUrl, + songConfig.queueLimit, + songConfig.personalLimit, + songConfig.streamerOnly + )) } } } \ No newline at end of file diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt index bda6a26..06aedd7 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt @@ -1,6 +1,7 @@ package space.mori.chzzk_bot.webserver.routes import io.ktor.server.routing.* +import io.ktor.server.sessions.* import io.ktor.server.websocket.* import io.ktor.websocket.* import kotlinx.coroutines.CoroutineScope @@ -17,6 +18,7 @@ import space.mori.chzzk_bot.common.services.SongConfigService import space.mori.chzzk_bot.common.services.SongListService import space.mori.chzzk_bot.common.services.UserService import space.mori.chzzk_bot.common.utils.getYoutubeVideo +import space.mori.chzzk_bot.webserver.UserSession import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue @@ -27,33 +29,30 @@ fun Routing.wsSongListRoutes() { val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java) - fun addSession(sid: String, session: WebSocketServerSession) { - sessions.computeIfAbsent(sid) { ConcurrentLinkedQueue() }.add(session) + fun addSession(uid: String, session: WebSocketServerSession) { + sessions.computeIfAbsent(uid) { ConcurrentLinkedQueue() }.add(session) } - fun removeSession(sid: String, session: WebSocketServerSession) { - sessions[sid]?.remove(session) - if(sessions[sid]?.isEmpty() == true) { - sessions.remove(sid) + fun removeSession(uid: String, session: WebSocketServerSession) { + sessions[uid]?.remove(session) + if(sessions[uid]?.isEmpty() == true) { + sessions.remove(uid) } } - webSocket("/songlist/{sid}") { - val sid = call.parameters["sid"] - val session = sid?.let { SongConfigService.getConfig(it) } - val user = sid?.let {SongConfigService.getUserByToken(sid) } - if (sid == null) { - close(CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Invalid SID")) - return@webSocket - } - if (user == null || session == null) { + webSocket("/songlist") { + val session = call.sessions.get() + val user = session?.id?.let { UserService.getUserWithNaverId( it.toLong() ) } + if (user == null) { close(CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Invalid SID")) return@webSocket } - addSession(sid, this) + val uid = user.token - if(status[sid] == SongType.STREAM_OFF) { + addSession(uid, this) + + if(status[uid] == SongType.STREAM_OFF) { CoroutineScope(Dispatchers.Default).launch { sendSerialized(SongResponse( SongType.STREAM_OFF.value, @@ -65,7 +64,7 @@ fun Routing.wsSongListRoutes() { null )) } - removeSession(sid, this) + removeSession(uid, this) } try { @@ -107,7 +106,7 @@ fun Routing.wsSongListRoutes() { } } } catch(e: Exception) { - logger.debug("SongType.ADD Error: {} / {}", session.token, e) + logger.debug("SongType.ADD Error: {} / {}", uid, e) } } else if(data.type == SongType.REMOVE.value && data.url != null) { @@ -145,7 +144,7 @@ fun Routing.wsSongListRoutes() { } catch(e: ClosedReceiveChannelException) { logger.error("Error in WebSocket: ${e.message}") } finally { - removeSession(sid, this) + removeSession(uid, this) } } From b864fc262be1636c7e939de1d96482955f9a93bb Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:47:40 +0900 Subject: [PATCH 2/3] add Session flows - WSSongListRoutes - fix CORS --- .../main/kotlin/space/mori/chzzk_bot/webserver/Main.kt | 10 +++++++--- .../chzzk_bot/webserver/routes/WSSongListRoutes.kt | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt index 155e6e0..4d0d446 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt @@ -20,7 +20,6 @@ import io.ktor.server.sessions.* import io.ktor.server.websocket.* import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json -import space.mori.chzzk_bot.common.dotenv import space.mori.chzzk_bot.webserver.routes.* import java.time.Duration @@ -48,8 +47,13 @@ val server = embeddedServer(Netty, port = 8080, ) { }) } install(CORS) { - anyHost() - allowHeader(HttpHeaders.ContentType) + allowMethod(HttpMethod.Options) + allowMethod(HttpMethod.Put) + allowMethod(HttpMethod.Patch) + allowMethod(HttpMethod.Delete) + allowMethod(HttpMethod.Get) + allowHost("http://localhost:8080") + allowHost(dotenv["FRONTEND"]) } install(Sessions) { cookie("user_session", storage = SessionStorageMemory()) {} diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt index 06aedd7..b2c063f 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/WSSongListRoutes.kt @@ -13,7 +13,6 @@ import kotlinx.serialization.json.Json import org.koin.java.KoinJavaComponent.inject import org.slf4j.LoggerFactory import space.mori.chzzk_bot.common.events.* -import space.mori.chzzk_bot.common.models.Counters.withDefinition import space.mori.chzzk_bot.common.services.SongConfigService import space.mori.chzzk_bot.common.services.SongListService import space.mori.chzzk_bot.common.services.UserService From c179195b1883d43f19468320bba96f2443469e8f Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:22:06 +0900 Subject: [PATCH 3/3] add Session flows - fix CORS --- .../src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt index 4d0d446..ab3e1b2 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt @@ -52,8 +52,7 @@ val server = embeddedServer(Netty, port = 8080, ) { allowMethod(HttpMethod.Patch) allowMethod(HttpMethod.Delete) allowMethod(HttpMethod.Get) - allowHost("http://localhost:8080") - allowHost(dotenv["FRONTEND"]) + anyHost() } install(Sessions) { cookie("user_session", storage = SessionStorageMemory()) {}