diff --git a/src/commonMain/kotlin/teksturepako/pakku/Main.kt b/src/commonMain/kotlin/teksturepako/pakku/Main.kt index 7977bc5..05bde2a 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/Main.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/Main.kt @@ -8,8 +8,8 @@ import com.github.ajalt.mordant.terminal.Terminal import com.github.michaelbull.result.get import com.github.michaelbull.result.onFailure import kotlinx.coroutines.runBlocking -import teksturepako.pakku.api.executePakku -import teksturepako.pakku.api.initPakku +import teksturepako.pakku.api.http.client +import teksturepako.pakku.api.pakku import teksturepako.pakku.api.platforms.CURSEFORGE_API_KEY import teksturepako.pakku.api.platforms.CurseForge import teksturepako.pakku.api.platforms.Modrinth @@ -23,31 +23,30 @@ fun main(args: Array) { println() - initPakku { + pakku { curseForge(apiKey = System.getenv("CURSEFORGE_API_KEY") ?: CURSEFORGE_API_KEY) withUserAgent("Pakku/$VERSION (github.com/juraj-hrivnak/Pakku)") } - executePakku { - // Read 'cli-config.json' - val cliConfig = runBlocking { CliConfig.readToResult() } - .onFailure { error -> debug { println(error.rawMessage) } } - .get() + // Read 'cli-config.json' + val cliConfig = runBlocking { CliConfig.readToResult() } + .onFailure { error -> debug { println(error.rawMessage) } } + .get() - Pakku().context { - terminal = cliConfig?.toTerminal() ?: Terminal(theme = CliThemes.Default) - }.subcommands( - Init(), Import(), Add(), Rm(), Cfg(), Set(), Status(), Update(), Ls(), Fetch(), Sync(), Link(), Export(), - Diff() - ).main(args) + Pakku().context { + terminal = cliConfig?.toTerminal() ?: Terminal(theme = CliThemes.Default) + }.subcommands( + Init(), Import(), Add(), Rm(), Cfg(), Set(), Status(), Update(), Ls(), Fetch(), Sync(), Link(), Export(), + Diff() + ).main(args) - // Check Modrinth's rate limit - Modrinth.checkRateLimit() + // Check Modrinth's rate limit + Modrinth.checkRateLimit() - debug { CurseForge.checkApiKey() } - } + debug { CurseForge.checkApiKey() } debug { println("Program arguments: ${args.joinToString()}") } + client.close() exitProcess(0) } diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/PakkuApi.kt b/src/commonMain/kotlin/teksturepako/pakku/api/PakkuApi.kt index e8f4539..581383b 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/PakkuApi.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/PakkuApi.kt @@ -1,33 +1,36 @@ package teksturepako.pakku.api -import teksturepako.pakku.api.http.client import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes object PakkuApi { data class Configuration( - internal var developmentMode: Boolean = false, - internal var curseForgeApiKey: String? = null, - internal var userAgent: String? = null, - internal var timeout: Duration = 3.minutes, + var developmentMode: Boolean = false, + var curseForgeApiKey: String? = null, + var userAgent: String? = null, + var timeout: Duration = 3.minutes, ) { + /** Enables development mode for testing purposes. */ fun developmentMode() { this.developmentMode = true } + /** Sets the CurseForge API key for authentication. */ fun curseForge(apiKey: String) { this.curseForgeApiKey = apiKey } + /** Sets the user agent for HTTP requests. */ fun withUserAgent(agent: String) { this.userAgent = agent } + /** Sets the timeout duration for HTTP requests. */ fun withTimeout(timeout: Duration) { this.timeout = timeout @@ -35,24 +38,21 @@ object PakkuApi internal fun init() { - configuration?.let { config -> - if (developmentMode) - { - println("Pakku is running in development mode") - } - else - { - requireNotNull(config.curseForgeApiKey) { "curseForgeApiKey must be specified" } - requireNotNull(config.userAgent) { "userAgent must be specified" } - } - } ?: throw IllegalStateException("PakkuApi must be configured before use") + if (configuration?.developmentMode == true) + { + println("Pakku is running in development mode") + } + else + { + requireNotNull(configuration?.curseForgeApiKey) { "curseForgeApiKey must be specified" } + requireNotNull(configuration?.userAgent) { "userAgent must be specified" } + } } } - var configuration: Configuration? = null - private set - get() = field?.copy() + private var configuration: Configuration? = null + @Throws(IllegalStateException::class) internal fun configure(block: Configuration.() -> Unit) { if (configuration == null) @@ -62,21 +62,25 @@ object PakkuApi } } - fun isConfigured(): Boolean = configuration != null -} + /** Indicates whether development mode is enabled. */ + internal val developmentMode: Boolean + get() = configuration?.developmentMode ?: false -fun initPakku(block: PakkuApi.Configuration.() -> Unit) -{ - PakkuApi.configure(block) + /** The CurseForge API key used for authentication. */ + internal val curseForgeApiKey: String? + get() = configuration?.curseForgeApiKey + + /** The user agent used for HTTP requests. */ + internal val userAgent: String? + get() = configuration?.userAgent + + /** The timeout duration for HTTP requests. */ + internal val timeout: Duration + get() = configuration?.timeout ?: 3.minutes } -fun executePakku(block: () -> Unit): Boolean +/** Initializes Pakku with the provided configuration. */ +fun pakku(block: PakkuApi.Configuration.() -> Unit) { - if (PakkuApi.isConfigured()) - { - block() - client.close() - } - - return PakkuApi.isConfigured() + PakkuApi.configure(block) } diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/http/HttpClient.kt b/src/commonMain/kotlin/teksturepako/pakku/api/http/HttpClient.kt index b04539b..2a7e1ca 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/http/HttpClient.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/http/HttpClient.kt @@ -6,7 +6,6 @@ import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import kotlinx.serialization.json.Json import teksturepako.pakku.api.PakkuApi -import kotlin.time.Duration.Companion.minutes import kotlin.time.toJavaDuration val client = HttpClient(OkHttp) { @@ -14,19 +13,19 @@ val client = HttpClient(OkHttp) { Json } install(HttpTimeout) { - val timeout = PakkuApi.configuration?.timeout?.inWholeMilliseconds + val timeout = PakkuApi.timeout.inWholeMilliseconds socketTimeoutMillis = timeout requestTimeoutMillis = timeout connectTimeoutMillis = timeout } install(UserAgent) { - PakkuApi.configuration?.userAgent?.let { agent = it } + PakkuApi.userAgent?.let { agent = it } } engine { pipelining = true config { - val timeout = PakkuApi.configuration?.timeout?.toJavaDuration() ?: 1.minutes.toJavaDuration() + val timeout = PakkuApi.timeout.toJavaDuration() retryOnConnectionFailure(true) diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt index 24da349..dcb0c5f 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt @@ -42,7 +42,7 @@ object CurseForge : Platform( private const val API_KEY_HEADER = "x-api-key" - private val apiKey: String? = PakkuApi.configuration?.curseForgeApiKey?.takeIf { it.isNotBlank() } + private val apiKey: String? = PakkuApi.curseForgeApiKey?.takeIf { it.isNotBlank() } fun checkApiKey() { diff --git a/src/commonTest/kotlin/teksturepako/pakku/PakkuTest.kt b/src/commonTest/kotlin/teksturepako/pakku/PakkuTest.kt index 1f3a691..1bfd4b7 100644 --- a/src/commonTest/kotlin/teksturepako/pakku/PakkuTest.kt +++ b/src/commonTest/kotlin/teksturepako/pakku/PakkuTest.kt @@ -3,7 +3,7 @@ package teksturepako.pakku import kotlinx.coroutines.runBlocking import teksturepako.pakku.api.data.generatePakkuId import teksturepako.pakku.api.data.workingPath -import teksturepako.pakku.api.initPakku +import teksturepako.pakku.api.pakku import java.nio.file.Path import kotlin.io.path.* import kotlin.test.AfterTest @@ -41,7 +41,7 @@ open class PakkuTest @BeforeTest fun `set-up-test`() { - initPakku { + pakku { developmentMode() } diff --git a/src/commonTest/kotlin/teksturepako/pakku/api/export/CfModpackModelTest.kt b/src/commonTest/kotlin/teksturepako/pakku/api/export/CfModpackModelTest.kt index 3006723..dcecc45 100644 --- a/src/commonTest/kotlin/teksturepako/pakku/api/export/CfModpackModelTest.kt +++ b/src/commonTest/kotlin/teksturepako/pakku/api/export/CfModpackModelTest.kt @@ -25,31 +25,6 @@ import kotlin.test.assertNotNull class CfModpackModelTest : PakkuTest() { - private val modpackName = "CurseForgeProfileTestModpack" - - private val greeneryCfId = 574029 - private val greeneryCfFileId = 5913357 - - private val greeneryProject = Project( - type = ProjectType.MOD, - id = mutableMapOf(CurseForge.serialName to greeneryCfId.toString()), - name = mutableMapOf(CurseForge.serialName to "Greenery\uD83C\uDF3F"), - slug = mutableMapOf(CurseForge.serialName to "greenery"), - files = mutableSetOf( - ProjectFile( - type = CurseForge.serialName, - fileName = "Greenery-1.12.2-7.0.jar", - mcVersions = mutableListOf("1.12.2", "1.12.1", "1.12"), - loaders = mutableListOf("forge"), - id = greeneryCfFileId.toString(), - parentId = greeneryCfId.toString(), - ) - ) - ) - - private val mcVersion = "1.12.2" - private val forgeVersion = "xxx.xxx.xxx" - override suspend fun `set-up`() { val lockFile = LockFile( @@ -77,6 +52,31 @@ class CfModpackModelTest : PakkuTest() } } + private val modpackName = "CurseForgeProfileTestModpack" + + private val greeneryCfId = 574029 + private val greeneryCfFileId = 5913357 + + private val greeneryProject = Project( + type = ProjectType.MOD, + id = mutableMapOf(CurseForge.serialName to greeneryCfId.toString()), + name = mutableMapOf(CurseForge.serialName to "Greenery\uD83C\uDF3F"), + slug = mutableMapOf(CurseForge.serialName to "greenery"), + files = mutableSetOf( + ProjectFile( + type = CurseForge.serialName, + fileName = "Greenery-1.12.2-7.0.jar", + mcVersions = mutableListOf("1.12.2", "1.12.1", "1.12"), + loaders = mutableListOf("forge"), + id = greeneryCfFileId.toString(), + parentId = greeneryCfId.toString(), + ) + ) + ) + + private val mcVersion = "1.12.2" + private val forgeVersion = "xxx.xxx.xxx" + @Test fun `test cf modpack model in cache`() {