Peanuuutz / tomlkt

Multiplatform TOML library with builtin support for kotlinx.serialization
Apache License 2.0
117 stars 5 forks source link

ArrayIndexOutOfBoundsException trying to deserialize file that was created by serializing the same object #72

Open Vodes opened 4 days ago

Vodes commented 4 days ago
> Task :app:run FAILED
2024-11-30 19:34:05 - [W] - Config File has been created at: C:\Users\Alex\AppData\Roaming\Styx-Server\config.toml
Please do the necessary edits.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
        at net.peanuuutz.tomlkt.TomlElementKt.getByPathRecursively(TomlElement.kt:1486)
        at net.peanuuutz.tomlkt.TomlElementKt.get(TomlElement.kt:1175)
        at net.peanuuutz.tomlkt.Toml.decodeFromString(Toml.kt:178)
        at moe.styx.common.config.UnifiedConfig$Companion.getCurrent(UnifiedConfig.kt:287)
        at org.example.AppKt.main(App.kt:12)
        at org.example.AppKt.main(App.kt)
Generated File ```toml [General] # Enable or disable debug logging. Will prefer 'DEBUG' env variable if any. debug = false # Base URL for styx-web. Will prefer 'BASE_URL' env variable if any. siteBaseURL = "https://example.com" # Base URL for styx-api. Will prefer 'API_BASE_URL' env variable if any. apiBaseURL = "https://api.example.com" # Base URL for the images directory. Will prefer 'IMAGE_URL' env variable if any. # You can leave this empty and use the API for image access under 'apiBaseURL/image/file.ext' but it will be slower than a good webserver. imageBaseURL = "https://images.example.com" # Directory containing all the images. Will prefer 'IMAGE_DIR' env variable if any. imageDir = "/images" # Directory containing all the desktop app builds. Will prefer 'BUILD_DIR' env variable if any. buildDir = "/builds" # Directory containing all the android app builds. Will prefer 'ANDROID_BUILD_DIR' env variable if any. androidBuildDir = "/android-builds" # Directory containing all the mpv bundles. Will prefer 'MPV_DIR' env variable if any. mpvDir = "/mpv" # User-Agent used for all outgoing http requests. Will prefer 'USER_AGENT' env variable if any. httpUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" # themoviedb.org API Token. Will prefer 'TMDB_TOKEN' env variable if any. tmdbToken = "" [Database-Config] # Host or IP of the database. Will prefer 'DB_HOST' env variable if any. host = "" # Username for the database. Will prefer 'DB_USER' env variable if any. user = "" # Password for the database. Will prefer 'DB_PASS' env variable if any. pass = "" [StyxWeb-Config] # Host to bind for styx-web. # Leaving this empty assumes 0.0.0.0 when running in a docker and localhost otherwise. serveHost = "" # Port to bind for styx-web. servePort = 8080 # Discord Auth Token to be used, essentially skipping login. DO NOT USE ON PUBLICLY HOSTED INSTANCES. debugAuthToken = "" [StyxAPI-Config] # Host to bind for styx-api. # Leaving this empty assumes 0.0.0.0 when running in a docker and localhost otherwise. serveHost = "" # Port to bind for styx-api. servePort = 8081 # Enable or disable checking the APPSECRET that clients use as verification that a build is legitimate. # Secrets are to be put in a 'SECRETS' file in the same directory as this config. # Just plain text and each line is a separate secret. enableSecretsCheck = true # Nginx Access Log file used for traffic logging. Leaving this empty just disables the functionality. # Recommended to create a separate one and filter it to /watch routes to not parse too much useless data. nginxLogFile = "" [Discord-Config] # Discord Bot Token used for the downloader to notify about new episodes. # Will prefer 'DISCORD_TOKEN' env variable if any. botToken = "" # Channel where some backend logs like new devices being added etc. are posted to. # In the format: https://discord.com/channels// # Will prefer 'LOG_CHANNEL_URL' env variable if any. logChannelURL = "" # The channel announcements for new episodes will be posted in. # In the format: https://discord.com/channels// # Will prefer 'DISCORD_CHANNEL_URL' env variable if any. announcementChannelURL = "" # The role ID that users should have if they should be pinged in the channel for new episodes of favourites. # Will prefer 'DISCORD_PING_ROLE' env variable if any. announcementPingRole = "" # The role ID that users should have if they should be directly messaged by the bot for new episodes of favourites. # Will prefer 'DISCORD_DM_ROLE' env variable if any. announcementDmRole = "" # Used by styx-web for manual imports. Should ideally be in the same channel as the one above. # Will prefer 'DISCORD_WEBHOOK' env variable if any. announcementWebhookURL = "" # Used by styx-dl to show the current schedule in a message. # If this is a channel URL it will post a new message in that channel and update the config accordingly. # Will prefer 'DISCORD_SCHEDULE_MSG' env variable if any. scheduleMessageURL = "" # Client ID used for authentication. Will prefer 'DISCORD_CLIENT_ID' env variable if any. discordClientID = "" # Client Secret used for authentication. Will prefer 'DISCORD_CLIENT_SECRET' env variable if any. discordClientSecret = "" [Downloader-Config] # Ignore episodes like 'One Piece - Egghead SP1' or 'One Piece E1078.5' ignoreSpecialsAndPoint5 = true # FTP Connection used if there isn't any explicitly passed in the downloader option. defaultFTPConnectionString = "" [Downloader-Config.RSS-Config] # Directory where only temporary downloads will go to. tempDir = "" # Directory where downloads will be kept for seeding. seedDir = "" # Templates you can use in torrent/usenet options as shortcuts for feeds to check. # Do not include a query string in templates if you want to use dynamic queries in the webui! # '%tosho%my hero academia' would result in 'https://feed.animetosho.org/rss2?q=my+hero+academia' [Downloader-Config.RSS-Config.feedTemplates] tosho = "https://feed.animetosho.org/rss2" [Downloader-Config.Torrent-Client] # Type of torrent client, can be Flood or Transmission. clientType = "Transmission" # URL to the client. clientURL = "" # Username used for the client. clientUser = "" # Password used for the client. clientPass = "" [Downloader-Config.SABnzbd-Client] # URL to the SABnzbd instance. sabURL = "" # API-Key for the instance. sabApiKey = "" [Downloader-Config.IRC-Config] # Whitelisted XDCC Bots to listen for. whitelistedXDCCBots = [ "StyxXDCC", "CR-ARUTHA|NEW" ] # A map of server host and the channels to be listened to. [Downloader-Config.IRC-Config.servers] "irc.rizon.net" = [ "#subsplease", "#Styx-XDCC" ] ```

Also passes this linter for what it's worth.

Sample to test with is here: https://github.com/Vodes/Tomlkt-Sample/

The object I'm using is here: https://github.com/Vodes/Styx-Common/blob/0.4.1/styx-common/src/jvmMain/kotlin/moe/styx/common/config/UnifiedConfig.kt


My current (stupid) workaround is to just use ktoml for reading the file and tomlkt for writing it (because the former seemingly does not support writing comments and I really like that feature)

Peanuuutz commented 3 days ago

OK I almost didn't figure out the problem. It's this import that causes the exception:

import net.peanuuutz.tomlkt.decodeFromString

It refers to this declaration:

public inline fun <reified T> Toml.decodeFromString(
    string: String,
    vararg keys: Any?
): T

Which means there's a hidden empty array passed into the keys parameter. Such a footgun. :P

Change that import to this should fix your problem:

import kotlinx.serialization.decodeFromString

I'm gonna add an empty array check inside that get overload.

Vodes commented 3 days ago

Interesting. I thought I already tried that but alas. Thanks for the quick turnaround anyhow.