diff --git a/src/main/kotlin/net/taehui/twilight/BundleIO.kt b/src/main/kotlin/net/taehui/twilight/BundleIO.kt index d8791b7..507d02e 100644 --- a/src/main/kotlin/net/taehui/twilight/BundleIO.kt +++ b/src/main/kotlin/net/taehui/twilight/BundleIO.kt @@ -1,5 +1,6 @@ package net.taehui.twilight +import com.fasterxml.jackson.annotation.JsonValue import org.apache.commons.io.FileUtils import org.apache.commons.io.FilenameUtils import java.nio.ByteBuffer @@ -18,13 +19,18 @@ val bundleFileName: String, private val isSaveAs: Boolean ) : AutoCloseable { - enum class BundleVariety(val value: Int, val fileVariety: String) { + enum class BundleVariety(@JvmField val value: Int, val fileVariety: String) { DEFAULT_UI(-2, ".zip"), DEFAULT_NOTE(-1, ".zip"), UI(1, ".zip"), QWILIGHT( 2, ".zip" ), EVENT_NOTE(3, ".txt"), NOTE(4, ".zip"), NET(5, ".zip"); + @JsonValue + fun getValue(): Int { + return value + } + companion object { fun getBundleVariety(value: Int): BundleVariety { return when (value) { @@ -50,8 +56,12 @@ ) } - fun saveFilePosition(filePosition: Int) { + fun saveFilePosition(filePosition: Int): Boolean { this.filePosition += filePosition + return this.filePosition > when (bundleVariety) { + BundleVariety.NET -> TwilightComponent.NET_BUNDLE_LENGTH + else -> TwilightComponent.BUNDLE_LENGTH + } } fun getBundleLength(): Long { diff --git a/src/main/kotlin/net/taehui/twilight/TwilightComponent.kt b/src/main/kotlin/net/taehui/twilight/TwilightComponent.kt index 0dc278d..0533fd9 100644 --- a/src/main/kotlin/net/taehui/twilight/TwilightComponent.kt +++ b/src/main/kotlin/net/taehui/twilight/TwilightComponent.kt @@ -17,4 +17,7 @@ val ABILITY_ENTRY_PATH: Path = SYSTEM_ENTRY_PATH.resolve("Ability") val EDGE_ENTRY_PATH: Path = SYSTEM_ENTRY_PATH.resolve("Edge") val AWILIGHT_FILE_PATH: Path = SYSTEM_ENTRY_PATH.resolve("Awilight.py") + + const val NET_BUNDLE_LENGTH = 1_000_000_000L + const val BUNDLE_LENGTH = 5_000_000_000L } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt b/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt index 5a4d83f..df81407 100644 --- a/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/qwilight/QwilightAvatar.kt @@ -36,13 +36,10 @@ override lateinit var handler: ChannelHandlerContext override var isAwilight = false override var isAvailable = true - private val savingDefaultNoteIDs = mutableListOf() - private val savingDefaultUIIDs = mutableListOf() - private val defaultNoteSaveStore = LinkedList() - private val defaultUISaveStore = LinkedList() + private val defaultNoteNames = LinkedList() + private val defaultUINames = LinkedList() override lateinit var avatarIP: InetAddress override var avatarEstimatedID = "" - private val savingAsBundleIOs = ConcurrentHashMap() private val savingBundleIOs = ConcurrentHashMap() override var isEstablished = false override var isSignedIn = false @@ -74,8 +71,8 @@ handler.writeAndFlush(event) } - private fun hasAvailableCount(): Boolean { - return savingBundleIOs.size + savingAsBundleIOs.size < BUNDLE_AVAILABLE_COUNT + private fun hasAvailableBundleIOs(): Boolean { + return savingBundleIOs.size < BUNDLE_AVAILABLE_COUNT } private fun doCallBundle(targetAvatarID: String, isWindowOpen: Boolean) { @@ -86,7 +83,7 @@ send(EventOuterClass.Event.EventID.CALL_BUNDLE, object { val targetAvatar = targetAvatarID val targetValue = bundles.second - val bundleLength = 5000000000 + val bundleLength = TwilightComponent.BUNDLE_LENGTH @JvmField val isWindowOpen = isWindowOpen @@ -147,26 +144,20 @@ fun saveDefaultNote(eventText: String) { val text = if (eventText.isEmpty()) null else jm.readValue(eventText, Array::class.java) if (text != null) { - if (defaultNoteSaveStore.isEmpty()) { + if (defaultNoteNames.isEmpty()) { Files.list(TwilightComponent.DEFAULT_NOTE_ENTRY).use { defaultNoteFilePaths -> - defaultNoteSaveStore.addAll(defaultNoteFilePaths.filter { defaultNoteFilePath -> - FilenameUtils.isExtension( - defaultNoteFilePath.fileName.toString(), - "zip" - ) - }.map { defaultNoteFilePath -> + defaultNoteNames.addAll(defaultNoteFilePaths.map { defaultNoteFilePath -> defaultNoteFilePath.nameWithoutExtension - }.toList().subtract(text.toList().toSet())) + }.toList().subtract(text.toSet())) } } else { send(EventOuterClass.Event.EventID.ALREADY_LOADING_BUNDLE, null) return } } - val saveBundleID = UUID.randomUUID().toString() - savingDefaultNoteIDs.add(saveBundleID) - defaultNoteSaveStore.poll().let { + defaultNoteNames.poll().let { if (it != null) { + val saveBundleID = UUID.randomUUID().toString() val bundleFileName = "$it.zip" val bundleFilePath = TwilightComponent.DEFAULT_NOTE_ENTRY.resolve(bundleFileName) val fileChannel = AsynchronousFileChannel.open(bundleFilePath) @@ -183,29 +174,20 @@ EventOuterClass.Event.EventID.SAVE_BUNDLE, object { val bundleID = saveBundleID - val bundleVariety = BundleVariety.DEFAULT_NOTE.value + val bundleVariety = BundleVariety.DEFAULT_NOTE val bundleLength = fileChannel.size() } ) - } else { - send( - EventOuterClass.Event.EventID.NOTIFY_INFO, - translateLanguage("savedDefaultNote") - ) } } } fun saveDefaultUI(eventText: String) { - val defaultUISaveStore = defaultUISaveStore if (eventText.toBoolean()) { - if (defaultUISaveStore.isEmpty()) { + if (defaultUINames.isEmpty()) { Files.list(TwilightComponent.DEFAULT_UI_ENTRY).use { defaultUIFilePaths -> - defaultUISaveStore.addAll(defaultUIFilePaths.filter { defaultUIFilePath -> - FilenameUtils.isExtension( - defaultUIFilePath.fileName.toString(), - "zip" - ) + defaultUINames.addAll(defaultUIFilePaths.map { + it.nameWithoutExtension }.toList()) } } else { @@ -213,17 +195,16 @@ return } } - val saveBundleID = UUID.randomUUID().toString() - savingDefaultUIIDs.add(saveBundleID) - defaultUISaveStore.poll().let { + defaultUINames.poll().let { if (it != null) { - val bundleFileName = it.fileName.toString() - val targetDefaultUI = FilenameUtils.removeExtension(bundleFileName) - val saveDefaultUIChannel = AsynchronousFileChannel.open(it) + val saveBundleID = UUID.randomUUID().toString() + val bundleFileName = "$it.zip" + val bundleFilePath = TwilightComponent.DEFAULT_UI_ENTRY.resolve(bundleFileName) + val fileChannel = AsynchronousFileChannel.open(bundleFilePath) savingBundleIOs[saveBundleID] = BundleIO( + bundleFilePath, + fileChannel, it, - saveDefaultUIChannel, - targetDefaultUI, BundleVariety.DEFAULT_UI, "", bundleFileName, @@ -233,15 +214,10 @@ EventOuterClass.Event.EventID.SAVE_BUNDLE, object { val bundleID = saveBundleID - val bundleVariety = BundleVariety.DEFAULT_UI.value - val bundleLength = saveDefaultUIChannel.size() + val bundleVariety = BundleVariety.DEFAULT_UI + val bundleLength = fileChannel.size() } ) - } else { - send( - EventOuterClass.Event.EventID.NOTIFY_INFO, - translateLanguage("savedDefaultUI") - ) } } } @@ -372,12 +348,12 @@ val etc = text.etc fun saveAsBundle(bundleEntryPath: Path, saveAsBundleName: String, saveAsBundleID: String) { - if (hasAvailableCount()) { + if (hasAvailableBundleIOs()) { if (!Files.isDirectory(bundleEntryPath)) { Files.createDirectories(bundleEntryPath) } val bundleFilePath = bundleEntryPath.resolve("$saveAsBundleName.tmp") - savingAsBundleIOs[saveAsBundleID] = BundleIO( + savingBundleIOs[saveAsBundleID] = BundleIO( bundleFilePath, AsynchronousFileChannel.open( bundleFilePath, @@ -434,8 +410,7 @@ } EventOuterClass.Event.EventID.SAVING_AS_BUNDLE -> wantEstablished { - val savingAsBundleIOs = savingAsBundleIOs - savingAsBundleIOs[eventText]?.let { + savingBundleIOs[eventText]?.let { val savingAsBundleData = eventData[0].asReadOnlyByteBuffer() it.fileChannel.write( savingAsBundleData, @@ -445,25 +420,27 @@ override fun completed(result: Int, attachment: BundleIO) = Unit override fun failed(exc: Throwable, attachment: BundleIO) { - savingAsBundleIOs.remove(eventText)?.use { - logFault(exc) - } + savingBundleIOs.remove(eventText)?.close() + logFault(exc) } }) - it.saveFilePosition(savingAsBundleData.capacity()) + if (it.saveFilePosition(savingAsBundleData.capacity())) { + savingBundleIOs.remove(eventText)?.close() + send(EventOuterClass.Event.EventID.STOP_SAVING_AS_BUNDLE, eventText) + } } } EventOuterClass.Event.EventID.STOP_SAVING_AS_BUNDLE -> wantEstablished { - savingAsBundleIOs.remove(eventText)?.close() + savingBundleIOs.remove(eventText)?.close() } EventOuterClass.Event.EventID.SAVED_AS_BUNDLE -> wantEstablished { avatarID -> - savingAsBundleIOs.remove(eventText)?.let { bundleIO -> - bundleIO.fileChannel.write( + savingBundleIOs.remove(eventText)?.let { savingBundleIO -> + savingBundleIO.fileChannel.write( eventData[0].asReadOnlyByteBuffer(), - bundleIO.filePosition.toLong(), - bundleIO, + savingBundleIO.filePosition.toLong(), + savingBundleIO, object : CompletionHandler { override fun completed(result: Int, attachment: BundleIO) { attachment.use { @@ -472,7 +449,6 @@ val bundleVariety = it.bundleVariety if (bundleVariety == BundleVariety.NET) { it.setFileVariety() - send(EventOuterClass.Event.EventID.SAVED_AS_BUNDLE, eventText) val bundleFileName = it.bundleFileName SiteHandler.putSiteYell( this@QwilightAvatar, @@ -490,11 +466,7 @@ ) } else { val bundleLength = it.getBundleLength() - if (DB.isBundleLengthAvailable( - avatarID, - bundleLength - ) - ) { + if (DB.isBundleLengthAvailable(avatarID, bundleLength)) { it.setFileVariety() DB.saveBundle( avatarID, @@ -530,7 +502,7 @@ EventOuterClass.Event.EventID.SAVE_BUNDLE -> wantEstablished { avatarID -> val text = jm.readValue(eventText, JSON.QwilightSaveBundle::class.java) val etc = text.etc - if (hasAvailableCount()) { + if (hasAvailableBundleIOs()) { if (Utility.isEtcNetBundle(etc)) { val bundleFileName = etc + BundleVariety.NET.fileVariety val bundleFilePath = TwilightComponent.BUNDLE_ENTRY_PATH.resolve(bundleFileName) @@ -548,7 +520,7 @@ EventOuterClass.Event.EventID.SAVE_BUNDLE, object { val bundleID = etc - val bundleVariety = BundleVariety.NET.value + val bundleVariety = BundleVariety.NET val bundleLength = fileChannel.size() } ) @@ -638,13 +610,12 @@ } EventOuterClass.Event.EventID.SAVING_BUNDLE -> wantEstablished { - val savingBundleIOs = savingBundleIOs - savingBundleIOs[eventText]?.let { bundleIO -> - val savingBundleData = bundleIO.data - bundleIO.fileChannel.read( + savingBundleIOs[eventText]?.let { savingBundleIO -> + val savingBundleData = savingBundleIO.data + savingBundleIO.fileChannel.read( savingBundleData, - bundleIO.filePosition.toLong(), - bundleIO, + savingBundleIO.filePosition.toLong(), + savingBundleIO, object : CompletionHandler { override fun completed(result: Int, attachment: BundleIO) { attachment.saveFilePosition(result) @@ -669,38 +640,41 @@ } } } else { - savingBundleIOs[eventText]?.use { - send( - EventOuterClass.Event.EventID.SAVED_BUNDLE, - object { - val bundleID = eventText - val bundleVariety = it.bundleVariety.value - val bundleName = it.bundleName - val etc = it.etc - }, - ByteString.copyFrom(savingBundleData.flip()) - ).addListener { future -> - if (future.isSuccess) { - savingBundleIOs.remove(eventText)?.close() - when (it.bundleVariety) { + savingBundleIO.close() + send( + EventOuterClass.Event.EventID.SAVED_BUNDLE, + object { + val bundleID = eventText + val bundleVariety = savingBundleIO.bundleVariety + val bundleName = savingBundleIO.bundleName + val etc = savingBundleIO.etc + @JvmField + val isLastDefault = when (savingBundleIO.bundleVariety) { + BundleIO.BundleVariety.DEFAULT_NOTE -> defaultNoteNames.isEmpty() + BundleIO.BundleVariety.DEFAULT_UI -> defaultUINames.isEmpty() + else -> false + } + }, + ByteString.copyFrom(savingBundleData.flip()) + ).addListener { future -> + if (future.isSuccess) { + savingBundleIOs.remove(eventText)?.let { savingBundleIO -> + when (savingBundleIO.bundleVariety) { BundleIO.BundleVariety.DEFAULT_NOTE -> saveDefaultNote("") BundleIO.BundleVariety.DEFAULT_UI -> saveDefaultUI(false.toString()) else -> Unit } - } else { - failed(future.cause(), attachment) } + } else { + failed(future.cause(), attachment) } } } } override fun failed(exc: Throwable, attachment: BundleIO) { - savingBundleIOs.remove(eventText)?.let { bundleIO -> - bundleIO.use { - logFault(exc) - } - } + savingBundleIOs.remove(eventText)?.close() + logFault(exc) } }) } @@ -708,11 +682,10 @@ EventOuterClass.Event.EventID.STOP_SAVING_BUNDLE -> wantEstablished { savingBundleIOs.remove(eventText)?.use { - if (savingDefaultNoteIDs.remove(eventText)) { - defaultNoteSaveStore.clear() - } - if (savingDefaultUIIDs.remove(eventText)) { - defaultUISaveStore.clear() + when (it.bundleVariety) { + BundleVariety.DEFAULT_NOTE -> defaultNoteNames.clear() + BundleVariety.DEFAULT_UI -> defaultUINames.clear() + else -> Unit } } } @@ -1352,10 +1325,11 @@ AvatarHandler.getAvatar(it)?.send( EventOuterClass.Event.newBuilder().apply { eventID = EventOuterClass.Event.EventID.IO_MULTIPLIER - twilightIOMultiplier = EventOuterClass.Event.TwilightIOMultiplier.newBuilder().apply { - handlerID = qwilightIOMultiplier.handlerID - multiplier = qwilightIOMultiplier.multiplier - }.build() + twilightIOMultiplier = + EventOuterClass.Event.TwilightIOMultiplier.newBuilder().apply { + handlerID = qwilightIOMultiplier.handlerID + multiplier = qwilightIOMultiplier.multiplier + }.build() }.build() ) } diff --git a/src/main/kotlin/net/taehui/twilight/system/DB.kt b/src/main/kotlin/net/taehui/twilight/system/DB.kt index 976d83d..cb3a57f 100644 --- a/src/main/kotlin/net/taehui/twilight/system/DB.kt +++ b/src/main/kotlin/net/taehui/twilight/system/DB.kt @@ -1327,7 +1327,7 @@ } fun isBundleLengthAvailable(avatarID: String, bundleLength: Long): Boolean { - pool.connection.use { + return pool.connection.use { it.prepareStatement( """ SELECT SUM(Length) AS Length @@ -1337,7 +1337,7 @@ ).use { dbStatement -> dbStatement.setString(1, avatarID) dbStatement.executeQuery() - .use { rows -> return rows.next() && bundleLength + rows.getLong("Length") < 5000000000 } + .use { rows -> rows.next() && bundleLength + rows.getLong("Length") < TwilightComponent.BUNDLE_LENGTH } } } } diff --git a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt index 5cd0950..121cb8e 100644 --- a/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/PlatformSystem.kt @@ -127,7 +127,7 @@ qwilightPlatform = platform?.getGuildById(platformClient.qwilight) doCallPlatformAvatars() - qwilightPlatform?.audioManager?.openAudioConnection(qwilightPlatform?.getVoiceChannelById(platformClient.siteAudio)) +// qwilightPlatform?.audioManager?.openAudioConnection(qwilightPlatform?.getVoiceChannelById(platformClient.siteAudio)) } catch (e: Throwable) { logFault(e) } diff --git a/src/main/resources/Language.json b/src/main/resources/Language.json index fc2fa75..8c07793 100644 --- a/src/main/resources/Language.json +++ b/src/main/resources/Language.json @@ -67,14 +67,6 @@ "ko-KR": "공유 받기를 눌러서 %s를 다운로드 받으세요", "en-US": "Click Get Share to download %s" }, - "savedDefaultNote": { - "ko-KR": "모든 기본곡을 성공적으로 받음", - "en-US": "Successfully received all basic songs" - }, - "savedDefaultUI": { - "ko-KR": "모든 추가 스킨을 성공적으로 받음", - "en-US": "Successfully received all additional skins" - }, "signInAsEnter": { "ko-KR": "이 방에 참가하려면 먼저 로그인하세요", "en-US": "Please log in first to join this room"