diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-08-03 00:40:20 +0900 |
|---|---|---|
| committer | Sho Sakuma <me@m1sk9.dev> | 2026-08-05 00:42:22 +0900 |
| commit | e8b44cf42888cc00c67d885c3d641ca1a8f78034 (patch) | |
| tree | c71efd14f5c492fa8003a6ac527dd9d7849f6bb5 | |
| parent | 9a57b249dd660c49ac968ab2d3246736772504e1 (diff) | |
| download | LunaticChat-e8b44cf42888cc00c67d885c3d641ca1a8f78034.tar.gz LunaticChat-e8b44cf42888cc00c67d885c3d641ca1a8f78034.tar.bz2 LunaticChat-e8b44cf42888cc00c67d885c3d641ca1a8f78034.zip | |
perf: stop paying at startup for features that are off
Both HTTP consumers - Japanese conversion and the update check - default
to disabled, yet onEnable built an HttpClient(CIO) unconditionally,
starting a selector and dispatcher pool that a stock install never used
and nothing ever closed. It is now created on first use and closed on
disable, which also fixes the leak across /reload.
LanguageManager parsed and flattened every bundled language file, though
getMessage only ever reads the selected one and the English fallback. It
now loads exactly those two.
Co-Authored-By: Claude <noreply@anthropic.com>
4 files changed, 25 insertions, 11 deletions
diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/LunaticChat.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/LunaticChat.kt index 5b8cab1..7b2f3a0 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/LunaticChat.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/LunaticChat.kt @@ -45,6 +45,10 @@ class LunaticChat : private val updateAvailable = AtomicBoolean(false) + // Only the Japanese conversion and update-check features make HTTP calls, and both default + // to off, so a stock install should not pay for a CIO engine and its thread pool. + private val httpClient = lazy { HttpClient(CIO) } + override fun onEnable() { saveDefaultConfig() val configManager = ConfigManager() @@ -55,8 +59,6 @@ class LunaticChat : logger.info("Debug: $configuration") } - val httpClient = HttpClient(CIO) - // Initialize plugin coroutine scope pluginScope = PluginCoroutineScope(logger) @@ -79,7 +81,7 @@ class LunaticChat : // Check for updates if (configuration.checkForUpdates) { - initializeUpdateChecker(httpClient) + initializeUpdateChecker(httpClient.value) } logger.info("LunaticChat enabled.") @@ -88,6 +90,7 @@ class LunaticChat : override fun onDisable() { pluginScope.cancel() serviceInitializer.shutdown(services) + if (httpClient.isInitialized()) httpClient.value.close() logger.info("LunaticChat disabled.") } diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/ServiceInitializer.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/ServiceInitializer.kt index c118c12..6d47788 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/ServiceInitializer.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/ServiceInitializer.kt @@ -48,7 +48,7 @@ private data class ChannelComponents( class ServiceInitializer( private val plugin: JavaPlugin, private val configuration: LunaticChatConfiguration, - private val httpClient: HttpClient, + private val httpClient: Lazy<HttpClient>, private val logger: Logger, ) { private val handshakeCompleted = AtomicBoolean(false) @@ -195,7 +195,7 @@ class ServiceInitializer( val apiClient = GoogleIMEClient( timeout = configuration.features.japaneseConversion.apiTimeout.milliseconds, - httpClient = httpClient, + httpClient = httpClient.value, ) // Initialize Romanji converter diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManager.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManager.kt index dd702ba..19774d2 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManager.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManager.kt @@ -37,13 +37,16 @@ class LanguageManager( private val languageCache = mutableMapOf<Language, Map<String, String>>() /** - * Initializes the language manager by loading all language files. + * Initializes the language manager by loading the languages [getMessage] can read: the + * selected one and the English fallback. Other bundled languages are never consulted, so + * parsing and flattening them at startup would be wasted work. + * * This should be called during plugin initialization. * * @throws IllegalStateException if the English fallback file is missing or cannot be loaded */ fun initialize() { - Language.entries.forEach { lang -> + linkedSetOf(Language.EN, selectedLanguage).forEach { lang -> try { val messages = loadLanguageFile(lang) languageCache[lang] = messages diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManagerTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManagerTest.kt index 158d985..6774be8 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManagerTest.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/LanguageManagerTest.kt @@ -63,13 +63,21 @@ class LanguageManagerTest { } @Test - fun `initialize should load both language files`() { - val (manager, logger) = createLanguageManager(Language.EN) + fun `initialize should load the selected language alongside the English fallback`() { + val (manager, logger) = createLanguageManager(Language.JA) manager.initialize() - // Both en.yml and ja.yml should be loaded - assertTrue(logger.infoMessages.any { it.contains("en.yml") }) assertTrue(logger.infoMessages.any { it.contains("ja.yml") }) + assertTrue(logger.infoMessages.any { it.contains("en.yml") }) + } + + @Test + fun `initialize should not load languages that cannot be read`() { + val (manager, logger) = createLanguageManager(Language.EN) + manager.initialize() + + // English is both the selection and the fallback, so nothing else is worth parsing. + assertTrue(logger.infoMessages.none { it.contains("ja.yml") }) } @Test |
