add counter, counter handlers

This commit is contained in:
dalbodeule 2024-06-13 14:43:49 +09:00
parent 4da72f194e
commit 20f6d84040
No known key found for this signature in database
GPG Key ID: EFA860D069C9FA65
16 changed files with 285 additions and 41 deletions

View File

@ -66,9 +66,9 @@ dependencies {
// https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-dao // https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-dao
implementation("org.jetbrains.exposed:exposed-dao:0.51.1") implementation("org.jetbrains.exposed:exposed-dao:0.51.1")
// https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-jdbc // https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-jdbc
runtimeOnly("org.jetbrains.exposed:exposed-jdbc:0.51.1") implementation("org.jetbrains.exposed:exposed-jdbc:0.51.1")
// https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-kotlin-datetime // https://mvnrepository.com/artifact/org.jetbrains.exposed/exposed-kotlin-datetime
runtimeOnly("org.jetbrains.exposed:exposed-kotlin-datetime:0.51.1") implementation("org.jetbrains.exposed:exposed-java-time:0.51.1")
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP // https://mvnrepository.com/artifact/com.zaxxer/HikariCP
implementation("com.zaxxer:HikariCP:5.1.0") implementation("com.zaxxer:HikariCP:5.1.0")

View File

@ -7,13 +7,12 @@ import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import space.mori.chzzk_bot.models.Commands import space.mori.chzzk_bot.models.*
import space.mori.chzzk_bot.models.Users
object Connector { object Connector {
private val dotenv = dotenv() private val dotenv = dotenv()
val hikariConfig = HikariConfig().apply { private val hikariConfig = HikariConfig().apply {
jdbcUrl = dotenv["DB_URL"] jdbcUrl = dotenv["DB_URL"]
driverClassName = "org.mariadb.jdbc.Driver" driverClassName = "org.mariadb.jdbc.Driver"
username = dotenv["DB_USER"] username = dotenv["DB_USER"]
@ -24,12 +23,10 @@ object Connector {
init { init {
Database.connect(dataSource) Database.connect(dataSource)
val tables = listOf(Users, Commands) val tables = listOf(Users, Commands, Counters, DailyCounters, PersonalCounters)
transaction { transaction {
tables.forEach { table -> SchemaUtils.createMissingTablesAndColumns(* tables.toTypedArray())
SchemaUtils.createMissingTablesAndColumns(table)
}
} }
} }
} }

View File

@ -9,6 +9,7 @@ import space.mori.chzzk_bot.chzzk.ChzzkHandler
import space.mori.chzzk_bot.discord.Discord import space.mori.chzzk_bot.discord.Discord
import space.mori.chzzk_bot.chzzk.Connector as ChzzkConnector import space.mori.chzzk_bot.chzzk.Connector as ChzzkConnector
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess
val dotenv = dotenv() val dotenv = dotenv()
val logger: Logger = LoggerFactory.getLogger("main") val logger: Logger = LoggerFactory.getLogger("main")
@ -26,7 +27,7 @@ fun main(args: Array<String>) {
if(dotenv.get("RUN_AGENT", "false").toBoolean()) { if(dotenv.get("RUN_AGENT", "false").toBoolean()) {
runBlocking { runBlocking {
delay(TimeUnit.MINUTES.toMillis(1)) delay(TimeUnit.MINUTES.toMillis(1))
discord.disable() exitProcess(0)
} }
} }

View File

@ -3,6 +3,7 @@ package space.mori.chzzk_bot.chzzk
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import space.mori.chzzk_bot.chzzk.Connector.chzzk import space.mori.chzzk_bot.chzzk.Connector.chzzk
import space.mori.chzzk_bot.models.User
import space.mori.chzzk_bot.services.UserService import space.mori.chzzk_bot.services.UserService
import xyz.r2turntrue.chzzk4j.chat.ChatEventListener import xyz.r2turntrue.chzzk4j.chat.ChatEventListener
import xyz.r2turntrue.chzzk4j.chat.ChatMessage import xyz.r2turntrue.chzzk4j.chat.ChatMessage
@ -14,13 +15,13 @@ object ChzzkHandler {
private val handlers = mutableListOf<UserHandler>() private val handlers = mutableListOf<UserHandler>()
private val logger = LoggerFactory.getLogger(this::class.java) private val logger = LoggerFactory.getLogger(this::class.java)
internal fun addUser(chzzkChannel: ChzzkChannel) { internal fun addUser(chzzkChannel: ChzzkChannel, user: User) {
handlers.add(UserHandler(chzzkChannel, logger)) handlers.add(UserHandler(chzzkChannel, logger, user))
} }
internal fun enable() { internal fun enable() {
UserService.getAllUsers().map { UserService.getAllUsers().map {
chzzk.getChannel(it.token)?.let { token -> addUser(token)} chzzk.getChannel(it.token)?.let { token -> addUser(token, it)}
} }
} }
@ -31,7 +32,7 @@ object ChzzkHandler {
} }
internal fun reloadCommand(chzzkChannel: ChzzkChannel) { internal fun reloadCommand(chzzkChannel: ChzzkChannel) {
val handler = handlers.firstOrNull { it.channel == chzzkChannel } val handler = handlers.firstOrNull { it.channel.channelId == chzzkChannel.channelId }
if (handler != null) if (handler != null)
handler.reloadCommand() handler.reloadCommand()
else else
@ -39,7 +40,9 @@ object ChzzkHandler {
} }
} }
class UserHandler(val channel: ChzzkChannel, private val logger: Logger) { class UserHandler(
val channel: ChzzkChannel, private val logger: Logger, private val user: User
) {
private lateinit var messageHandler: MessageHandler private lateinit var messageHandler: MessageHandler
private var listener: ChzzkChat = chzzk.chat(channel.channelId) private var listener: ChzzkChat = chzzk.chat(channel.channelId)
@ -56,7 +59,7 @@ class UserHandler(val channel: ChzzkChannel, private val logger: Logger) {
} }
override fun onChat(msg: ChatMessage) { override fun onChat(msg: ChatMessage) {
messageHandler.handle(msg) messageHandler.handle(msg, user)
} }
override fun onConnectionClosed(code: Int, reason: String?, remote: Boolean, tryingToReconnect: Boolean) { override fun onConnectionClosed(code: Int, reason: String?, remote: Boolean, tryingToReconnect: Boolean) {

View File

@ -1,7 +1,9 @@
package space.mori.chzzk_bot.chzzk package space.mori.chzzk_bot.chzzk
import org.slf4j.Logger import org.slf4j.Logger
import space.mori.chzzk_bot.models.User
import space.mori.chzzk_bot.services.CommandService import space.mori.chzzk_bot.services.CommandService
import space.mori.chzzk_bot.services.CounterService
import space.mori.chzzk_bot.services.UserService import space.mori.chzzk_bot.services.UserService
import xyz.r2turntrue.chzzk4j.chat.ChatMessage import xyz.r2turntrue.chzzk4j.chat.ChatMessage
import xyz.r2turntrue.chzzk4j.chat.ChzzkChat import xyz.r2turntrue.chzzk4j.chat.ChzzkChat
@ -12,7 +14,12 @@ class MessageHandler(
private val logger: Logger, private val logger: Logger,
private val listener: ChzzkChat private val listener: ChzzkChat
) { ) {
private val commands = mutableMapOf<String, () -> Unit>() private val commands = mutableMapOf<String, (msg: ChatMessage, user: User) -> Unit>()
private val counterPattern = Regex("<counter:([^>]+)>")
private val personalCounterPattern = Regex("<counter_personal:([^>]+)>")
private val dailyCounterPattern = Regex("<daily_counter:([^>]+)>")
private val namePattern = Regex("<name>")
init { init {
reloadCommand() reloadCommand()
@ -24,16 +31,59 @@ class MessageHandler(
val commands = CommandService.getCommands(user) val commands = CommandService.getCommands(user)
commands.map { commands.map {
this.commands.put(it.command.lowercase()) { this.commands.put(it.command.lowercase()) { msg, user ->
logger.debug("${channel.channelName} - ${it.command} - ${it.content}") logger.debug("${channel.channelName} - ${it.command} - ${it.content}/${it.failContent}")
listener.sendChat(it.content)
val result = replaceCounters(Pair(it.content, it.failContent), user, msg.userId, msg.profile?.nickname ?: "")
listener.sendChat(result)
} }
} }
} }
internal fun handle(msg: ChatMessage) { internal fun handle(msg: ChatMessage, user: User) {
val commandKey = msg.content.split(' ')[0] val commandKey = msg.content.split(' ')[0]
commands[commandKey.lowercase()]?.let { it() } commands[commandKey.lowercase()]?.let { it(msg, user) }
}
private fun replaceCounters(chat: Pair<String, String>, user: User, userId: String, userName: String): String {
var result = chat.first
var isFail = false
result = counterPattern.replace(result) {
val name = it.groupValues[1]
CounterService.updateCounterValue(name, 1, user).toString()
}
result = personalCounterPattern.replace(result) {
val name = it.groupValues[1]
CounterService.updatePersonalCounterValue(name, userId, 1, user).toString()
}
result = dailyCounterPattern.replace(result) {
val name = it.groupValues[1]
val dailyCounter = CounterService.getDailyCounterValue(name, userId, user)
return@replace if(dailyCounter.second)
CounterService.updateDailyCounterValue(name, userId, 1, user).first.toString()
else {
isFail = true
dailyCounter.first.toString()
}
}
if(isFail) {
result = chat.second
result = dailyCounterPattern.replace(result) {
val name = it.groupValues[1]
val dailyCounter = CounterService.getDailyCounterValue(name, userId, user)
dailyCounter.first.toString()
}
}
result = namePattern.replace(result, userName)
return result
} }
} }

View File

@ -20,10 +20,12 @@ object AddCommand : CommandInterface {
override val command = Commands.slash(name, "명령어를 추가합니다.") override val command = Commands.slash(name, "명령어를 추가합니다.")
.addOptions(OptionData(OptionType.STRING, "label", "작동할 명령어를 입력하세요.", true)) .addOptions(OptionData(OptionType.STRING, "label", "작동할 명령어를 입력하세요.", true))
.addOptions(OptionData(OptionType.STRING, "content", "표시될 텍스트를 입력하세요.", true)) .addOptions(OptionData(OptionType.STRING, "content", "표시될 텍스트를 입력하세요.", true))
.addOptions(OptionData(OptionType.STRING, "fail_content", "카운터 업데이트 실패시 표시될 텍스트를 입력하세요.", false))
override fun run(event: SlashCommandInteractionEvent, bot: JDA) { override fun run(event: SlashCommandInteractionEvent, bot: JDA) {
val label = event.getOption("label")?.asString val label = event.getOption("label")?.asString
val content = event.getOption("content")?.asString val content = event.getOption("content")?.asString
val failContent = event.getOption("fail_content")?.asString
if(label == null || content == null) { if(label == null || content == null) {
event.hook.sendMessage("명령어와 텍스트는 필수 입력입니다.").queue() event.hook.sendMessage("명령어와 텍스트는 필수 입력입니다.").queue()
@ -35,14 +37,21 @@ object AddCommand : CommandInterface {
event.hook.sendMessage("치지직 계정을 찾을 수 없습니다.").queue() event.hook.sendMessage("치지직 계정을 찾을 수 없습니다.").queue()
return return
} }
val commands = CommandService.getCommands(user)
if (commands.any { it.command == label }) {
event.hook.sendMessage("$label 명령어는 이미 있습니다! 업데이트 명령어를 써주세요.").queue()
return
}
val chzzkChannel = Connector.getChannel(user.token) val chzzkChannel = Connector.getChannel(user.token)
try { try {
CommandService.saveCommand(user, label, content) CommandService.saveCommand(user, label, content, failContent ?: "")
try { try {
ChzzkHandler.reloadCommand(chzzkChannel!!) ChzzkHandler.reloadCommand(chzzkChannel!!)
} catch (_: Exception) {} } catch (_: Exception) {}
event.hook.sendMessage("등록이 완료되었습니다. $label = $content").queue() event.hook.sendMessage("등록이 완료되었습니다. $label = $content/$failContent").queue()
} catch (e: Exception) { } catch (e: Exception) {
event.hook.sendMessage("에러가 발생했습니다.").queue() event.hook.sendMessage("에러가 발생했습니다.").queue()
logger.debug(e.stackTraceToString()) logger.debug(e.stackTraceToString())

View File

@ -40,8 +40,8 @@ object Register: CommandInterface {
} }
try { try {
UserService.saveUser(chzzkChannel.channelName, chzzkChannel.channelId, event.user.idLong) val user = UserService.saveUser(chzzkChannel.channelName, chzzkChannel.channelId, event.user.idLong)
ChzzkHandler.addUser(chzzkChannel) ChzzkHandler.addUser(chzzkChannel, user)
event.hook.sendMessage("등록이 완료되었습니다. `${chzzkChannel.channelId}` - `${chzzkChannel.channelName}`") event.hook.sendMessage("등록이 완료되었습니다. `${chzzkChannel.channelId}` - `${chzzkChannel.channelName}`")
} catch(e: Exception) { } catch(e: Exception) {
event.hook.sendMessage("에러가 발생했습니다.").queue() event.hook.sendMessage("에러가 발생했습니다.").queue()

View File

@ -21,10 +21,12 @@ object UpdateCommand : CommandInterface {
override val command = Commands.slash(name, "명령어를 수정합니다.") override val command = Commands.slash(name, "명령어를 수정합니다.")
.addOptions(OptionData(OptionType.STRING, "label", "수정할 명령어를 입력하세요.", true)) .addOptions(OptionData(OptionType.STRING, "label", "수정할 명령어를 입력하세요.", true))
.addOptions(OptionData(OptionType.STRING, "content", "표시될 텍스트를 입력하세요.", true)) .addOptions(OptionData(OptionType.STRING, "content", "표시될 텍스트를 입력하세요.", true))
.addOptions(OptionData(OptionType.STRING, "fail_content", "카운터 업데이트 실패시 표시될 텍스트를 입력하세요.", false))
override fun run(event: SlashCommandInteractionEvent, bot: JDA) { override fun run(event: SlashCommandInteractionEvent, bot: JDA) {
val label = event.getOption("label")?.asString val label = event.getOption("label")?.asString
val content = event.getOption("content")?.asString val content = event.getOption("content")?.asString
val failContent = event.getOption("fail_content")?.asString
if(label == null || content == null) { if(label == null || content == null) {
event.hook.sendMessage("명령어와 텍스트는 필수 입력입니다.").queue() event.hook.sendMessage("명령어와 텍스트는 필수 입력입니다.").queue()
@ -39,10 +41,8 @@ object UpdateCommand : CommandInterface {
val chzzkChannel = Connector.getChannel(user.token) val chzzkChannel = Connector.getChannel(user.token)
try { try {
CommandService.updateCommand(user, label, content) CommandService.updateCommand(user, label, content, failContent ?: "")
try { chzzkChannel?.let { ChzzkHandler.reloadCommand(it) }
ChzzkHandler.reloadCommand(chzzkChannel!!)
} catch (_: Exception) {}
event.hook.sendMessage("등록이 완료되었습니다. $label = $content").queue() event.hook.sendMessage("등록이 완료되었습니다. $label = $content").queue()
} catch (e: Exception) { } catch (e: Exception) {
event.hook.sendMessage("에러가 발생했습니다.").queue() event.hook.sendMessage("에러가 발생했습니다.").queue()

View File

@ -10,6 +10,7 @@ object Commands: IntIdTable("commands") {
val user = reference("user", Users, onDelete = ReferenceOption.CASCADE) val user = reference("user", Users, onDelete = ReferenceOption.CASCADE)
val command = varchar("command", 255) val command = varchar("command", 255)
val content = text("content") val content = text("content")
val failContent = text("fail_content")
} }
class Command(id: EntityID<Int>) : IntEntity(id) { class Command(id: EntityID<Int>) : IntEntity(id) {
@ -18,4 +19,5 @@ class Command(id: EntityID<Int>) : IntEntity(id) {
var user by User referencedOn Commands.user var user by User referencedOn Commands.user
var command by Commands.command var command by Commands.command
var content by Commands.content var content by Commands.content
var failContent by Commands.failContent
} }

View File

@ -0,0 +1,20 @@
package space.mori.chzzk_bot.models
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
object Counters: IntIdTable("counters") {
val name = varchar("name", 255)
val value = integer("value")
val user = reference("streamer", Users)
}
class Counter(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Counter>(Counters)
var name by Counters.name
var value by Counters.value
var user by User referencedOn Counters.user
}

View File

@ -0,0 +1,25 @@
package space.mori.chzzk_bot.models
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.javatime.date
object DailyCounters: IntIdTable("daily_counters") {
val name = varchar("name", 255)
val userId = varchar("user_id", 64)
val value = integer("value")
val updatedAt = date("updated_at")
val user = reference("streamer", Users)
}
class DailyCounter(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<DailyCounter>(DailyCounters)
var name by DailyCounters.name
var userId by DailyCounters.userId
var value by DailyCounters.value
var updatedAt by DailyCounters.updatedAt
var user by User referencedOn DailyCounters.user
}

View File

@ -0,0 +1,22 @@
package space.mori.chzzk_bot.models
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
object PersonalCounters: IntIdTable("personal_counters") {
val name = varchar("name", 255)
val userId = varchar("user_id", 64)
val value = integer("value")
val user = reference("streamer", Users)
}
class PersonalCounter(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<PersonalCounter>(PersonalCounters)
var name by PersonalCounters.name
var userId by PersonalCounters.userId
var value by PersonalCounters.value
var user by User referencedOn PersonalCounters.user
}

View File

@ -9,12 +9,13 @@ import space.mori.chzzk_bot.models.Commands
import space.mori.chzzk_bot.models.User import space.mori.chzzk_bot.models.User
object CommandService { object CommandService {
fun saveCommand(user: User, command: String, content: String): Command { fun saveCommand(user: User, command: String, content: String, failContent: String): Command {
return transaction { return transaction {
return@transaction Command.new { return@transaction Command.new {
this.user = user this.user = user
this.command = command this.command = command
this.content = content this.content = content
this.failContent = failContent
} }
} }
} }
@ -26,31 +27,32 @@ object CommandService {
commandRow ?: throw RuntimeException("Command not found! $command") commandRow ?: throw RuntimeException("Command not found! $command")
commandRow.delete() commandRow.delete()
return@transaction commandRow commandRow
} }
} }
fun updateCommand(user: User, command: String, content: String): Command { fun updateCommand(user: User, command: String, content: String, failContent: String): Command {
return transaction { return transaction {
val updated = Commands.update({Commands.user eq user.id and(Commands.command eq command)}) { val updated = Commands.update({Commands.user eq user.id and(Commands.command eq command)}) {
it[Commands.content] = content it[Commands.content] = content
it[Commands.failContent] = failContent
} }
if(updated == 0) throw RuntimeException("Command not found! $command") if(updated == 0) throw RuntimeException("Command not found! $command")
return@transaction Command.find(Commands.user eq user.id and(Commands.command eq command)).first() Command.find(Commands.user eq user.id and(Commands.command eq command)).first()
} }
} }
fun getCommand(id: Int): Command? { fun getCommand(id: Int): Command? {
return transaction { return transaction {
return@transaction Command.findById(id) Command.findById(id)
} }
} }
fun getCommands(user: User): List<Command> { fun getCommands(user: User): List<Command> {
return transaction { return transaction {
return@transaction Command.find(Commands.user eq user.id) Command.find(Commands.user eq user.id)
.toList() .toList()
} }
} }

View File

@ -0,0 +1,105 @@
package space.mori.chzzk_bot.services
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.transactions.transaction
import space.mori.chzzk_bot.models.*
import java.time.LocalDate
object CounterService {
fun getCounterValue(name: String, user: User): Int {
return transaction {
Counter.find {
(Counters.name eq name) and (Counters.user eq user.id)
}.singleOrNull()?.value ?: 0
}
}
fun updateCounterValue(name: String, increment: Int, user: User): Int {
return transaction {
val counter = Counter.find {
(Counters.name eq name) and (Counters.user eq user.id) }.singleOrNull()
return@transaction if (counter != null) {
counter.value += increment
counter.value
} else {
val newCounter = Counter.new {
this.name = name
this.value = increment
this.user = user
}
newCounter.value
}
}
}
fun getPersonalCounterValue(name: String, userId: String, user: User): Int {
return transaction {
PersonalCounter.find {
(PersonalCounters.name eq name) and (PersonalCounters.userId eq userId) and (PersonalCounters.user eq user.id)
}.singleOrNull()?.value ?: 0
}
}
fun updatePersonalCounterValue(name: String, userId: String, increment: Int, user: User): Int {
return transaction {
val counter = PersonalCounter.find {
(PersonalCounters.name eq name) and (PersonalCounters.userId eq userId) and (PersonalCounters.user eq user.id)
}.singleOrNull()
return@transaction if (counter != null) {
counter.value += increment
counter.value
} else {
val newCounter = PersonalCounter.new {
this.name = name
this.value = increment
this.userId = userId
this.user = user
}
newCounter.value
}
}
}
fun getDailyCounterValue(name: String, userId: String, user: User): Pair<Int, Boolean> {
val today = LocalDate.now()
return transaction {
val counter = DailyCounter.find {
(DailyCounters.name eq name) and (DailyCounters.userId eq userId) and (DailyCounters.user eq user.id)
}.singleOrNull()
Pair(counter?.value ?: 0, counter?.updatedAt != today)
}
}
fun updateDailyCounterValue(name: String, userId: String, increment: Int, user: User): Pair<Int, Boolean> {
val today = LocalDate.now()
return transaction {
val counter = DailyCounter.find {
(DailyCounters.name eq name) and (DailyCounters.userId eq userId) and (DailyCounters.user eq user.id)
}.singleOrNull()
println("$counter")
if(counter == null) {
val newCounter = DailyCounter.new {
this.name = name
this.value = increment
this.userId = userId
this.updatedAt = today
this.user = user
}
return@transaction Pair(newCounter.value, true)
}
return@transaction if(counter.updatedAt == today)
Pair(counter.value, false)
else {
counter.value += increment
Pair(counter.value, true)
}
}
}
}

View File

@ -8,7 +8,7 @@ import space.mori.chzzk_bot.models.Users
object UserService { object UserService {
fun saveUser(username: String, token: String, discordID: Long): User { fun saveUser(username: String, token: String, discordID: Long): User {
return transaction { return transaction {
return@transaction User.new { User.new {
this.username = username this.username = username
this.token = token this.token = token
this.discord = discordID this.discord = discordID
@ -18,7 +18,7 @@ object UserService {
fun getUser(id: Int): User? { fun getUser(id: Int): User? {
return transaction { return transaction {
return@transaction User.findById(id) User.findById(id)
} }
} }
@ -26,7 +26,7 @@ object UserService {
return transaction { return transaction {
val users = User.find(Users.discord eq discordID) val users = User.find(Users.discord eq discordID)
return@transaction users.firstOrNull() users.firstOrNull()
} }
} }
@ -34,13 +34,13 @@ object UserService {
return transaction { return transaction {
val users = User.find(Users.token eq chzzkID) val users = User.find(Users.token eq chzzkID)
return@transaction users.firstOrNull() users.firstOrNull()
} }
} }
fun getAllUsers(): List<User> { fun getAllUsers(): List<User> {
return transaction { return transaction {
return@transaction User.all().toList() User.all().toList()
} }
} }
} }

View File

@ -380,6 +380,10 @@
"name":"kotlinx.coroutines.CancellableContinuationImpl", "name":"kotlinx.coroutines.CancellableContinuationImpl",
"fields":[{"name":"_decisionAndIndex$volatile"}, {"name":"_parentHandle$volatile"}, {"name":"_state$volatile"}] "fields":[{"name":"_decisionAndIndex$volatile"}, {"name":"_parentHandle$volatile"}, {"name":"_state$volatile"}]
}, },
{
"name":"kotlinx.coroutines.CompletedExceptionally",
"fields":[{"name":"_handled$volatile"}]
},
{ {
"name":"kotlinx.coroutines.EventLoopImplBase", "name":"kotlinx.coroutines.EventLoopImplBase",
"fields":[{"name":"_delayed$volatile"}, {"name":"_isCompleted$volatile"}, {"name":"_queue$volatile"}] "fields":[{"name":"_delayed$volatile"}, {"name":"_isCompleted$volatile"}, {"name":"_queue$volatile"}]
@ -388,6 +392,10 @@
"name":"kotlinx.coroutines.JobSupport", "name":"kotlinx.coroutines.JobSupport",
"fields":[{"name":"_parentHandle$volatile"}, {"name":"_state$volatile"}] "fields":[{"name":"_parentHandle$volatile"}, {"name":"_state$volatile"}]
}, },
{
"name":"kotlinx.coroutines.JobSupport$Finishing",
"fields":[{"name":"_exceptionsHolder$volatile"}, {"name":"_isCompleting$volatile"}, {"name":"_rootCause$volatile"}]
},
{ {
"name":"kotlinx.coroutines.internal.DispatchedContinuation", "name":"kotlinx.coroutines.internal.DispatchedContinuation",
"fields":[{"name":"_reusableCancellableContinuation$volatile"}] "fields":[{"name":"_reusableCancellableContinuation$volatile"}]