diff --git a/src/main/kotlin/net/taehui/twilight/Site.kt b/src/main/kotlin/net/taehui/twilight/Site.kt index 6cc77f1..caf47b4 100644 --- a/src/main/kotlin/net/taehui/twilight/Site.kt +++ b/src/main/kotlin/net/taehui/twilight/Site.kt @@ -7,6 +7,7 @@ import net.dv8tion.jda.api.events.message.MessageDeleteEvent import net.dv8tion.jda.api.events.message.MessageReceivedEvent import net.dv8tion.jda.api.events.message.MessageUpdateEvent +import net.taehui.twilight.site.SiteAvatar import net.taehui.twilight.system.* import okhttp3.internal.toImmutableList import org.apache.commons.io.FileUtils @@ -678,10 +679,9 @@ tryQuitNet() } avatarGroups.remove(avatarID) - if (siteHandQueue.remove(avatar)) { - if (siteHand == avatar) { - setAutoSiteHand() - } + siteHandQueue.remove(avatar) + if (siteHand == avatar) { + setAutoSiteHand() } avatar.send(EventOuterClass.Event.EventID.QUIT_SITE, siteID.toString()) if (isEnterQuitAware && avatar.isEnterQuitAware) { @@ -717,7 +717,9 @@ avatarGroups[avatarID] = if (isNetSite) 0 else -1 lastAudioInputMillis[avatarID] = Long.MIN_VALUE isAudioInputs[avatarID] = false - siteHandQueue.addFirst(avatar) + if (avatar !is SiteAvatar) { + siteHandQueue.addFirst(avatar) + } val data = synchronized(siteYells) { siteYells.stream().skip(0.coerceAtLeast(siteYells.size - SITE_YELL_UNIT).toLong()).map { val avatarName = it.avatarName diff --git a/src/main/kotlin/net/taehui/twilight/Twilight.kt b/src/main/kotlin/net/taehui/twilight/Twilight.kt index 567bb3c..539381d 100644 --- a/src/main/kotlin/net/taehui/twilight/Twilight.kt +++ b/src/main/kotlin/net/taehui/twilight/Twilight.kt @@ -4,7 +4,7 @@ import net.taehui.twilight.qwilight.QwilightBoot import net.taehui.twilight.site.SiteBoot import net.taehui.twilight.system.* -import net.taehui.twilight.trust.TrustBoot +import net.taehui.twilight.etc.EtcBoot import net.taehui.twilight.www.WwwBoot import org.fusesource.jansi.AnsiConsole import java.io.IOException @@ -89,7 +89,7 @@ QwilightBoot(eventLoopGroup, sslContext).use { SiteBoot(eventLoopGroup).use { WwwBoot(eventLoopGroup).use { - TrustBoot(eventLoopGroup).use { + EtcBoot(eventLoopGroup).use { AvatarHandler.sendClose(IO.handleSystem()) } } diff --git a/src/main/kotlin/net/taehui/twilight/Utility.kt b/src/main/kotlin/net/taehui/twilight/Utility.kt index 293143e..aad629e 100644 --- a/src/main/kotlin/net/taehui/twilight/Utility.kt +++ b/src/main/kotlin/net/taehui/twilight/Utility.kt @@ -38,8 +38,9 @@ } fun getDefaultAvatarID(avatarID: String): String { - val platformID = avatarID.substring(avatarID.indexOf('@') + 1) - return PlatformIDSystem.getAvatarID(avatarID.substring(avatarID.indexOf('$') + 1)) ?: platformID + val siteWipedID = avatarID.substring(avatarID.indexOf('@') + 1) + val platformWipedID = siteWipedID.substring(siteWipedID.indexOf('$') + 1) + return PlatformIDSystem.getAvatarID(platformWipedID) ?: siteWipedID } fun getFaultText(e: Throwable): String { diff --git a/src/main/kotlin/net/taehui/twilight/etc/EtcAvatar.kt b/src/main/kotlin/net/taehui/twilight/etc/EtcAvatar.kt new file mode 100644 index 0000000..c4ebf82 --- /dev/null +++ b/src/main/kotlin/net/taehui/twilight/etc/EtcAvatar.kt @@ -0,0 +1,149 @@ +package net.taehui.twilight.etc + +import com.fasterxml.jackson.databind.ObjectMapper +import io.netty.buffer.ByteBufUtil +import io.netty.channel.ChannelFutureListener +import io.netty.channel.ChannelHandlerContext +import io.netty.channel.SimpleChannelInboundHandler +import io.netty.handler.codec.http.* +import net.taehui.twilight.Logger +import net.taehui.twilight.Utility +import net.taehui.twilight.system.AvatarHandler +import net.taehui.twilight.system.Configure +import org.slf4j.LoggerFactory +import java.net.InetSocketAddress +import java.net.URLDecoder +import java.nio.charset.StandardCharsets +import java.nio.file.Files + +class EtcAvatar : SimpleChannelInboundHandler(), Logger { + class QwilightDate { + var date = "" + var hashAMD64 = "" + var hashARM64 = "" + var titleAMD64 = "" + var titleARM64 = "" + @Deprecated("hashX64") + var hashX64 = "" + @Deprecated("titleX64") + var titleX64 = "" + } + + private var avatarIP = "" + + private fun send204(handler: ChannelHandlerContext) { + handler.writeAndFlush(DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT)) + .addListener(ChannelFutureListener.CLOSE) + } + + override fun channelActive(ctx: ChannelHandlerContext) { + avatarIP = (ctx.channel().remoteAddress() as InetSocketAddress).address.hostAddress + } + + public override fun channelRead0(ctx: ChannelHandlerContext, msg: FullHttpRequest) { + fun getQwilightDate(): QwilightDate { + val jm = ObjectMapper() + val qwilightDateFilePath = Configure.path.wwwPath.resolve(Configure.path.datePath) + return jm.readValue(Files.readString(qwilightDateFilePath), QwilightDate::class.java) + } + + val path = URLDecoder.decode(msg.uri(), StandardCharsets.UTF_8) + val mode = msg.method() + logInfo("$mode $path") + when (mode) { + HttpMethod.GET -> when (path) { + "/health" -> { + send204(ctx) + } + } + + HttpMethod.PATCH -> when (path) { + "/date/AMD64" -> { + val data = ByteBufUtil.getBytes(msg.content()) + logFuture { + Files.write(Configure.path.wwwPath.resolve(getQwilightDate().titleAMD64), data) + send204(ctx) + } + } + + "/date/ARM64" -> { + val data = ByteBufUtil.getBytes(msg.content()) + logFuture { + Files.write(Configure.path.wwwPath.resolve(getQwilightDate().titleARM64), data) + send204(ctx) + } + } + + "/date" -> { + val data = msg.content().toString(StandardCharsets.UTF_8).split(" ".toRegex()) + logFuture { + var date = data[0] + val hashAMD64 = data[1] + val hashARM64 = data[2] + if (date.contains("!")) { + Configure.hash.clear() + date = date.replace("!", "") + } + Configure.hash.add(hashAMD64) + Configure.hash.add(hashARM64) + Configure.saveConfigure() + val jm = ObjectMapper() + val qwilightDateFilePath = Configure.path.wwwPath.resolve(Configure.path.datePath) + val qwilightDate = + jm.readValue(Files.readString(qwilightDateFilePath), QwilightDate::class.java) + qwilightDate.date = date + qwilightDate.hashAMD64 = hashAMD64 + qwilightDate.hashARM64 = hashARM64 + qwilightDate.hashX64 = hashAMD64 + Files.newBufferedWriter(qwilightDateFilePath).use { + jm.writerWithDefaultPrettyPrinter().writeValue(it, qwilightDate) + } + send204(ctx) + } + } + + "/drawing" -> { + AvatarHandler.sendInvalidateAvatarDrawing(msg.content().toString(StandardCharsets.UTF_8)) + send204(ctx) + } + + "/totem" -> { + AvatarHandler.handleNotLogIn(msg.content().toString(StandardCharsets.UTF_8)) + send204(ctx) + } + + else -> ctx.writeAndFlush( + DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.NOT_FOUND + ) + ).addListener( + ChannelFutureListener.CLOSE + ) + } + + else -> ctx.writeAndFlush( + DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.METHOD_NOT_ALLOWED + ) + ).addListener( + ChannelFutureListener.CLOSE + ) + } + } + + override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { + logFault(cause) + } + + override fun logInfo(toNotify: String) { + LoggerFactory.getLogger(javaClass).info("[{}] {}", avatarIP, toNotify) + } + + override fun logFault(e: Throwable) { + if (Utility.isValidFault(e)) { + LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFaultText(e)) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/etc/EtcBoot.kt b/src/main/kotlin/net/taehui/twilight/etc/EtcBoot.kt new file mode 100644 index 0000000..c859240 --- /dev/null +++ b/src/main/kotlin/net/taehui/twilight/etc/EtcBoot.kt @@ -0,0 +1,38 @@ +package net.taehui.twilight.etc + +import io.netty.bootstrap.ServerBootstrap +import io.netty.channel.Channel +import io.netty.channel.ChannelInitializer +import io.netty.channel.EventLoopGroup +import io.netty.channel.socket.SocketChannel +import io.netty.channel.socket.nio.NioServerSocketChannel +import io.netty.handler.codec.http.HttpClientCodec +import io.netty.handler.codec.http.HttpObjectAggregator +import io.netty.handler.codec.http.HttpServerCodec +import net.taehui.twilight.Logger + +class EtcBoot(eventLoopGroup: EventLoopGroup) : Logger, AutoCloseable { + private val mainBootstrap: ServerBootstrap = ServerBootstrap().group(eventLoopGroup).channel(NioServerSocketChannel::class.java) + .childHandler(object : ChannelInitializer() { + public override fun initChannel(ch: SocketChannel) { + ch.pipeline() + .addLast(HttpServerCodec()) + .addLast(HttpObjectAggregator(Int.MAX_VALUE)) + .addLast(HttpClientCodec()) + .addLast(EtcAvatar()) + } + }) + private val mainChannel: Channel + + init { + logInfo("Loading Etc") + mainChannel = mainBootstrap.bind(8300).channel().closeFuture() + .addListener { + logInfo("Closed Etc") + }.channel() + } + + override fun close() { + mainChannel.close() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt b/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt index e063841..c968022 100644 --- a/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt @@ -52,9 +52,9 @@ override var avatarCompetence = 1 override var situationValue = QwilightAvatar.NOTE_FILE_MODE override var situationText = "" - private val fragments = mutableListOf() override val isEnterQuitAware = false override val avatarNameTitle = "🌐 " + private val fragments = mutableListOf() override fun send(eventID: EventOuterClass.Event.EventID, text: Any?, vararg data: ByteString?): ChannelFuture { return handler.writeAndFlush( diff --git a/src/main/kotlin/net/taehui/twilight/system/AwilightHandler.kt b/src/main/kotlin/net/taehui/twilight/system/AwilightHandler.kt index 5fab30c..4927483 100644 --- a/src/main/kotlin/net/taehui/twilight/system/AwilightHandler.kt +++ b/src/main/kotlin/net/taehui/twilight/system/AwilightHandler.kt @@ -50,7 +50,7 @@ val text = object { val qwilightName = avatar.qwilightName val hash = Configure.hash.random() - val date = "" + val date = "2.0.0" val language = "ko-KR" } if (it != null) { diff --git a/src/main/kotlin/net/taehui/twilight/system/PlatformIDSystem.kt b/src/main/kotlin/net/taehui/twilight/system/PlatformIDSystem.kt index af4e837..55266c3 100644 --- a/src/main/kotlin/net/taehui/twilight/system/PlatformIDSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/PlatformIDSystem.kt @@ -47,8 +47,4 @@ fun getPlatformID(avatarID: String): String? { return avatarIDPlatformIDMap[avatarID] } - - fun hasPlatformID(platformID: String): Boolean { - return platformIDAvatarIDMap.containsKey(platformID) - } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt index 7c11862..17cd398 100644 --- a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt @@ -128,7 +128,7 @@ } fun onLogin(replyEvent: IReplyCallback, modalEvent: IModalCallback) { - if (PlatformIDSystem.hasPlatformID(replyEvent.user.id)) { + if (PlatformIDSystem.getAvatarID(replyEvent.user.id) != null) { replyEvent.reply("You are already logged in").setEphemeral(true).queue() } else { modalEvent.replyModal( diff --git a/src/main/kotlin/net/taehui/twilight/trust/TrustAvatar.kt b/src/main/kotlin/net/taehui/twilight/trust/TrustAvatar.kt deleted file mode 100644 index 805e61b..0000000 --- a/src/main/kotlin/net/taehui/twilight/trust/TrustAvatar.kt +++ /dev/null @@ -1,150 +0,0 @@ -package net.taehui.twilight.trust - -import com.fasterxml.jackson.databind.ObjectMapper -import io.netty.buffer.ByteBufUtil -import io.netty.channel.ChannelFutureListener -import io.netty.channel.ChannelHandlerContext -import io.netty.channel.SimpleChannelInboundHandler -import io.netty.handler.codec.http.* -import net.taehui.twilight.Logger -import net.taehui.twilight.Utility -import net.taehui.twilight.system.AvatarHandler -import net.taehui.twilight.system.Configure -import org.slf4j.LoggerFactory -import java.net.InetSocketAddress -import java.net.URLDecoder -import java.nio.charset.StandardCharsets -import java.nio.file.Files -import java.util.concurrent.CompletableFuture - -class TrustAvatar : SimpleChannelInboundHandler(), Logger { - class QwilightDate { - var date = "" - var hashAMD64 = "" - var hashARM64 = "" - var titleAMD64 = "" - var titleARM64 = "" - @Deprecated("hashX64") - var hashX64 = "" - @Deprecated("titleX64") - var titleX64 = "" - } - - private var avatarIP = "" - - private fun send204(handler: ChannelHandlerContext) { - handler.writeAndFlush(DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT)) - .addListener(ChannelFutureListener.CLOSE) - } - - override fun channelActive(ctx: ChannelHandlerContext) { - avatarIP = (ctx.channel().remoteAddress() as InetSocketAddress).address.hostAddress - } - - public override fun channelRead0(ctx: ChannelHandlerContext, msg: FullHttpRequest) { - fun getQwilightDate(): QwilightDate { - val jm = ObjectMapper() - val qwilightDateFilePath = Configure.path.wwwPath.resolve(Configure.path.datePath) - return jm.readValue(Files.readString(qwilightDateFilePath), QwilightDate::class.java) - } - - val path = URLDecoder.decode(msg.uri(), StandardCharsets.UTF_8) - val mode = msg.method() - logInfo("$mode $path") - when (mode) { - HttpMethod.GET -> when (path) { - "/health" -> { - send204(ctx) - } - } - - HttpMethod.PATCH -> when (path) { - "/date/AMD64" -> { - val data = ByteBufUtil.getBytes(msg.content()) - logFuture { - Files.write(Configure.path.wwwPath.resolve(getQwilightDate().titleAMD64), data) - send204(ctx) - } - } - - "/date/ARM64" -> { - val data = ByteBufUtil.getBytes(msg.content()) - logFuture { - Files.write(Configure.path.wwwPath.resolve(getQwilightDate().titleARM64), data) - send204(ctx) - } - } - - "/date" -> { - val data = msg.content().toString(StandardCharsets.UTF_8).split(" ".toRegex()) - logFuture { - var date = data[0] - val hashAMD64 = data[1] - val hashARM64 = data[2] - if (date.contains("!")) { - Configure.hash.clear() - date = date.replace("!", "") - } - Configure.hash.add(hashAMD64) - Configure.hash.add(hashARM64) - Configure.saveConfigure() - val jm = ObjectMapper() - val qwilightDateFilePath = Configure.path.wwwPath.resolve(Configure.path.datePath) - val qwilightDate = - jm.readValue(Files.readString(qwilightDateFilePath), QwilightDate::class.java) - qwilightDate.date = date - qwilightDate.hashAMD64 = hashAMD64 - qwilightDate.hashARM64 = hashARM64 - qwilightDate.hashX64 = hashAMD64 - Files.newBufferedWriter(qwilightDateFilePath).use { - jm.writerWithDefaultPrettyPrinter().writeValue(it, qwilightDate) - } - send204(ctx) - } - } - - "/drawing" -> { - AvatarHandler.sendInvalidateAvatarDrawing(msg.content().toString(StandardCharsets.UTF_8)) - send204(ctx) - } - - "/totem" -> { - AvatarHandler.handleNotLogIn(msg.content().toString(StandardCharsets.UTF_8)) - send204(ctx) - } - - else -> ctx.writeAndFlush( - DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.NOT_FOUND - ) - ).addListener( - ChannelFutureListener.CLOSE - ) - } - - else -> ctx.writeAndFlush( - DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.METHOD_NOT_ALLOWED - ) - ).addListener( - ChannelFutureListener.CLOSE - ) - } - } - - override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { - logFault(cause) - } - - override fun logInfo(toNotify: String) { - LoggerFactory.getLogger(javaClass).info("[{}] {}", avatarIP, toNotify) - } - - override fun logFault(e: Throwable) { - if (Utility.isValidFault(e)) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFaultText(e)) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/trust/TrustBoot.kt b/src/main/kotlin/net/taehui/twilight/trust/TrustBoot.kt deleted file mode 100644 index b6a608b..0000000 --- a/src/main/kotlin/net/taehui/twilight/trust/TrustBoot.kt +++ /dev/null @@ -1,38 +0,0 @@ -package net.taehui.twilight.trust - -import io.netty.bootstrap.ServerBootstrap -import io.netty.channel.Channel -import io.netty.channel.ChannelInitializer -import io.netty.channel.EventLoopGroup -import io.netty.channel.socket.SocketChannel -import io.netty.channel.socket.nio.NioServerSocketChannel -import io.netty.handler.codec.http.HttpClientCodec -import io.netty.handler.codec.http.HttpObjectAggregator -import io.netty.handler.codec.http.HttpServerCodec -import net.taehui.twilight.Logger - -class TrustBoot(eventLoopGroup: EventLoopGroup) : Logger, AutoCloseable { - private val mainBootstrap: ServerBootstrap = ServerBootstrap().group(eventLoopGroup).channel(NioServerSocketChannel::class.java) - .childHandler(object : ChannelInitializer() { - public override fun initChannel(ch: SocketChannel) { - ch.pipeline() - .addLast(HttpServerCodec()) - .addLast(HttpObjectAggregator(Int.MAX_VALUE)) - .addLast(HttpClientCodec()) - .addLast(TrustAvatar()) - } - }) - private val mainChannel: Channel - - init { - logInfo("Loading Trust") - mainChannel = mainBootstrap.bind(8300).channel().closeFuture() - .addListener { - logInfo("Closed Trust") - }.channel() - } - - override fun close() { - mainChannel.close() - } -} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt b/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt index c5f4657..4053a5d 100644 --- a/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt @@ -569,15 +569,11 @@ sendAvatarDrawing(avatarID) } } else if (avatarID.startsWith('$')) { - if (PlatformIDSystem.hasPlatformID(avatarID.substring(avatarID.indexOf('$')))) { - sendAvatarDrawing(avatarID) + val avatarDrawing = PlatformSystem.getDrawing(avatarID) + if (avatarDrawing != null) { + send(ctx, avatarDrawing) } else { - val avatarDrawing = PlatformSystem.getDrawing(avatarID) - if (avatarDrawing != null) { - send(ctx, avatarDrawing) - } else { - sendAvatarDrawing(avatarID) - } + sendAvatarDrawing(avatarID) } } else { sendAvatarDrawing(avatarID) diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 8ed6059..a5a3476 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -48,7 +48,7 @@ - +