minecraft-mod/ServerStatus/src/main/kotlin/com/beemer/serverstatus/command/AuthCommand.kt

153 lines
5.8 KiB
Kotlin

package com.beemer.serverstatus.command
import com.beemer.serverstatus.ServerStatusMod
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.StringArgumentType
import com.mojang.brigadier.context.CommandContext
import java.net.HttpURLConnection
import java.net.URI
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.minecraft.commands.CommandSourceStack
import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
/** /인증 명령어 처리 웹사이트 계정 연동을 위한 명령어 */
object AuthCommand {
private val json = Json {
ignoreUnknownKeys = true
encodeDefaults = true
}
// 웹 서버 연동 API URL (환경 또는 설정에서 가져올 수 있음)
private const val WEB_API_URL = "http://minecraft-status/link/verify"
/** 명령어 등록 */
fun register(dispatcher: CommandDispatcher<CommandSourceStack>) {
// /인증 <토큰>
dispatcher.register(
Commands.literal("인증")
.then(
Commands.argument("token", StringArgumentType.word()).executes {
context ->
executeAuth(context)
}
)
)
ServerStatusMod.LOGGER.info("[${ServerStatusMod.MOD_ID}] /인증 명령어 등록됨")
}
/** 인증 명령어 실행 */
private fun executeAuth(context: CommandContext<CommandSourceStack>): Int {
val source = context.source
val player = source.player
// 플레이어만 사용 가능
if (player == null) {
source.sendFailure(Component.literal("§c플레이어만 이 명령어를 사용할 수 있습니다."))
return 0
}
val token = StringArgumentType.getString(context, "token").uppercase()
// 토큰 검증 (6자리 영숫자)
if (!token.matches(Regex("^[A-Z0-9]{6}$"))) {
source.sendFailure(Component.literal("§c유효하지 않은 인증 코드입니다."))
return 0
}
// 비동기로 웹 API 호출
Thread {
try {
val result = verifyWithWebServer(token, player)
// UI 스레드에서 메시지 전송
player.server.execute {
if (result.success) {
player.sendSystemMessage(
Component.literal("§a§l✓ 계정 연동 완료!\n§7웹사이트에서 프로필이 업데이트됩니다.")
)
} else {
player.sendSystemMessage(
Component.literal(
"§c✗ 연동 실패: ${result.error ?: "알 수 없는 오류"}"
)
)
}
}
} catch (e: Exception) {
ServerStatusMod.LOGGER.error(
"[${ServerStatusMod.MOD_ID}] 인증 오류: ${e.message}"
)
player.server.execute {
player.sendSystemMessage(Component.literal("§c✗ 연동 처리 중 오류가 발생했습니다."))
}
}
}
.start()
// 즉시 응답
source.sendSuccess({ Component.literal("§e인증 처리 중...") }, false)
return 1
}
/** 웹 서버에 연동 요청 */
private fun verifyWithWebServer(token: String, player: ServerPlayer): VerifyResponse {
val requestBody =
json.encodeToString(
VerifyRequest(
token = token,
uuid = player.stringUUID,
name = player.name.string
)
)
val url = URI(WEB_API_URL).toURL()
val conn = url.openConnection() as HttpURLConnection
try {
conn.requestMethod = "POST"
conn.doOutput = true
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8")
conn.connectTimeout = 5000
conn.readTimeout = 5000
// 요청 전송
conn.outputStream.use { os -> os.write(requestBody.toByteArray(Charsets.UTF_8)) }
// 응답 처리
val responseCode = conn.responseCode
val responseBody =
if (responseCode in 200..299) {
conn.inputStream.bufferedReader().use { it.readText() }
} else {
conn.errorStream?.bufferedReader()?.use { it.readText() } ?: ""
}
ServerStatusMod.LOGGER.info(
"[${ServerStatusMod.MOD_ID}] 인증 응답: $responseCode - $responseBody"
)
return try {
json.decodeFromString<VerifyResponse>(responseBody)
} catch (e: Exception) {
VerifyResponse(success = responseCode in 200..299, error = responseBody)
}
} finally {
conn.disconnect()
}
}
@Serializable data class VerifyRequest(val token: String, val uuid: String, val name: String)
@Serializable
data class VerifyResponse(
val success: Boolean = false,
val message: String? = null,
val error: String? = null
)
}