diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index e805548..ae3f30a 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 8194073..4cbb3ab 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.9.20" + kotlin("jvm") version "1.9.21" application id("io.ktor.plugin") version "2.3.6" } @@ -33,10 +33,10 @@ implementation("net.dv8tion:JDA:5.0.0-beta.16") implementation("org.apache.commons:commons-compress:1.25.0") implementation("org.apache.commons:commons-dbcp2:2.11.0") - implementation("org.apache.commons:commons-lang3:3.13.0") - implementation("org.apache.httpcomponents.client5:httpclient5:5.2.1") - implementation("org.apache.logging.log4j:log4j-core:2.21.1") - implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.21.1") + implementation("org.apache.commons:commons-lang3:3.14.0") + implementation("org.apache.httpcomponents.client5:httpclient5:5.2.2") + implementation("org.apache.logging.log4j:log4j-core:2.22.0") + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.22.0") implementation("org.jline:jline:3.24.1") implementation("org.jline:jline-terminal-jansi:3.24.1") implementation("org.jsoup:jsoup:1.16.2") diff --git a/src/main/kotlin/net/taehui/twilight/BMSCompiler.kt b/src/main/kotlin/net/taehui/twilight/BMSCompiler.kt index ff711ab..d19ea88 100644 --- a/src/main/kotlin/net/taehui/twilight/BMSCompiler.kt +++ b/src/main/kotlin/net/taehui/twilight/BMSCompiler.kt @@ -9,7 +9,7 @@ import kotlin.math.abs import kotlin.math.floor -class BMSCompiler(noteFileContents: ByteArray, format: String) : BaseCompiler(noteFileContents, format) { +class BMSCompiler(noteFileData: ByteArray, format: String) : BaseCompiler(noteFileData, format) { private open class BMSInputItem(val inputNote: InputNote, val bmsPosition: Double) : Comparable { override fun compareTo(other: BMSInputItem): Int { return inputNote.compareTo(other.inputNote) @@ -43,7 +43,7 @@ val meterMeterMultiplierMap = LinkedHashMap() meterMeterMultiplierMap[-1] = 1.0 val bmsIDBPMMap = mutableMapOf() - BufferedReader(InputStreamReader(ByteArrayInputStream(noteFileContents), format)).use { + BufferedReader(InputStreamReader(ByteArrayInputStream(noteFileData), format)).use { val saltComputer = Random() var lastBin = 0 var isValidStatement = true @@ -174,7 +174,8 @@ if (rawInput[1] == '6') { targetComputing.autoableNotes += 1 } - positionStandNoteCountMap[bmsPosition] = positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 + positionStandNoteCountMap[bmsPosition] = + positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 highestPosition = highestPosition.coerceAtLeast(bmsPosition) } else { earlyBMSLongInputItemSet.getOrPut(rawInput) { @@ -293,10 +294,12 @@ } var bmsPosition = lastEarlyBMSLongInputItem.bmsPosition highestPosition = highestPosition.coerceAtLeast(bmsPosition) - positionStandNoteCountMap[bmsPosition] = positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 + positionStandNoteCountMap[bmsPosition] = + positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 bmsPosition = earlyBMSLongInputItem.bmsPosition highestPosition = highestPosition.coerceAtLeast(bmsPosition) - positionStandNoteCountMap[bmsPosition] = positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 + positionStandNoteCountMap[bmsPosition] = + positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 lastEarlyBMSLongInputItem = null continue } @@ -308,7 +311,8 @@ } val bmsPosition = lastEarlyBMSLongInputItem.bmsPosition highestPosition = highestPosition.coerceAtLeast(bmsPosition) - positionStandNoteCountMap[bmsPosition] = positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 + positionStandNoteCountMap[bmsPosition] = + positionStandNoteCountMap.getOrDefault(bmsPosition, 0) + 1 } } lastEarlyBMSLongInputItem = earlyBMSLongInputItem @@ -422,20 +426,7 @@ } } } - targetComputing.inputMode = getInputMode(inputSet) - if (targetComputing.inputMode == Component.InputMode.INPUT_MODE_10_2 && (targetComputing.title.contains( - "9B", - true - ) || targetComputing.title.contains( - "9K", - true - ) || targetComputing.title.contains( - "PMS", - true - )) - ) { - targetComputing.inputMode = Component.InputMode.INPUT_MODE_9 - } + targetComputing.inputMode = getInputMode(inputSet, Utility.getDataID(targetComputing.noteID)) for (i in 0..highestMeter + 1) { bmsPositionSet.add(i.toDouble()) } @@ -654,7 +645,10 @@ } } - private fun getInputMode(inputSet: Collection): Component.InputMode { + private fun getInputMode(inputSet: Collection, dataID: Int): Component.InputMode { + if (dataID == 1) { + return Component.InputMode.INPUT_MODE_9 + } if (is4K) { return Component.InputMode.INPUT_MODE_4 } diff --git a/src/main/kotlin/net/taehui/twilight/BMSONCompiler.kt b/src/main/kotlin/net/taehui/twilight/BMSONCompiler.kt index 7bec5c1..2d68576 100644 --- a/src/main/kotlin/net/taehui/twilight/BMSONCompiler.kt +++ b/src/main/kotlin/net/taehui/twilight/BMSONCompiler.kt @@ -11,14 +11,14 @@ import java.util.* import kotlin.math.abs -class BMSONCompiler(noteFileContents: ByteArray, format: String) : BaseCompiler(noteFileContents, format) { +class BMSONCompiler(noteFileData: ByteArray, format: String) : BaseCompiler(noteFileData, format) { private val bmsonPositionLogicalYMap = TreeMap() private val bmsonPositionBPMMap = TreeMap() private lateinit var text: JSON.Bmson private var res = 0L override fun handleCompile(targetComputing: Computing) { - text = ObjectMapper().readValue(String(noteFileContents, Charset.forName(format)), JSON.Bmson::class.java) + text = ObjectMapper().readValue(String(noteFileData, Charset.forName(format)), JSON.Bmson::class.java) val title = text.info.title val titleAssister0 = text.info.subtitle val titleAssister1 = text.info.chart_name diff --git a/src/main/kotlin/net/taehui/twilight/BaseCompiler.kt b/src/main/kotlin/net/taehui/twilight/BaseCompiler.kt index 7123268..3469e37 100644 --- a/src/main/kotlin/net/taehui/twilight/BaseCompiler.kt +++ b/src/main/kotlin/net/taehui/twilight/BaseCompiler.kt @@ -10,7 +10,7 @@ import kotlin.math.max -abstract class BaseCompiler(val noteFileContents: ByteArray, val format: String) : Logger { +abstract class BaseCompiler(val noteFileData: ByteArray, val format: String) : Logger { val notes = mutableListOf() val waitBPMMap = TreeMap() val waitStopMap = TreeMap() @@ -144,38 +144,52 @@ abstract fun handleCompile(defaultComputer: DefaultCompute) companion object { - fun handleCompile(noteFileContents: ByteArray): Computing { - val targetComputing = Computing() - ByteArrayInputStream(noteFileContents).use { + fun handleCompile(noteFileData: ByteArray, dataID: Int): Array { + val noteID512 = Utility.getID512(noteFileData) + val targetComputings = mutableListOf() + ByteArrayInputStream(noteFileData).use { val formatComputer = CharsetDetector() formatComputer.setText(it) val formats = formatComputer.detectAll() val format = if (formats[0].confidence >= 87.5) formats[0].name else Configure.db.format var targetCompiler: BaseCompiler try { - targetCompiler = BMSONCompiler(noteFileContents, format) + val targetComputing = Computing("$noteID512:0") + targetCompiler = BMSONCompiler(noteFileData, format) targetCompiler.handleCompile(targetComputing) + targetCompiler.onCompiled(targetComputing) + targetComputings.add(targetComputing) } catch (e: JacksonException) { - targetCompiler = BMSCompiler(noteFileContents, format) - targetCompiler.handleCompile(targetComputing) + fun handleBMSCompile(dataID: Int): Computing { + val targetComputing = Computing("$noteID512:$dataID") + targetCompiler = BMSCompiler(noteFileData, format) + targetCompiler.handleCompile(targetComputing) + targetCompiler.onCompiled(targetComputing) + targetComputings.add(targetComputing) + return targetComputing + } + + if (handleBMSCompile(if (dataID == -1) 0 else dataID).inputMode == Component.InputMode.INPUT_MODE_10_2 && dataID == -1) { + handleBMSCompile(1) + } } - targetCompiler.onCompiled(targetComputing) + Unit } - return targetComputing + return targetComputings.toTypedArray() } - fun handleCompile(defaultComputer: DefaultCompute, noteFileContents: ByteArray) { - ByteArrayInputStream(noteFileContents).use { + fun handleCompile(defaultComputer: DefaultCompute, noteFileData: ByteArray) { + ByteArrayInputStream(noteFileData).use { val formatComputer = CharsetDetector() formatComputer.setText(it) val formats = formatComputer.detectAll() val format = if (formats[0].confidence > 50) formats[0].name else Configure.db.format var targetCompiler: BaseCompiler try { - targetCompiler = BMSONCompiler(noteFileContents, format) + targetCompiler = BMSONCompiler(noteFileData, format) targetCompiler.handleCompile(defaultComputer) } catch (e: Throwable) { - targetCompiler = BMSCompiler(noteFileContents, format) + targetCompiler = BMSCompiler(noteFileData, format) targetCompiler.handleCompile(defaultComputer) } targetCompiler.onCompiled(defaultComputer as Computing) diff --git a/src/main/kotlin/net/taehui/twilight/Computing.kt b/src/main/kotlin/net/taehui/twilight/Computing.kt index 87bf08b..35026a4 100644 --- a/src/main/kotlin/net/taehui/twilight/Computing.kt +++ b/src/main/kotlin/net/taehui/twilight/Computing.kt @@ -1,7 +1,6 @@ package net.taehui.twilight -open class Computing { - var noteID = "" +open class Computing(val noteID: String) { var noteVariety = Component.NoteVariety.BMS var title = "" var artist = "" diff --git a/src/main/kotlin/net/taehui/twilight/JSON.kt b/src/main/kotlin/net/taehui/twilight/JSON.kt index ecfc58a..54d10b6 100644 --- a/src/main/kotlin/net/taehui/twilight/JSON.kt +++ b/src/main/kotlin/net/taehui/twilight/JSON.kt @@ -227,7 +227,7 @@ var isNetSite = false var data: Any? = null var noteID = "" - var noteIDs: Array? = null + var noteIDs: Array = emptyArray() var title = "" var artist = "" var genre = "" diff --git a/src/main/kotlin/net/taehui/twilight/Logger.kt b/src/main/kotlin/net/taehui/twilight/Logger.kt index 4e93f66..cde3524 100644 --- a/src/main/kotlin/net/taehui/twilight/Logger.kt +++ b/src/main/kotlin/net/taehui/twilight/Logger.kt @@ -11,7 +11,7 @@ } fun logFault(e: Throwable) { - LoggerFactory.getLogger(javaClass).error(Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error(Utility.getFaultText(e)) } fun logValueFuture(onHandle: () -> T): CompletableFuture { diff --git a/src/main/kotlin/net/taehui/twilight/QwilightLogging.kt b/src/main/kotlin/net/taehui/twilight/QwilightLogging.kt index b5ddba3..ac202d7 100644 --- a/src/main/kotlin/net/taehui/twilight/QwilightLogging.kt +++ b/src/main/kotlin/net/taehui/twilight/QwilightLogging.kt @@ -30,6 +30,6 @@ } override fun logFault(e: Throwable) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFaultText(e)) } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/Site.kt b/src/main/kotlin/net/taehui/twilight/Site.kt index 70fd3ed..67ba3c6 100644 --- a/src/main/kotlin/net/taehui/twilight/Site.kt +++ b/src/main/kotlin/net/taehui/twilight/Site.kt @@ -15,6 +15,7 @@ import java.util.concurrent.* import java.util.stream.Collectors import java.util.stream.Stream +import kotlin.random.Random class Site : Logger { enum class AvatarConfigure(val value: Int) { @@ -62,7 +63,7 @@ } private val siteYells = LinkedList() private val platformSiteYells = mutableMapOf>() - private val targetComputing = Computing() + private val targetComputing = Computing("") private val isCallable: Boolean private val isGetNotify: Boolean private val isEnterQuitAware: Boolean @@ -838,7 +839,7 @@ this.siteHand = siteHand doCallSiteAvatar(true) if (siteHandQueue.remove(siteHand)) { - siteHandQueue.offerLast(siteHand) + siteHandQueue.offer(siteHand) } } } @@ -850,7 +851,7 @@ avatarConfigures.replace(it.avatarID, AvatarConfigure.LEVYING, AvatarConfigure.DEFAULT) siteHand = it doCallSiteAvatar(true) - siteHandQueue.offerLast(it) + siteHandQueue.offer(it) } } } @@ -1347,10 +1348,10 @@ } } - fun setNoteFileContents(avatar: Avatar, noteFileContents: JSON.QwilightSetNoteFile) { + fun setNoteFileContents(avatar: Avatar, noteFileData: JSON.QwilightSetNoteFile) { synchronized(avatarsCSX) { if (siteMode == SiteMode.NET && siteHand == avatar && siteSituation == SiteSituation.DEFAULT) { - if (Arrays.compare(noteFileContents.noteIDs, noteIDs) != 0) { + if (Arrays.compare(noteFileData.noteIDs, noteIDs) != 0) { synchronized(avatarsCSX) { avatars.forEach { avatarConfigures[it.avatarID] = AvatarConfigure.DEFAULT @@ -1358,34 +1359,34 @@ } doCallSiteAvatar(false) } - setNoteFileContents(noteFileContents) + setNoteFileContents(noteFileData) } } } - fun setNoteFileContents(noteFileContents: JSON.QwilightSetNoteFile) { - noteID = noteFileContents.noteID - noteIDs = noteFileContents.noteIDs - bundleEntryPath = noteFileContents.bundleEntryPath - targetComputing.title = noteFileContents.title - targetComputing.artist = noteFileContents.artist - targetComputing.genre = noteFileContents.genre - targetComputing.levelText = noteFileContents.levelText - targetComputing.level = noteFileContents.level - targetComputing.wantLevelID = noteFileContents.wantLevelID - targetComputing.bpm = noteFileContents.bpm - targetComputing.lowestBPM = noteFileContents.lowestBPM - targetComputing.highestBPM = noteFileContents.highestBPM - targetComputing.judgmentStage = noteFileContents.judgmentStage - targetComputing.hitPointsValue = noteFileContents.hitPointsValue - targetComputing.totalNotes = noteFileContents.totalNotes - targetComputing.longNotes = noteFileContents.longNotes - targetComputing.autoableNotes = noteFileContents.autoableNotes - targetComputing.trapNotes = noteFileContents.trapNotes - targetComputing.highestInputCount = noteFileContents.highestInputCount - targetComputing.length = noteFileContents.length - targetComputing.isAutoLongNote = noteFileContents.isAutoLongNote - targetComputing.inputMode = noteFileContents.inputMode + fun setNoteFileContents(noteFileData: JSON.QwilightSetNoteFile) { + noteID = noteFileData.noteID + noteIDs = noteFileData.noteIDs + bundleEntryPath = noteFileData.bundleEntryPath + targetComputing.title = noteFileData.title + targetComputing.artist = noteFileData.artist + targetComputing.genre = noteFileData.genre + targetComputing.levelText = noteFileData.levelText + targetComputing.level = noteFileData.level + targetComputing.wantLevelID = noteFileData.wantLevelID + targetComputing.bpm = noteFileData.bpm + targetComputing.lowestBPM = noteFileData.lowestBPM + targetComputing.highestBPM = noteFileData.highestBPM + targetComputing.judgmentStage = noteFileData.judgmentStage + targetComputing.hitPointsValue = noteFileData.hitPointsValue + targetComputing.totalNotes = noteFileData.totalNotes + targetComputing.longNotes = noteFileData.longNotes + targetComputing.autoableNotes = noteFileData.autoableNotes + targetComputing.trapNotes = noteFileData.trapNotes + targetComputing.highestInputCount = noteFileData.highestInputCount + targetComputing.length = noteFileData.length + targetComputing.isAutoLongNote = noteFileData.isAutoLongNote + targetComputing.inputMode = noteFileData.inputMode doCallSiteNet() } @@ -1415,7 +1416,7 @@ fun audioInput(avatar: Avatar, data: ByteString) { synchronized(avatarsCSX) { - if (siteMode != SiteMode.DEFAULT && (avatar == null || isAvatarJoined(avatar))) { + if (siteMode != SiteMode.DEFAULT && isAvatarJoined(avatar)) { val avatarID = avatar.avatarID val event = EventOuterClass.Event.newBuilder().apply { eventID = EventOuterClass.Event.EventID.AUDIO_INPUT @@ -1455,7 +1456,7 @@ handlerID = this@Site.handlerID avatarName = avatar.avatarName postedItem = qwilightPostItem.postedItem - wait = Utility.getSaltedItem(qwilightPostItem.lowestWait, qwilightPostItem.highestWait) + wait = Random.nextDouble(qwilightPostItem.lowestWait, qwilightPostItem.highestWait) }.build() }.build()) } @@ -1476,7 +1477,7 @@ } override fun logFault(e: Throwable) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", siteName, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", siteName, Utility.getFaultText(e)) } companion object { diff --git a/src/main/kotlin/net/taehui/twilight/Twilight.kt b/src/main/kotlin/net/taehui/twilight/Twilight.kt index 36911af..69c2ebc 100644 --- a/src/main/kotlin/net/taehui/twilight/Twilight.kt +++ b/src/main/kotlin/net/taehui/twilight/Twilight.kt @@ -56,7 +56,7 @@ AbilityClassSystem.loadAbilityClasses() AbilitySystem.loadAbility() BannedIP.loadBannedIP() - BannedNote.loadBannedNote() + BannedNoteFile.loadBannedNoteFile() EdgeSystem.loadEdge() AvatarIPSystem.loadAvatarIP() LevelSystem.loadLevel() @@ -96,7 +96,7 @@ AutoSystem.dispose() AvatarIPSystem.saveAvatarIP() BannedIP.saveBannedIP() - BannedNote.saveBannedNote() + BannedNoteFile.saveBannedNoteFile() Configure.saveConfigure() eventLoopGroup.shutdownGracefully() } diff --git a/src/main/kotlin/net/taehui/twilight/Utility.kt b/src/main/kotlin/net/taehui/twilight/Utility.kt index ddd9995..50c1f74 100644 --- a/src/main/kotlin/net/taehui/twilight/Utility.kt +++ b/src/main/kotlin/net/taehui/twilight/Utility.kt @@ -3,9 +3,11 @@ import io.netty.handler.codec.DecoderException import io.netty.handler.ssl.NotSslRecordException import net.taehui.twilight.system.PlatformIDSystem +import org.apache.commons.codec.binary.Hex import java.net.MalformedURLException import java.net.SocketException import java.net.URI +import java.security.MessageDigest import java.util.* object Utility { @@ -39,7 +41,7 @@ return PlatformIDSystem.getAvatarID(avatarID.substring(avatarID.indexOf("@") + 1)) } - fun getFault(e: Throwable): String { + fun getFaultText(e: Throwable): String { return StringBuilder(e.localizedMessage ?: "").apply { e.stackTrace.forEach { append(System.lineSeparator()) @@ -48,14 +50,6 @@ }.toString() } - fun getSaltedItem(toSaltItems: List, defaultValue: T): T { - return if (toSaltItems.isEmpty()) defaultValue else toSaltItems[(Math.random() * toSaltItems.size).toInt()] - } - - fun getSaltedItem(lowestWait: Double, highestWait: Double): Double { - return lowestWait + Math.random() * (highestWait - lowestWait) - } - fun getQuitStatusValue(point: Double, stand: Int): Int { if (point < 0.8) { return 6 @@ -83,4 +77,30 @@ fun isValidFault(e: Throwable): Boolean { return !(e is SocketException && e.localizedMessage?.contains("Connection reset") == true) && !(e is DecoderException && e.cause is NotSslRecordException) } + + fun getID512(noteFileData: ByteArray): String { + val hashComputer = MessageDigest.getInstance("SHA-512") + hashComputer.update(noteFileData) + return Hex.encodeHexString(hashComputer.digest()) + } + + fun getID256(noteFileData: ByteArray): String { + val hashComputer = MessageDigest.getInstance("SHA-256") + hashComputer.update(noteFileData) + return Hex.encodeHexString(hashComputer.digest()) + } + + fun getID128(noteFileData: ByteArray): String { + val hashComputer = MessageDigest.getInstance("MD5") + hashComputer.update(noteFileData) + return Hex.encodeHexString(hashComputer.digest()) + } + + fun getNoteID512(noteID: String): String { + return noteID.split(':')[0] + } + + fun getDataID(noteID: String): Int { + return noteID.split(':')[1].toInt() + } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/awilight/AwilightAvatar.kt b/src/main/kotlin/net/taehui/twilight/awilight/AwilightAvatar.kt index 03ccd6c..e3bc0f2 100644 --- a/src/main/kotlin/net/taehui/twilight/awilight/AwilightAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/awilight/AwilightAvatar.kt @@ -124,7 +124,7 @@ enteredSites[siteID]?.let { if (it.isSiteHand) { NoteFilesSystem.noteFile?.let { (noteID, noteFilePath) -> - val targetComputing = BaseCompiler.handleCompile(Files.readAllBytes(noteFilePath)) + val targetComputing = BaseCompiler.handleCompile(Files.readAllBytes(noteFilePath), -1).random() send( EventOuterClass.Event.EventID.SET_NOTE_FILE, object { @@ -169,7 +169,7 @@ } override fun logFault(e: Throwable) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", this.qwilightName, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", this.qwilightName, Utility.getFaultText(e)) } override fun channelActive(ctx: ChannelHandlerContext) { @@ -237,18 +237,15 @@ send( EventOuterClass.Event.EventID.ENTER_SITE, object { - val siteID = Utility.getSaltedItem(siteIDs, null) + val siteID = siteIDs.random() val siteCipher = "" } ) } else { - NoteFilesSystem.noteFile?.let { (noteID, noteFilePath) -> - val targetComputing = BaseCompiler.handleCompile( - Files.readAllBytes( - noteFilePath - ) - ) - targetComputing.noteID = noteID + NoteFilesSystem.noteFile?.let { noteFile -> + val targetComputing = + BaseCompiler.handleCompile(Files.readAllBytes(noteFile.value), -1) + .random() val modeComponentValue = ModeComponent() send( EventOuterClass.Event.EventID.NEW_SITE, @@ -351,18 +348,16 @@ enteredSites[text.siteID]?.let { synchronized(defaultComputerCSX) { defaultComputer?.stop() - defaultComputer = DefaultCompute(this, text.handlerID, it).also { tmpComputer -> - tmpComputer.noteID = - if (NoteFilesSystem.hasNoteFile(it.noteID)) { - it.noteID - } else { - Arrays.stream(text.noteIDs) - .filter { - NoteFilesSystem.hasNoteFile( - it - ) - }.findAny().orElse(null) - } + defaultComputer = DefaultCompute( + if (NoteFilesSystem.hasNoteFile(it.noteID)) { + it.noteID + } else { + Arrays.stream(text.noteIDs) + .filter { + NoteFilesSystem.hasNoteFile(it) + }.findAny().orElse("") + }, this, text.handlerID, it + ).also { tmpComputer -> Thread { var isOK = false try { diff --git a/src/main/kotlin/net/taehui/twilight/awilight/DefaultCompute.kt b/src/main/kotlin/net/taehui/twilight/awilight/DefaultCompute.kt index 642d123..5689948 100644 --- a/src/main/kotlin/net/taehui/twilight/awilight/DefaultCompute.kt +++ b/src/main/kotlin/net/taehui/twilight/awilight/DefaultCompute.kt @@ -16,7 +16,7 @@ import java.util.concurrent.ConcurrentLinkedQueue import kotlin.math.abs -class DefaultCompute(val avatar: AwilightAvatar, val handlerID: String, val site: AwilightSite) : Computing() { +class DefaultCompute(noteID: String, val avatar: AwilightAvatar, val handlerID: String, val site: AwilightSite) : Computing(noteID) { val ioAvatarIDs = mutableListOf() val pendingIOAvatarIDs = mutableListOf() private val sentIOAvatarIDs = mutableListOf() @@ -30,7 +30,7 @@ val waitBPMMap = TreeMap() val netDrawings = mutableListOf() private val r = Random() - private lateinit var noteFileContents: ByteArray + private lateinit var noteFileData: ByteArray var setStop = false var targetStand = 0 var isF = false @@ -112,8 +112,8 @@ } fun handleCompile(noteFilePath: Path) { - noteFileContents = Files.readAllBytes(noteFilePath) - BaseCompiler.handleCompile(this, noteFileContents) + noteFileData = Files.readAllBytes(noteFilePath) + BaseCompiler.handleCompile(this, noteFileData) avatar.send(EventOuterClass.Event.EventID.COMPILED, object { val siteID = site.siteID val handlerID = this@DefaultCompute.handlerID diff --git a/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt b/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt index 7ac660f..64f0246 100644 --- a/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt @@ -10,7 +10,6 @@ import net.taehui.twilight.BundleIO.BundleVariety.Companion.getBundleVariety import net.taehui.twilight.Component import net.taehui.twilight.system.* -import org.apache.commons.codec.binary.Hex import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream import org.apache.commons.io.FilenameUtils import org.apache.commons.io.IOUtils @@ -23,7 +22,6 @@ import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardOpenOption -import java.security.MessageDigest import java.time.LocalDateTime import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -797,27 +795,18 @@ val inputFlags = text.inputFlags val commentFileContents = eventData[1] if (longNoteMode != INPUT_LONG_NOTE_MODE && judgmentMode != FAVOR_JUDGMENT_MODE && hitPointsMode != FAVOR_HIT_POINTS_MODE && hitPointsMode != TEST_HIT_POINTS_MODE && noteModifyMode != LONG_NOTE_NOTE_MODIFY_MODE) { - val noteFileContents = eventData[0].toByteArray() - val hashComputer512 = MessageDigest.getInstance("SHA-512") - hashComputer512.update(noteFileContents) - val hashComputer128 = MessageDigest.getInstance("MD5") - hashComputer128.update(noteFileContents) - val hashComputer256 = MessageDigest.getInstance("SHA-256") - hashComputer256.update(noteFileContents) - val noteID512 = Hex.encodeHexString(hashComputer512.digest()) - val noteID128 = Hex.encodeHexString(hashComputer128.digest()) - val noteID256 = Hex.encodeHexString(hashComputer256.digest()) - val targetComputing = BaseCompiler.handleCompile(noteFileContents) - if (!targetComputing.isBanned && !BannedNote.isBanned(noteID512)) { + val noteFileData = eventData[0].toByteArray() + val targetComputing = BaseCompiler.handleCompile(noteFileData, dataID).single() + val noteID512 = Utility.getID512(noteFileData) + if (!targetComputing.isBanned && !BannedNoteFile.isBanned(targetComputing.noteID)) { logFuture { - Files.write(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID512), noteFileContents) + Files.write(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID512), noteFileData) DB.setNote( - "$noteID512:$dataID", - noteID128, - noteID256, + targetComputing.noteID, + Utility.getID128(noteFileData), + Utility.getID256(noteFileData), targetComputing ) - hashComputer512.reset() val lastTitles = DB.getTitleItems(it) val inputMode = text.inputMode @@ -831,7 +820,7 @@ val comment = CommentOuterClass.Comment.parseFrom(commentFileContents) val commentFileData = commentFileContents.toByteArray() - val commentID = Hex.encodeHexString(hashComputer512.digest(commentFileData)) + val commentID = Utility.getID512(commentFileData) if (DB.saveComment( multiplier, autoMode, @@ -852,7 +841,7 @@ salt, commentID, it, - "$noteID512:$dataID", + targetComputing.noteID, isPaused, inputFlags ) @@ -922,7 +911,10 @@ } if (lastAvatarLevel < avatarLevel) { - send(EventOuterClass.Event.EventID.LEVEL_UP, null) + send(EventOuterClass.Event.EventID.LEVEL_UP, object { + val from = lastAvatarLevel + val to = avatarLevel + }) } } } @@ -931,31 +923,10 @@ EventOuterClass.Event.EventID.VALVE_COMMENT -> wantNotSignedIn { val text = jm.readValue(eventText, JSON.QwilightValveComment::class.java) - val noteFileContents = eventData[0].toByteArray() - val hashComputer512 = MessageDigest.getInstance("SHA-512") - hashComputer512.update(noteFileContents) - val hashComputer128 = MessageDigest.getInstance("MD5") - hashComputer128.update(noteFileContents) - val hashComputer256 = MessageDigest.getInstance("SHA-256") - hashComputer256.update(noteFileContents) - val noteID512 = Hex.encodeHexString(hashComputer512.digest()) - val noteID128 = Hex.encodeHexString(hashComputer128.digest()) - val noteID256 = Hex.encodeHexString(hashComputer256.digest()) - val targetComputing = BaseCompiler.handleCompile(noteFileContents) - if (!targetComputing.isBanned) { + val targetComputing = BaseCompiler.handleCompile(eventData[0].toByteArray(), text.dataID).single() + if (!targetComputing.isBanned && !BannedNoteFile.isBanned(targetComputing.noteID)) { logFuture { - Files.write(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID512), noteFileContents) - DB.setNote( - "$noteID512:${text.dataID}", - noteID128, - noteID256, - targetComputing - ) - if (SiteHandler.hasAvatar( - this, - SiteHandler.commentSiteID - ) - ) { + if (SiteHandler.hasAvatar(this, SiteHandler.commentSiteID)) { SiteHandler.putSiteYell( SiteHandler.commentSiteID, JSON.TwilightCommentSiteYell( @@ -1504,7 +1475,7 @@ override fun logFault(e: Throwable) { if (Utility.isValidFault(e)) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFaultText(e)) } } diff --git a/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt b/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt index da2f69a..ba5ac9d 100644 --- a/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/site/SiteAvatar.kt @@ -259,7 +259,7 @@ override fun logFault(e: Throwable) { if (Utility.isValidFault(e)) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", loggerID, Utility.getFaultText(e)) } } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/BannedNote.kt b/src/main/kotlin/net/taehui/twilight/system/BannedNote.kt deleted file mode 100644 index c75d0cc..0000000 --- a/src/main/kotlin/net/taehui/twilight/system/BannedNote.kt +++ /dev/null @@ -1,44 +0,0 @@ -package net.taehui.twilight.system - -import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.ObjectMapper -import net.taehui.twilight.Logger -import java.io.IOException -import java.nio.file.Paths -import java.util.concurrent.ConcurrentHashMap - -object BannedNote : Logger { - private var bannedNoteStore = mutableMapOf() - - fun loadBannedNote() { - try { - bannedNoteStore.putAll( - ObjectMapper().readValue( - Paths.get("Banned Note.json").toFile(), - object : TypeReference>() {}) - ) - logInfo("Loaded Banned Note") - saveBannedNote() - } catch (e: IOException) { - logFault(e) - } - } - - fun saveBannedNote() { - ObjectMapper().writerWithDefaultPrettyPrinter() - .writeValue(Paths.get("Banned Note.json").toFile(), bannedNoteStore) - logInfo("Saved Banned Note") - } - - fun putBannedIP(noteID: String, comment: String) { - bannedNoteStore[noteID] = comment - } - - fun wipeBannedNote(noteID: String) { - bannedNoteStore.remove(noteID) - } - - fun isBanned(noteID: String): Boolean { - return bannedNoteStore.contains(noteID) - } -} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/BannedNoteFile.kt b/src/main/kotlin/net/taehui/twilight/system/BannedNoteFile.kt new file mode 100644 index 0000000..d636e0b --- /dev/null +++ b/src/main/kotlin/net/taehui/twilight/system/BannedNoteFile.kt @@ -0,0 +1,44 @@ +package net.taehui.twilight.system + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import net.taehui.twilight.Logger +import java.io.IOException +import java.nio.file.Paths +import java.util.concurrent.ConcurrentHashMap + +object BannedNoteFile : Logger { + private var bannedNoteFileStore = mutableMapOf() + + fun loadBannedNoteFile() { + try { + bannedNoteFileStore.putAll( + ObjectMapper().readValue( + Paths.get("Banned Note File.json").toFile(), + object : TypeReference>() {}) + ) + logInfo("Loaded Banned Note File") + saveBannedNoteFile() + } catch (e: IOException) { + logFault(e) + } + } + + fun saveBannedNoteFile() { + ObjectMapper().writerWithDefaultPrettyPrinter() + .writeValue(Paths.get("Banned Note File.json").toFile(), bannedNoteFileStore) + logInfo("Saved Banned Note File") + } + + fun putBannedNoteFile(noteID: String, comment: String) { + bannedNoteFileStore[noteID] = comment + } + + fun wipeBannedNoteFile(noteID: String) { + bannedNoteFileStore.remove(noteID) + } + + fun isBanned(noteID: String): Boolean { + return bannedNoteFileStore.contains(noteID) + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/DB.kt b/src/main/kotlin/net/taehui/twilight/system/DB.kt index 77778dd..a5fea98 100644 --- a/src/main/kotlin/net/taehui/twilight/system/DB.kt +++ b/src/main/kotlin/net/taehui/twilight/system/DB.kt @@ -10,9 +10,7 @@ import java.io.IOException import java.nio.file.Files import java.nio.file.Path -import java.sql.PreparedStatement -import java.sql.SQLIntegrityConstraintViolationException -import java.sql.Timestamp +import java.sql.* import java.time.Instant import java.time.LocalDate import java.time.ZoneId @@ -20,6 +18,7 @@ import java.util.* import java.util.concurrent.CompletableFuture import java.util.stream.Stream +import kotlin.collections.ArrayList import kotlin.math.pow object DB : Logger { @@ -64,7 +63,7 @@ dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_comment ( - Date TIMESTAMP, + Date DATETIME, Note_ID VARCHAR(139), Avatar VARCHAR(20), Multiplier REAL, @@ -121,7 +120,7 @@ """ CREATE TABLE IF NOT EXISTS tw_bundle ( Avatar VARCHAR(20), - Date TIMESTAMP, + Date DATETIME, Name VARCHAR(191), Length LONG, Competence INTEGER, @@ -205,7 +204,7 @@ CREATE TABLE IF NOT EXISTS tw_level ( Avatar VARCHAR(20), Level_ID CHAR(36), - Date TIMESTAMP, + Date DATETIME, PRIMARY KEY (Avatar, Level_ID), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB @@ -237,7 +236,7 @@ CREATE TABLE IF NOT EXISTS tw_favor ( Note_ID VARCHAR(139), Avatar VARCHAR(20), - Date TIMESTAMP, + Date DATETIME, Favor BOOLEAN, PRIMARY KEY (Avatar, Note_ID), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE @@ -297,13 +296,14 @@ if (favor != null) { it.prepareStatement( """ - REPLACE INTO tw_favor(Note_ID, Avatar, Favor) - VALUES(?, ?, ?) + REPLACE INTO tw_favor + VALUES(?, ?, ?, ?) """.trimIndent() ).use { dbStatement -> dbStatement.setString(1, noteID) dbStatement.setString(2, avatarID) - dbStatement.setBoolean(3, favor) + dbStatement.setTimestamp(3, Timestamp(System.currentTimeMillis())) + dbStatement.setBoolean(4, favor) dbStatement.execute() } } else { @@ -382,57 +382,67 @@ } } - fun getWipeNote(noteID: String): CompletableFuture { - return logValueFuture { - pool.connection.use { - it.prepareStatement( - """ - SELECT COUNT(Note_ID) AS Count - FROM tw_note - WHERE Note_ID LIKE ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, "$noteID:%") - dbStatement.executeQuery().use { rows -> - if (rows.next()) { - rows.getInt("Count") - } else { - 0 - } - } - } - } - } - } - - fun wipeNote(noteID: String): CompletableFuture { + fun wipeNote(noteID: String, logger: Logger): CompletableFuture { return logFuture { pool.connection.use { it.prepareStatement( """ DELETE - FROM tw_comment - WHERE Note_ID LIKE ? + FROM tw_note + WHERE Note_ID = ? """.trimIndent() ).use { dbStatement -> - dbStatement.setString(1, "$noteID:%") - val wipedCount = dbStatement.executeUpdate() - FileUtils.deleteDirectory(TwilightComponent.COMMENT_ENTRY_PATH.resolve(noteID).toFile()) - logInfo("Wiped $wipedCount Comments") + dbStatement.setString(1, noteID) + logger.logInfo("Wiped ${dbStatement.executeUpdate()} Notes") } - } - pool.connection.use { it.prepareStatement( """ - DELETE + SELECT Note_ID FROM tw_note WHERE Note_ID LIKE ? """.trimIndent() ).use { dbStatement -> - dbStatement.setString(1, "$noteID:%") - val wipedCount = dbStatement.executeUpdate() - FileUtils.deleteQuietly(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID).toFile()) - logInfo("Wiped $wipedCount Notes") + val noteID512 = Utility.getNoteID512(noteID) + dbStatement.setString(1, "$noteID512:%") + dbStatement.executeQuery().use { rows -> + if (!rows.next() && Files.deleteIfExists(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID512))) { + logger.logInfo("Wiped Note File") + } else { + logger.logInfo("Wiped 0 Note Files") + } + } + } + it.prepareStatement( + """ + DELETE + FROM tw_comment + WHERE Note_ID = ? + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, noteID) + logger.logInfo("Wiped ${dbStatement.executeUpdate()} Comments") + } + it.prepareStatement( + """ + SELECT Comment_ID + FROM tw_comment + WHERE Note_ID = ? + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, noteID) + dbStatement.executeQuery().use { rows -> + var wipedCount = 0 + while (rows.next()) { + if (Files.deleteIfExists( + TwilightComponent.COMMENT_ENTRY_PATH.resolve(Utility.getNoteID512(noteID)) + .resolve("${rows.getString("Comment_ID")}.xz") + ) + ) { + ++wipedCount + } + } + logger.logInfo("Wiped $wipedCount Comment Files") + } } } } @@ -454,128 +464,87 @@ pool.connection.use { it.prepareStatement( """ - SELECT tw_note.Note_ID, Artist, Title + SELECT tw_note.Note_ID FROM tw_note LEFT OUTER JOIN tw_comment ON tw_note.Note_ID = tw_comment.Note_ID WHERE tw_comment.Note_ID IS NULL """.trimIndent() ).use { dbStatement -> dbStatement.executeQuery().use { rows -> - val noteIDs = mutableSetOf() + val data = mutableSetOf() while (rows.next()) { val noteID = rows.getString("Note_ID") if (!LevelSystem.levelNoteIDs.contains(noteID)) { - noteIDs.add(noteID) + data.add(noteID) } } - noteIDs + data } } } } } - fun wipeNotes(noteIDs: Collection): CompletableFuture { + fun pmsNote(noteID: String, logger: Logger): CompletableFuture { return logFuture { - logInfo( - "Wiped ${ - noteIDs.count { noteID -> - pool.connection.use { - it.prepareStatement( - """ - DELETE - FROM tw_note - WHERE Note_ID = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, noteID) - dbStatement.execute() - true - } - } + pool.connection.use { + it.autoCommit = false + val pmsNoteID = "${Utility.getNoteID512(noteID)}:1" + it.prepareStatement( + """ + UPDATE tw_note + SET Note_ID = ?, Input_Mode = 12 + WHERE Note_ID = ? + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, pmsNoteID) + dbStatement.setString(2, noteID) + if (dbStatement.executeUpdate() > 0) { + logger.logInfo("PMSed Note File") } - } Notes" - ) - logInfo( - "Wiped ${ - noteIDs.count { - try { - Files.delete(TwilightComponent.NOTE_ENTRY_PATH.resolve(it.substring(0, it.indexOf(':')))) - true - } catch (e: IOException) { - logFault(e) - false - } - } - } Note Files") + } + it.prepareStatement( + """ + UPDATE tw_comment + SET Note_ID = ? + WHERE Note_ID = ? + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, pmsNoteID) + dbStatement.setString(2, noteID) + logger.logInfo("PMSed ${dbStatement.executeUpdate()} Comment Files") + } + it.commit() + } } } - fun getWipeComment(avatarID: String): CompletableFuture { + fun getPMSNotes(): CompletableFuture> { return logValueFuture { pool.connection.use { it.prepareStatement( """ - SELECT COUNT(Comment_ID) AS Count - FROM tw_comment - WHERE Avatar = ? + SELECT Note_ID, Title + FROM tw_note + WHERE Input_Mode = 12 """.trimIndent() ).use { dbStatement -> - dbStatement.setString(1, avatarID) dbStatement.executeQuery().use { rows -> - if (rows.next()) { - rows.getInt("Count") - } else { - 0 - } - } - } - } - } - } - - fun wipeComment(avatarID: String): CompletableFuture { - return logFuture { - pool.connection.use { - it.prepareStatement( - """ - SELECT Note_ID, Comment_ID - FROM tw_comment - WHERE Avatar = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, avatarID) - dbStatement.executeQuery().use { rows -> - var wipedCount = 0 + val data = mutableSetOf() while (rows.next()) { - try { - var noteID = rows.getString("Note_ID") - noteID = noteID.substring(0, noteID.indexOf(':')) - Files.delete( - TwilightComponent.COMMENT_ENTRY_PATH.resolve(noteID) - .resolve("${rows.getString("Comment_ID")}.xz") + val title = rows.getString("Title") + if (title.contains("9B", true) || title.contains("9K", true) || title.contains( + "PMS", + true ) - ++wipedCount - } catch (e: IOException) { - logFault(e) + ) { + data.add(rows.getString("Note_ID")) } } - logInfo("Wiped $wipedCount Comment Files") + data } } } - pool.connection.use { - it.prepareStatement( - """ - DELETE - FROM tw_comment - WHERE Avatar LIKE ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, avatarID) - logInfo("Wiped ${dbStatement.executeUpdate()} Comments") - } - } } } @@ -612,21 +581,16 @@ } } - fun wipeComments(commentFilePaths: Collection): CompletableFuture { - return logFuture { - logInfo( - "Wiped ${ - commentFilePaths.count { - try { - Files.delete(it) - true - } catch (e: IOException) { - logFault(e) - false - } - } - } Comment Files" - ) + fun wipeComments(commentFilePaths: Collection): CompletableFuture { + return logValueFuture { + commentFilePaths.count { + try { + Files.deleteIfExists(it) + } catch (e: IOException) { + logFault(e) + false + } + } } } @@ -664,21 +628,16 @@ } } - fun wipeBundles(bundleFilePaths: Collection) { - logValueFuture { - logInfo( - "Wiped ${ - bundleFilePaths.count { - try { - Files.delete(it) - true - } catch (e: IOException) { - logFault(e) - false - } - } - } Bundle Files" - ) + fun wipeBundles(bundleFilePaths: Collection): CompletableFuture { + return logValueFuture { + bundleFilePaths.count { + try { + Files.deleteIfExists(it) + } catch (e: IOException) { + logFault(e) + false + } + } } } @@ -903,13 +862,34 @@ } } + fun getNotes(): CompletableFuture> { + return logValueFuture { + pool.connection.use { + it.prepareStatement( + """ + SELECT Note_ID + FROM tw_note + """.trimIndent() + ).use { dbStatement -> + dbStatement.executeQuery().use { rows -> + val data = mutableListOf() + while (rows.next()) { + data.add(rows.getString("Note_ID")) + } + data + } + } + } + } + } + fun setBundle(qwilightSetBundle: JSON.QwilightSetBundle, avatarID: String) { logValueFuture { pool.connection.use { it.prepareStatement( """ UPDATE tw_bundle - SET Competence = ?, Date = Date + SET Competence = ? WHERE Name = ? AND Avatar = ? """.trimIndent() ).use { dbStatement -> @@ -1000,7 +980,7 @@ WHERE Avatar_ID = ? """.trimIndent() ).use { dbStatement -> - dbStatement.setTimestamp(1, Timestamp.from(Instant.now())) + dbStatement.setTimestamp(1, Timestamp(System.currentTimeMillis())) dbStatement.setString(2, avatarID) dbStatement.execute() } @@ -1152,12 +1132,13 @@ pool.connection.use { it.prepareStatement( """ - REPLACE INTO tw_level(Avatar, Level_ID) - VALUES (?, ?) + REPLACE INTO tw_level + VALUES (?, ?, ?) """.trimIndent() ).use { dbStatement -> dbStatement.setString(1, avatarID) dbStatement.setString(2, levelID) + dbStatement.setTimestamp(3, Timestamp(System.currentTimeMillis())) dbStatement.execute() } } @@ -1290,21 +1271,22 @@ pool.connection.use { it.prepareStatement( """ - INSERT INTO tw_bundle(Avatar, Name, Length, Competence, Variety, Etc) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO tw_bundle + VALUES (?, ?, ?, ?, ?, ?, ?) """.trimIndent() ).use { dbStatement -> dbStatement.setString(1, avatarID) - dbStatement.setString(2, bundleName) - dbStatement.setLong(3, bundleLength) + dbStatement.setTimestamp(2, Timestamp(System.currentTimeMillis())) + dbStatement.setString(3, bundleName) + dbStatement.setLong(4, bundleLength) dbStatement.setInt( - 4, + 5, if (bundleVariety == BundleVariety.QWILIGHT) QwilightAvatar.BUNDLE_VOID else getDefaultBundleCompetence( avatarID ) ) - dbStatement.setInt(5, bundleVariety.value) - dbStatement.setString(6, etc) + dbStatement.setInt(6, bundleVariety.value) + dbStatement.setString(7, etc) dbStatement.execute() } } @@ -1667,7 +1649,7 @@ it.prepareStatement( """ UPDATE tw_comment - SET Date = Date, Is_Max = false + SET Is_Max = false WHERE Note_ID = ? AND Avatar = ? """.trimIndent() ).use { dbStatement -> @@ -1678,33 +1660,34 @@ } it.prepareStatement( """ - INSERT INTO tw_comment(Note_ID, Avatar, Multiplier, Auto_Mode, Note_Salt_Mode, Audio_Multiplier, Faint_Note_Mode, Judgment_Mode, Hit_Points_Mode, Note_Mobility_Mode, Long_Note_Mode, Input_Favor_Mode, Note_Modify_Mode, Lowest_Judgment_Condition_Mode, Stand, Band, Is_P, Point, Salt, Comment_ID, Is_Max, Is_Paused, Input_Flags) - VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + INSERT INTO tw_comment + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """.trimIndent() ).use { dbStatement -> - dbStatement.setString(1, noteID) - dbStatement.setString(2, avatarID) - dbStatement.setDouble(3, multiplier) - dbStatement.setInt(4, autoMode) - dbStatement.setInt(5, noteSaltMode) - dbStatement.setDouble(6, audioMultiplier) - dbStatement.setInt(7, faintNoteMode) - dbStatement.setInt(8, judgmentMode) - dbStatement.setInt(9, hitPointsMode) - dbStatement.setInt(10, noteMobilityMode) - dbStatement.setInt(11, longNoteMode) - dbStatement.setInt(12, inputFavorMode) - dbStatement.setInt(13, noteModifyMode) - dbStatement.setInt(14, lowestJudgmentConditionMode) - dbStatement.setInt(15, stand) - dbStatement.setInt(16, band) - dbStatement.setBoolean(17, isP) - dbStatement.setDouble(18, point) - dbStatement.setInt(19, salt) - dbStatement.setString(20, commentID) - dbStatement.setBoolean(21, isNewStand) - dbStatement.setBoolean(22, isPaused) - dbStatement.setInt(23, inputFlags) + dbStatement.setTimestamp(1, Timestamp(System.currentTimeMillis())) + dbStatement.setString(2, noteID) + dbStatement.setString(3, avatarID) + dbStatement.setDouble(4, multiplier) + dbStatement.setInt(5, autoMode) + dbStatement.setInt(6, noteSaltMode) + dbStatement.setDouble(7, audioMultiplier) + dbStatement.setInt(8, faintNoteMode) + dbStatement.setInt(9, judgmentMode) + dbStatement.setInt(10, hitPointsMode) + dbStatement.setInt(11, noteMobilityMode) + dbStatement.setInt(12, longNoteMode) + dbStatement.setInt(13, inputFavorMode) + dbStatement.setInt(14, noteModifyMode) + dbStatement.setInt(15, lowestJudgmentConditionMode) + dbStatement.setInt(16, stand) + dbStatement.setInt(17, band) + dbStatement.setBoolean(18, isP) + dbStatement.setDouble(19, point) + dbStatement.setInt(20, salt) + dbStatement.setString(21, commentID) + dbStatement.setBoolean(22, isNewStand) + dbStatement.setBoolean(23, isPaused) + dbStatement.setInt(24, inputFlags) dbStatement.execute() } it.commit() @@ -2398,7 +2381,7 @@ ORDER BY COUNT DESC LIMIT 10 """.trimIndent() - ).use {dbStatement -> + ).use { dbStatement -> dbStatement.setString(1, avatarID) dbStatement.setInt(2, inputMode.value) dbStatement.executeQuery().use { @@ -3444,76 +3427,4 @@ } } } - - fun setCommentMax(avatarID: String): CompletableFuture { - return logFuture { - val noteIDs = mutableListOf() - pool.connection.use { - it.prepareStatement( - """ - SELECT DISTINCT Note_ID - FROM tw_comment - WHERE Avatar = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, avatarID) - dbStatement.executeQuery().use { rows -> - while (rows.next()) { - noteIDs.add(rows.getString("Note_ID")) - } - } - } - } - noteIDs.forEach { noteID -> - pool.connection.use { it -> - it.autoCommit = false - var stand = 0 - var date: Timestamp? = null - it.prepareStatement( - """ - SELECT Stand, Date - FROM tw_comment - WHERE Note_ID = ? AND Date = ( - SELECT MAX(Date) - FROM tw_comment AS tw_comment_2 - WHERE Note_ID = ? AND Avatar = ? AND Stand = ( - SELECT MAX(Stand) - FROM tw_comment AS tw_comment_3 - WHERE Note_ID = ? AND Avatar = ? - ) - ) AND Avatar = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString(1, noteID) - dbStatement.setString(2, noteID) - dbStatement.setString(3, avatarID) - dbStatement.setString(4, noteID) - dbStatement.setString(5, avatarID) - dbStatement.setString(6, avatarID) - dbStatement.executeQuery().use { - if (it.next()) { - stand = it.getInt("Stand") - date = it.getTimestamp("Date") - } - } - } - it.prepareStatement( - """ - UPDATE tw_comment - SET Date = Date, Is_Max = (Stand = ? AND Date = ?) - WHERE Note_ID = ? AND Avatar = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setInt(1, stand) - dbStatement.setTimestamp(2, date) - dbStatement.setString(3, noteID) - dbStatement.setString(4, avatarID) - dbStatement.execute() - } - it.commit() - } - } - logInfo("Learned") - } - } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/IO.kt b/src/main/kotlin/net/taehui/twilight/system/IO.kt index bf030c9..eab3655 100644 --- a/src/main/kotlin/net/taehui/twilight/system/IO.kt +++ b/src/main/kotlin/net/taehui/twilight/system/IO.kt @@ -3,11 +3,10 @@ import net.taehui.twilight.BaseCompiler import net.taehui.twilight.Logger import net.taehui.twilight.TwilightComponent -import org.apache.commons.codec.binary.Hex +import net.taehui.twilight.Utility import org.jline.reader.UserInterruptException import java.nio.file.Files import java.nio.file.Path -import java.security.MessageDigest import java.time.LocalDateTime import java.util.concurrent.CompletableFuture import java.util.concurrent.atomic.AtomicInteger @@ -15,12 +14,10 @@ object IO : Logger { - private val futureNoteLearnerStatus = AtomicInteger() - private var futureNoteLearner: CompletableFuture? = null - private var futureCommentLearner: CompletableFuture? = null - private var futureWipeNote = "" + private val futureLearnNotesStatus = AtomicInteger() + private var futureLearnNotes: CompletableFuture? = null private var futureWipeNotes: Collection? = null - private var futureWipeComment = "" + private var futurePMSNotes: Collection? = null private var futureWipeComments: Collection? = null private var futureWipeBundles: Collection? = null @@ -32,36 +29,33 @@ val line = r.readLine("> ") if (line.isNotEmpty()) { val w = r.parsedLine.words() - if (futureWipeNote.isNotEmpty()) { - if ("y".equals(w[0], ignoreCase = true)) { - DB.wipeNote(futureWipeNote) - } else { - logInfo("Cancelled") - } - futureWipeNote = "" - continue - } if (futureWipeNotes != null) { - if ("y".equals(w[0], ignoreCase = true)) { - DB.wipeNotes(futureWipeNotes!!) + if ("y".equals(w[0], true)) { + futureWipeNotes?.forEach { + DB.wipeNote(it, this) + } } else { logInfo("Cancelled") } futureWipeNotes = null continue } - if (futureWipeComment.isNotEmpty()) { - if ("y".equals(w[0], ignoreCase = true)) { - DB.wipeComment(futureWipeComment) + if (futurePMSNotes != null) { + if ("y".equals(w[0], true)) { + futurePMSNotes?.forEach { + DB.pmsNote(it, this) + } } else { logInfo("Cancelled") } - futureWipeComment = "" + futurePMSNotes = null continue } if (futureWipeComments != null) { - if ("y".equals(w[0], ignoreCase = true)) { - DB.wipeComments(futureWipeComments!!) + if ("y".equals(w[0], true)) { + DB.wipeComments(futureWipeComments!!).thenAccept { + logInfo("Wiped $it Comment Files") + } } else { logInfo("Cancelled") } @@ -69,8 +63,10 @@ continue } if (futureWipeBundles != null) { - if ("y".equals(w[0], ignoreCase = true)) { - DB.wipeBundles(futureWipeBundles!!) + if ("y".equals(w[0], true)) { + DB.wipeBundles(futureWipeBundles!!).thenAccept { + logInfo("Wiped $it Bundle Files") + } } else { logInfo("Cancelled") } @@ -83,8 +79,7 @@ "alarm" -> { if (w.size > 2) { SiteHandler.setSiteNotify( - SiteHandler.getSiteID(w[1]), - w[2] + SiteHandler.getSiteID(w[1]), w[2] ) } else if (w.size > 1) { AvatarHandler.justNotify(w[1]) @@ -142,7 +137,7 @@ } } } - logInfo("avatar [view] view Avatars") + logInfo("avatar [view] View Avatars") logInfo("avatar [quit] Quit Avatar") logInfo("avatar [ban] Ban Avatar IP") logInfo("avatar [allow] Allow Avatar IP") @@ -150,16 +145,20 @@ "awilight" -> { if (w.size > 2) { - if ("set" == w[1]) { - val awilightCount = w[2].toInt() - Configure.awilightCount = - 0.coerceAtLeast(Configure.awilightCount + awilightCount) - AwilightHandler.setAwilightCount( - awilightCount - ) - continue - } else { - logInfo("awilight set ") + when (w[1]) { + "set" -> { + if (w.size > 3) { + val awilightCount = w[2].toInt() + Configure.awilightCount = + 0.coerceAtLeast(Configure.awilightCount + awilightCount) + AwilightHandler.setAwilightCount( + awilightCount + ) + } else { + logInfo("awilight set ") + } + continue + } } } logInfo("awilight [set] Set Awilight") @@ -167,59 +166,36 @@ "bundle" -> { if (w.size > 1) { - if ("wipe" == w[1]) { - DB.getWipeBundles().thenAccept { - if (it.isNotEmpty()) { - futureWipeBundles = it + when (w[1]) { + "wipe" -> { + DB.getWipeBundles().thenAccept { + if (it.isNotEmpty()) { + futureWipeBundles = it + } + logInfo("${it.size} Bundle Files") } - logInfo("${it.size} Bundle Files") + continue } - continue } } - logInfo("bundle [wipe] Wipe Bundle Files") + logInfo("bundle [wipe] Clean Bundle Files") } "comment" -> { if (w.size > 1) { when (w[1]) { "wipe" -> { - if (w.size > 2) { - DB.getWipeComment(w[2]).thenAccept { - if (it > 0) { - futureWipeComment = w[2] - } - logInfo("$it Comment Files") + DB.getWipeComments().thenAccept { + if (it.isNotEmpty()) { + futureWipeComments = it } - } else { - DB.getWipeComments().thenAccept { - if (it.isNotEmpty()) { - futureWipeComments = it - } - logInfo("${it.size} Comment Files") - } - } - continue - } - - "learn" -> { - if (w.size > 2) { - if (futureCommentLearner?.isDone != false) { - futureCommentLearner = DB.setCommentMax(w[2]) - } else { - logInfo( - "Learning Comments" - ) - } - } else { - logInfo("comment learn ") + logInfo("${it.size} Comment Files") } continue } } } - logInfo("comment [wipe] Wipe Comment Files") - logInfo("comment [learn] Learn Comments") + logInfo("comment [wipe] Clean Comment Files") } "note" -> { @@ -227,59 +203,54 @@ when (w[1]) { "learn" -> { fun learnNoteFile(noteFilePath: Path): Boolean { - try { - val noteData = Files.readAllBytes(noteFilePath) - val hashComputer512 = MessageDigest.getInstance("SHA-512") - hashComputer512.update(noteData) - val hashComputer128 = MessageDigest.getInstance("MD5") - hashComputer128.update(noteData) - val hashComputer256 = MessageDigest.getInstance("SHA-256") - hashComputer256.update(noteData) - val noteID512 = Hex.encodeHexString(hashComputer512.digest()) - val noteID128 = Hex.encodeHexString(hashComputer128.digest()) - val noteID256 = Hex.encodeHexString(hashComputer256.digest()) - val targetComputing = BaseCompiler.handleCompile(noteData) - DB.setNote( - "$noteID512:0", - noteID128, - noteID256, - targetComputing - ) - return true + return try { + val noteFileData = Files.readAllBytes(noteFilePath) + BaseCompiler.handleCompile(noteFileData, -1).forEach { + DB.setNote( + it.noteID, + Utility.getID128(noteFileData), + Utility.getID256(noteFileData), + it + ) + } + true } catch (e: Throwable) { logFault(e) - return false + false } } if (w.size > 2) { - learnNoteFile(Path.of(w[2])) + if (learnNoteFile(Path.of(w[2]))) { + logInfo("Learned Note File") + NoteFilesSystem.loadNoteFiles() + } } else { - if (futureNoteLearner?.isDone != false) { - futureNoteLearner = logFuture { + if (futureLearnNotes?.isDone != false) { + futureLearnNotes = logFuture { DB.wipeNotes() try { Files.newDirectoryStream( TwilightComponent.NOTE_ENTRY_PATH - ) - .use { - StreamSupport.stream(it.spliterator(), true) - .forEach { noteFilePath -> - if (learnNoteFile(noteFilePath)) { - futureNoteLearnerStatus.incrementAndGet() - } + ).use { + StreamSupport.stream(it.spliterator(), true) + .forEach { noteFilePath -> + if (learnNoteFile(noteFilePath)) { + futureLearnNotesStatus.incrementAndGet() } - } + } + } } finally { logInfo( - "Learned ${futureNoteLearnerStatus.get()} Note Files" + "Learned ${futureLearnNotesStatus.get()} Note Files" ) - futureNoteLearnerStatus.set(0) + futureLearnNotesStatus.set(0) + NoteFilesSystem.loadNoteFiles() } } } else { logInfo( - "Learning ${futureNoteLearnerStatus.get()} Note Files" + "Learning ${futureLearnNotesStatus.get()} Note Files" ) } } @@ -288,7 +259,7 @@ "ban" -> { if (w.size > 3) { - BannedNote.putBannedIP(w[2], w[3]) + BannedNoteFile.putBannedNoteFile(w[2], w[3]) } else { logInfo("note ban ") } @@ -297,7 +268,7 @@ "allow" -> { if (w.size > 2) { - BannedNote.wipeBannedNote(w[2]) + BannedNoteFile.wipeBannedNoteFile(w[2]) } else { logInfo("note allow ") } @@ -306,12 +277,7 @@ "wipe" -> { if (w.size > 2) { - DB.getWipeNote(w[2]).thenAccept { - if (it > 0) { - futureWipeNote = w[2] - } - logInfo("$it Notes") - } + DB.wipeNote(w[2], this) } else { DB.getWipeNotes().thenAccept { if (it.isNotEmpty()) { @@ -322,12 +288,27 @@ } continue } + + "pms" -> { + if (w.size > 2) { + DB.pmsNote(w[2], this) + } else { + DB.getPMSNotes().thenAccept { + if (it.isNotEmpty()) { + futurePMSNotes = it + } + logInfo("${it.size} Notes") + } + } + continue + } } } logInfo("note [learn] Learn Notes") logInfo("note [ban] Ban Note") logInfo("note [allow] Allow Note") - logInfo("note [wipe] Wipe Note File") + logInfo("note [wipe] Clean or Wipe Note File") + logInfo("note [pms] PMS Note File") } "pause" -> { @@ -352,9 +333,27 @@ } continue } + + "view" -> { + logInfo(PlatformSystem.platformStatus) + continue + } + + "dispose" -> { + PlatformSystem.dispose() + continue + } + + "handle" -> { + PlatformSystem.handleSystem() + continue + } } } - logInfo("platform [avatar] ") + logInfo("platform [avatar] Handle Avatars") + logInfo("platform [view] View Platform") + logInfo("platform [dispose] Close Platform") + logInfo("platform [handle] Handle Platform") } "ram" -> { @@ -402,12 +401,36 @@ } } } - logInfo("site [view] view Sites") + logInfo("site [view] View Sites") logInfo("site [put] Put Site") logInfo("site [wipe] Wipe Site") logInfo("site [silent] Silent Site") } + "tv" -> { + if (w.size > 1) { + when (w[1]) { + "view" -> { + logInfo(TVSystem.tvStatus) + continue + } + + "dispose" -> { + TVSystem.dispose() + continue + } + + "handle" -> { + TVSystem.handleSystem() + continue + } + } + } + logInfo("tv [view] View TV") + logInfo("tv [dispose] Close TV") + logInfo("tv [handle] Handle TV") + } + else -> { logInfo("[alarm] Send Notify") logInfo("[avatar] Handle Avatars") @@ -418,6 +441,7 @@ logInfo("[pause] Pause Twilight") logInfo("[platform] Handle Platform") logInfo("[site] Handle Sites") + logInfo("[tv] Handle TV") logInfo("[stop] Stop Twilight") } } diff --git a/src/main/kotlin/net/taehui/twilight/system/NoteFilesSystem.kt b/src/main/kotlin/net/taehui/twilight/system/NoteFilesSystem.kt index 99a0986..6fc1f1a 100644 --- a/src/main/kotlin/net/taehui/twilight/system/NoteFilesSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/NoteFilesSystem.kt @@ -4,29 +4,27 @@ import net.taehui.twilight.TwilightComponent import net.taehui.twilight.Utility import java.io.IOException -import java.nio.file.Files import java.nio.file.Path import java.util.concurrent.ConcurrentHashMap object NoteFilesSystem : Logger { - private val noteFiles = ConcurrentHashMap() + private var noteFiles = ConcurrentHashMap() fun loadNoteFiles() { - try { - noteFiles.clear() - Files.list(TwilightComponent.NOTE_ENTRY_PATH).use { noteFilePaths -> - noteFilePaths.forEach { noteFilePath -> - noteFiles["${noteFilePath.fileName}:0"] = noteFilePath - } + DB.getNotes().thenAccept { notes -> + try { + noteFiles = ConcurrentHashMap(notes.associateWith { + TwilightComponent.NOTE_ENTRY_PATH.resolve(Utility.getNoteID512(it)) + }) + logInfo("Loaded Note Files") + } catch (e: IOException) { + logFault(e) } - logInfo("Loaded Note Files") - } catch (e: IOException) { - logFault(e) } } val noteFile: Map.Entry? - get() = Utility.getSaltedItem(ArrayList?>(noteFiles.entries), null) + get() = noteFiles.entries.randomOrNull() fun getNoteFile(noteID: String): Path? { return noteFiles[noteID] diff --git a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt index c56f390..82148f0 100644 --- a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.JDA.Status import net.dv8tion.jda.api.JDABuilder import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.Member @@ -126,6 +127,9 @@ } } + val platformStatus: String + get() = (platform?.status ?: Status.SHUTDOWN).toString() + fun dispose() { platform?.shutdown() } diff --git a/src/main/kotlin/net/taehui/twilight/system/QwilightNamesSystem.kt b/src/main/kotlin/net/taehui/twilight/system/QwilightNamesSystem.kt index f232e40..2997f4d 100644 --- a/src/main/kotlin/net/taehui/twilight/system/QwilightNamesSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/QwilightNamesSystem.kt @@ -2,30 +2,25 @@ import net.taehui.twilight.Logger import net.taehui.twilight.Utility +import java.util.LinkedList +import java.util.concurrent.ConcurrentLinkedQueue object QwilightNamesSystem : Logger { - private val qwilightNameCountMap = mutableMapOf() - private val qwilightNames = mutableListOf() + private val qwilightNames = LinkedList() fun loadQwilightNames() { qwilightNames.addAll(DB.getQwilightNames()) - qwilightNames.forEach { qwilightNameCountMap[it] = 0 } logInfo("Loaded Qwilight Names") } val qwilightName: String get() { - synchronized(qwilightNameCountMap) { - val minValue = qwilightNameCountMap.values.minOrNull() ?: 0 - val qwilightName = Utility.getSaltedItem( - qwilightNameCountMap.entries - .filter { it.value == minValue } - .map { it.key }, "" - ) + return synchronized(qwilightNames) { + val qwilightName = qwilightNames.poll() ?: "" if (qwilightName.isNotEmpty()) { - qwilightNameCountMap[qwilightName] = (qwilightNameCountMap[qwilightName] ?: 0) + 1 + qwilightNames.offer(qwilightName) } - return qwilightName + qwilightName } } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/SiteHandler.kt b/src/main/kotlin/net/taehui/twilight/system/SiteHandler.kt index 197727d..38bd34f 100644 --- a/src/main/kotlin/net/taehui/twilight/system/SiteHandler.kt +++ b/src/main/kotlin/net/taehui/twilight/system/SiteHandler.kt @@ -191,9 +191,9 @@ ) } - fun setNoteFileContents(avatar: Avatar, siteID: UUID, noteFileContents: JSON.QwilightSetNoteFile) { + fun setNoteFileContents(avatar: Avatar, siteID: UUID, noteFileData: JSON.QwilightSetNoteFile) { sites[siteID]?.setNoteFileContents( - avatar, noteFileContents + avatar, noteFileData ) } @@ -258,7 +258,7 @@ site.setModeComponent(qwilightNewSite.data!!) site.setNoteFileContents(JSON.QwilightSetNoteFile().apply { noteID = qwilightNewSite.noteID - noteIDs = qwilightNewSite.noteIDs!! + noteIDs = qwilightNewSite.noteIDs title = qwilightNewSite.title artist = qwilightNewSite.artist genre = qwilightNewSite.genre diff --git a/src/main/kotlin/net/taehui/twilight/system/TVSystem.kt b/src/main/kotlin/net/taehui/twilight/system/TVSystem.kt index 74d8a2d..e89f2a4 100644 --- a/src/main/kotlin/net/taehui/twilight/system/TVSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/TVSystem.kt @@ -11,6 +11,7 @@ import java.time.Duration import java.util.concurrent.Executors import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit object TVSystem : Logger { @@ -33,51 +34,54 @@ isDaemon = true } } - private var targetSystem: WebDriver? = null + private var future: ScheduledFuture<*>? = null + private var tv: WebDriver? = null fun handleSystem() { if (Configure.mode.tv) { try { - targetSystem = EdgeDriver(EdgeOptions().apply { + tv = EdgeDriver(EdgeOptions().apply { addArguments("--headless", "--no-sandbox") }) - val pendingElements = mutableMapOf() var lastElements = emptySet() - ses.scheduleWithFixedDelay({ - targetSystem?.get("https://www.twitch.tv/directory/game/Qwilight") - val dataTest = By.cssSelector("[data-test-selector=TitleAndChannel]") - val elements = try { - WebDriverWait( - targetSystem, - Duration.ofSeconds(1) - ).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(dataTest)) - targetSystem?.findElements(dataTest) ?: throw TimeoutException() - } catch (e: TimeoutException) { - emptyList() - }.map { - TVItem( - it.getAttribute("href"), - it.findElement(By.tagName("h3")).text, - it.findElement(By.tagName("p")).text - ) - }.toSet() - elements.subtract(lastElements).filter { - pendingElements.remove(it) == null - }.forEach { - SiteHandler.putSiteYell(it) - } - lastElements.subtract(elements).forEach { - pendingElements[it] = 0 - } - pendingElements.toMap().forEach { - if (it.value < 5) { - pendingElements[it.key] = it.value + 1 - } else { - pendingElements.remove(it.key) + + future = ses.scheduleWithFixedDelay({ + tv?.let { it -> + it.get("https://www.twitch.tv/directory/game/Qwilight") + val dataTest = By.cssSelector("[data-test-selector=TitleAndChannel]") + val elements = try { + WebDriverWait( + it, + Duration.ofSeconds(1) + ).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(dataTest)) + it.findElements(dataTest) ?: throw TimeoutException() + } catch (e: TimeoutException) { + emptyList() + }.map { element -> + TVItem( + element.getAttribute("href"), + element.findElement(By.tagName("h3")).text, + element.findElement(By.tagName("p")).text + ) + }.toSet() + elements.subtract(lastElements).filter { + pendingElements.remove(it) == null + }.forEach { + SiteHandler.putSiteYell(it) } + lastElements.subtract(elements).forEach { + pendingElements[it] = 0 + } + pendingElements.toMap().forEach { + if (it.value < 5) { + pendingElements[it.key] = it.value + 1 + } else { + pendingElements.remove(it.key) + } + } + lastElements = elements } - lastElements = elements }, 0L, 1L, TimeUnit.MINUTES) } catch (e: Throwable) { logFault(e) @@ -85,9 +89,11 @@ } } + val tvStatus: String + get() = "{Title: ${tv?.title}, Page: ${tv?.pageSource}, URL: ${tv?.currentUrl}, Handles: [${tv?.windowHandles?.joinToString()}]}" + fun dispose() { ses.shutdown() - ses.awaitTermination(1, TimeUnit.SECONDS) - targetSystem?.quit() + tv?.quit() } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/WitSystem.kt b/src/main/kotlin/net/taehui/twilight/system/WitSystem.kt index 3479a7b..59d4663 100644 --- a/src/main/kotlin/net/taehui/twilight/system/WitSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/WitSystem.kt @@ -15,7 +15,6 @@ fun dispose() { ses.shutdown() - ses.awaitTermination(1, TimeUnit.SECONDS) } fun handleLoop(src: Any, date: LocalDateTime, loopCount: Int, toHandle: (LocalDateTime) -> Unit) { diff --git a/src/main/kotlin/net/taehui/twilight/taehui/TaehuiAvatar.kt b/src/main/kotlin/net/taehui/twilight/taehui/TaehuiAvatar.kt index a3ecfb1..b94ba02 100644 --- a/src/main/kotlin/net/taehui/twilight/taehui/TaehuiAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/taehui/TaehuiAvatar.kt @@ -97,7 +97,7 @@ override fun logFault(e: Throwable) { if (Utility.isValidFault(e)) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFaultText(e)) } } } \ 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 562255d..89335b4 100644 --- a/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt @@ -10,7 +10,6 @@ import io.netty.util.CharsetUtil import net.taehui.twilight.* import net.taehui.twilight.system.* -import org.apache.commons.codec.binary.Hex import org.apache.commons.compress.compressors.xz.XZCompressorInputStream import org.apache.commons.io.IOUtils import org.apache.hc.client5.http.classic.methods.HttpGet @@ -20,7 +19,6 @@ import java.net.URLDecoder import java.nio.charset.StandardCharsets import java.nio.file.Files -import java.security.MessageDigest import java.util.concurrent.CompletableFuture import kotlin.io.path.inputStream @@ -146,7 +144,7 @@ "/qwilight/www/comment" -> { val noteID = params.getOrDefault("noteID", "") - if (BannedNote.isBanned(noteID)) { + if (BannedNoteFile.isBanned(noteID)) { send(ctx, object { val favor = null val totalFavor = 0 @@ -165,10 +163,7 @@ } else { XZCompressorInputStream( TwilightComponent.COMMENT_ENTRY_PATH.resolve( - noteID.substring( - 0, - noteID.indexOf(':') - ) + Utility.getNoteID512(noteID) ).resolve("$commentID.xz") .inputStream() ).use { @@ -187,49 +182,89 @@ } } - "/qwilight/www/avatar/favorites/5K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_5_1, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/7K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_7_1, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/9K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_9, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/10K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_10_2, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/14K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_14_2, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/24K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_24_2, avatarID).thenAccept { - send(ctx, it) - } - "/qwilight/www/avatar/favorites/48K" -> DB.getAvatarFavorites(Component.InputMode.INPUT_MODE_48_4, avatarID).thenAccept { + "/qwilight/www/avatar/favorites/5K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_5_1, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/5K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_5_1, avatarID).thenAccept { + "/qwilight/www/avatar/favorites/7K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_7_1, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/7K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_7_1, avatarID).thenAccept { + + "/qwilight/www/avatar/favorites/9K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_9, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/9K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_9, avatarID).thenAccept { + + "/qwilight/www/avatar/favorites/10K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_10_2, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/10K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_10_2, avatarID).thenAccept { + + "/qwilight/www/avatar/favorites/14K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_14_2, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/14K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_14_2, avatarID).thenAccept { + + "/qwilight/www/avatar/favorites/24K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_24_2, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/24K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_24_2, avatarID).thenAccept { + + "/qwilight/www/avatar/favorites/48K" -> DB.getAvatarFavorites( + Component.InputMode.INPUT_MODE_48_4, + avatarID + ).thenAccept { send(ctx, it) } - "/qwilight/www/avatar/lasts/48K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_48_4, avatarID).thenAccept { - send(ctx, it) - } + + "/qwilight/www/avatar/lasts/5K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_5_1, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/7K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_7_1, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/9K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_9, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/10K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_10_2, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/14K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_14_2, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/24K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_24_2, avatarID) + .thenAccept { + send(ctx, it) + } + + "/qwilight/www/avatar/lasts/48K" -> DB.getAvatarLasts(Component.InputMode.INPUT_MODE_48_4, avatarID) + .thenAccept { + send(ctx, it) + } "/qwilight/www/avatar/wwwLevels" -> DB.getAvatarWwwLevels(avatarID).thenAccept { send(ctx, it) @@ -508,24 +543,21 @@ } "/qwilight/www/note" -> { - val noteFileContents = ByteBufUtil.getBytes(msg.content()) - val hashComputer512 = MessageDigest.getInstance("SHA-512") - hashComputer512.update(noteFileContents) - val hashComputer128 = MessageDigest.getInstance("MD5") - hashComputer128.update(noteFileContents) - val hashComputer256 = MessageDigest.getInstance("SHA-256") - hashComputer256.update(noteFileContents) - val noteID512 = Hex.encodeHexString(hashComputer512.digest()) - val noteID128 = Hex.encodeHexString(hashComputer128.digest()) - val noteID256 = Hex.encodeHexString(hashComputer256.digest()) - val targetComputing = BaseCompiler.handleCompile(noteFileContents) - if (targetComputing.isBanned || BannedNote.isBanned(noteID512)) { + val noteFileData = ByteBufUtil.getBytes(msg.content()) + val targetComputing = BaseCompiler.handleCompile(noteFileData, 0).single() + if (targetComputing.isBanned || BannedNoteFile.isBanned(targetComputing.noteID)) { send403(ctx) } else { logFuture { - Files.write(TwilightComponent.NOTE_ENTRY_PATH.resolve(noteID512), noteFileContents) + Files.write( + TwilightComponent.NOTE_ENTRY_PATH.resolve(Utility.getID512(noteFileData)), + noteFileData + ) DB.setNote( - "$noteID512:0", noteID128, noteID256, targetComputing + targetComputing.noteID, + Utility.getID128(noteFileData), + Utility.getID256(noteFileData), + targetComputing ) send204(ctx) } @@ -562,7 +594,7 @@ override fun logFault(e: Throwable) { if (Utility.isValidFault(e)) { - LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFault(e)) + LoggerFactory.getLogger(javaClass).error("[{}] {}", avatarIP, Utility.getFaultText(e)) } } } \ No newline at end of file