diff --git a/docs/quickstart/ktor.md b/docs/quickstart/ktor.md index 5806c43d7..ba440ee74 100755 --- a/docs/quickstart/ktor.md +++ b/docs/quickstart/ktor.md @@ -16,6 +16,7 @@ Let's go 🚀 First, add the Koin dependency like below: +For JVM applications: ```kotlin dependencies { // Koin for Kotlin apps @@ -24,6 +25,24 @@ dependencies { } ``` +For Multiplatform applications: +```kotlin +kotlin { + sourceSets { + commonMain.dependencies { + // Koin for Ktor + implementation("io.insert-koin:koin-ktor:$koin_ktor") + } + + // Optional + jvmMain.dependencies { + // SLF4J Logger + implementation("io.insert-koin:koin-logger-slf4j:$koin_ktor") + } + } +} +``` + ## Application Overview The idea of the application is to manage a list of users, and display it in our `UserApplication` class: diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 5e18503be..7860918f0 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -185,6 +185,25 @@ dependencies { } ``` +If you are using Kotlin Multiplatform: +```kotlin +kotlin { + sourceSets { + commonMain.dependencies { + // Koin for Ktor + implementation("io.insert-koin:koin-ktor:$koin_ktor") + } + + // Optional + jvmMain.dependencies { + // SLF4J Logger + implementation("io.insert-koin:koin-logger-slf4j:$koin_ktor") + } + } +} +``` + + You are now ready to install Koin feature into your Ktor application: ```kotlin diff --git a/docs/support/index.md b/docs/support/index.md index 2257aa91f..72d73e89d 100644 --- a/docs/support/index.md +++ b/docs/support/index.md @@ -9,7 +9,7 @@ The Koin team is leading its development with open-source and community-driven a We drive our developments with release cycles of 6 months to follow Kotlin language and library updates in a consistent manner. We will use beta periods of 6 weeks or more, to help gather first feedbacks. -Once a new version is released, we start the Community support phase for 6 months minimum. During that phase, we are actively gathering feedbacks, following all updates impacting our framework, like librairies, Kotling Android, Ktor and others frameworks versions. +Once a new version is released, we start the Community support phase for 6 months minimum. During that phase, we are actively gathering feedbacks, following all updates impacting our framework, like libraries, Kotlin Android, Ktor and others frameworks versions. ## Establishing Roadmap with Structured Versions diff --git a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/context/KoinContext.kt b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/context/KoinContext.kt index 70ab2121f..9a823079d 100644 --- a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/context/KoinContext.kt +++ b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/context/KoinContext.kt @@ -37,6 +37,11 @@ interface KoinContext { */ fun getOrNull(): Koin? + /** + * Get Koin Application instance + */ + fun getKoinApplicationOrNull(): KoinApplication? + /** * Stop current Koin instance */ diff --git a/projects/core/koin-core/src/jsMain/kotlin/org/koin/core/context/GlobalContext.kt b/projects/core/koin-core/src/jsMain/kotlin/org/koin/core/context/GlobalContext.kt index 68e5767a5..f5bfcdbc4 100644 --- a/projects/core/koin-core/src/jsMain/kotlin/org/koin/core/context/GlobalContext.kt +++ b/projects/core/koin-core/src/jsMain/kotlin/org/koin/core/context/GlobalContext.kt @@ -36,6 +36,8 @@ object GlobalContext : KoinContext { override fun getOrNull(): Koin? = _koin + override fun getKoinApplicationOrNull(): KoinApplication? = null + private fun register(koinApplication: KoinApplication) { if (_koin != null) { throw ApplicationAlreadyStartedException("A Koin Application has already been started") diff --git a/projects/core/koin-core/src/jvmMain/kotlin/org/koin/core/context/GlobalContext.kt b/projects/core/koin-core/src/jvmMain/kotlin/org/koin/core/context/GlobalContext.kt index 0cf7f219c..ac88e292c 100644 --- a/projects/core/koin-core/src/jvmMain/kotlin/org/koin/core/context/GlobalContext.kt +++ b/projects/core/koin-core/src/jvmMain/kotlin/org/koin/core/context/GlobalContext.kt @@ -37,7 +37,7 @@ object GlobalContext : KoinContext { override fun getOrNull(): Koin? = _koin - fun getKoinApplicationOrNull(): KoinApplication? = _koinApplication + override fun getKoinApplicationOrNull(): KoinApplication? = _koinApplication private fun register(koinApplication: KoinApplication) { if (_koin != null) { diff --git a/projects/core/koin-core/src/nativeMain/kotlin/org/koin/core/context/GlobalContext.kt b/projects/core/koin-core/src/nativeMain/kotlin/org/koin/core/context/GlobalContext.kt index 3e98dd2b3..7f98323a0 100644 --- a/projects/core/koin-core/src/nativeMain/kotlin/org/koin/core/context/GlobalContext.kt +++ b/projects/core/koin-core/src/nativeMain/kotlin/org/koin/core/context/GlobalContext.kt @@ -37,7 +37,7 @@ internal class MutableGlobalContext : KoinContext { override fun getOrNull(): Koin? = _koin - fun getKoinApplicationOrNull(): KoinApplication? = _koinApplication + override fun getKoinApplicationOrNull(): KoinApplication? = _koinApplication private fun register(koinApplication: KoinApplication) { if (_koin != null) { diff --git a/projects/gradle/libs.versions.toml b/projects/gradle/libs.versions.toml index 181b0af37..8ee564233 100644 --- a/projects/gradle/libs.versions.toml +++ b/projects/gradle/libs.versions.toml @@ -55,7 +55,8 @@ androidx-navigation = { module = "androidx.navigation:navigation-fragment-ktx", androidx-workmanager = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-workmanager" } # Ktor ktor-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" } -ktor-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" } +ktor-netty = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } +ktor-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } ktor-testHost = { module = "io.ktor:ktor-server-test-host", version.ref = "ktor" } ktor-slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } # Compose diff --git a/projects/ktor/koin-ktor/build.gradle.kts b/projects/ktor/koin-ktor/build.gradle.kts index 2e1e6ce6f..835d70d6a 100644 --- a/projects/ktor/koin-ktor/build.gradle.kts +++ b/projects/ktor/koin-ktor/build.gradle.kts @@ -1,18 +1,40 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") + alias(libs.plugins.kotlinMultiplatform) } -dependencies { - api(project(":core:koin-core")) - testImplementation(libs.kotlin.test) - testImplementation(libs.test.junit) +kotlin { + jvm { + withJava() + } + + macosX64() + macosArm64() + mingwX64() + linuxX64() + linuxArm64() + + sourceSets { + commonMain.dependencies { + api(project(":core:koin-core")) + + // Ktor + api(libs.ktor.core) + } + + commonTest.dependencies { + implementation(libs.kotlin.test) - // Ktor - api(libs.ktor.core) - testImplementation(libs.ktor.netty) - testImplementation(libs.ktor.testHost) + // Ktor + implementation(libs.ktor.testHost) + implementation(libs.ktor.cio) + } + + jvmTest.dependencies { + implementation(libs.ktor.netty) + } + } } tasks.withType().all { @@ -20,13 +42,5 @@ tasks.withType().all { jvmTarget = "1.8" } } -java { - sourceCompatibility = JavaVersion.VERSION_11 // or the desired Java version - targetCompatibility = JavaVersion.VERSION_11 // or the desired Java version -} -val sourcesJar: TaskProvider by tasks.registering(Jar::class) { - archiveClassifier.set("sources") - from(sourceSets.main.map { it.allSource.sourceDirectories }) -} -apply(from = file("../../gradle/publish-java.gradle.kts")) +apply(from = file("../../gradle/publish.gradle.kts")) diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationExt.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/ApplicationExt.kt similarity index 90% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationExt.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/ApplicationExt.kt index b2de696a2..5d956cf99 100644 --- a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationExt.kt +++ b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/ApplicationExt.kt @@ -17,13 +17,11 @@ package org.koin.ktor.ext import io.ktor.server.application.* import org.koin.core.Koin -import org.koin.core.context.GlobalContext import org.koin.core.parameter.ParametersDefinition import org.koin.core.qualifier.Qualifier -import org.koin.dsl.KoinAppDeclaration import org.koin.ktor.plugin.KOIN_ATTRIBUTE_KEY -import org.koin.ktor.plugin.Koin import org.koin.ktor.plugin.setKoinApplication +import org.koin.mp.KoinPlatformTools /** * Ktor Koin extensions @@ -39,7 +37,8 @@ import org.koin.ktor.plugin.setKoinApplication */ fun Application.getKoin(): Koin = attributes.getOrNull(KOIN_ATTRIBUTE_KEY)?.koin ?: run { - val defaultInstance = GlobalContext.getKoinApplicationOrNull() ?: error("No Koin instance started. Use install(Koin) or startKoin()") + val defaultContext = KoinPlatformTools.defaultContext() + val defaultInstance = defaultContext.getKoinApplicationOrNull() ?: error("No Koin instance started. Use install(Koin) or startKoin()") setKoinApplication(defaultInstance) attributes[KOIN_ATTRIBUTE_KEY].koin } diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/RouteExt.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/RouteExt.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/RouteExt.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/RouteExt.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/RoutingExt.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/RoutingExt.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/RoutingExt.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/ext/RoutingExt.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinApplicationEvents.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinApplicationEvents.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinApplicationEvents.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinApplicationEvents.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinPlugin.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/KoinPlugin.kt diff --git a/projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/RequestScope.kt b/projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/RequestScope.kt similarity index 100% rename from projects/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/RequestScope.kt rename to projects/ktor/koin-ktor/src/commonMain/kotlin/org/koin/ktor/plugin/RequestScope.kt diff --git a/projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt b/projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt similarity index 97% rename from projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt rename to projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt index 72b814fd4..82429d619 100644 --- a/projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt +++ b/projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt @@ -2,15 +2,16 @@ package org.koin.ktor.ext import io.ktor.server.application.* import io.ktor.server.testing.* -import org.junit.After -import org.junit.Assert.* -import org.junit.Test import org.koin.core.annotation.KoinReflectAPI import org.koin.core.context.stopKoin import org.koin.dsl.module import org.koin.ktor.plugin.Koin import org.koin.ktor.plugin.KoinIsolated import org.koin.mp.KoinPlatform +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull /** * @author vinicius @@ -24,7 +25,7 @@ class Bar2(val name: String = "") @OptIn(KoinReflectAPI::class) class KoinFeatureTest { - @After + @AfterTest fun after(){ stopKoin() } diff --git a/projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt b/projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt similarity index 78% rename from projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt rename to projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt index 499dafefe..991685309 100644 --- a/projects/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt +++ b/projects/ktor/koin-ktor/src/commonTest/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt @@ -20,28 +20,27 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.cio.CIO import io.ktor.server.engine.* -import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.testing.* import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeout -import org.junit.Before -import org.junit.Ignore -import org.junit.Test import org.koin.core.context.startKoin import org.koin.core.context.stopKoin import org.koin.core.logger.Level import org.koin.dsl.module import org.koin.ktor.plugin.Koin +import kotlin.test.BeforeTest +import kotlin.test.Ignore +import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue class KoinPluginRunTest { - @Before + @BeforeTest fun before(){ stopKoin() } @@ -73,7 +72,7 @@ class KoinPluginRunTest { } val s = embeddedServer( - Netty, + CIO, module = { val test by inject() println(test) @@ -82,30 +81,7 @@ class KoinPluginRunTest { delay(500) s.stop() - assert(counter == 1){ "counter should 1 - instance is created" } - } - - @Test - @Ignore // socket exception on GH - fun `should can reload`() = runBlocking { - val koinModule = module { - single { - "Reproduction test" - } - } - val s = embeddedServer( - Netty, - module = { - install(Koin) { - modules(koinModule) - } - }, - ).start(false) - delay(500) - - // verify for can auto-reload - (s.environment as ApplicationEngineEnvironmentReloading).reload() - s.stop() + assertTrue("counter should 1 - instance is created") { counter == 1 } } } diff --git a/projects/ktor/koin-ktor/src/jvmTest/kotlin/org/koin/ktor/ext/KoinPluginRunJVMTest.kt b/projects/ktor/koin-ktor/src/jvmTest/kotlin/org/koin/ktor/ext/KoinPluginRunJVMTest.kt new file mode 100644 index 000000000..63c202fe2 --- /dev/null +++ b/projects/ktor/koin-ktor/src/jvmTest/kotlin/org/koin/ktor/ext/KoinPluginRunJVMTest.kt @@ -0,0 +1,47 @@ +package org.koin.ktor.ext + +import io.ktor.server.application.install +import io.ktor.server.cio.CIO +import io.ktor.server.engine.ApplicationEngineEnvironmentReloading +import io.ktor.server.engine.embeddedServer +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.koin.ktor.plugin.Koin +import kotlin.test.BeforeTest +import kotlin.test.Ignore +import kotlin.test.Test + +/** + * @author Rafael Rain + */ +class KoinPluginRunJVMTest { + @BeforeTest + fun before(){ + stopKoin() + } + + @Test + @Ignore // socket exception on GH + fun `should can reload`() = runBlocking { + val koinModule = module { + single { + "Reproduction test" + } + } + val s = embeddedServer( + CIO, + module = { + install(Koin) { + modules(koinModule) + } + }, + ).start(false) + delay(500) + + // verify for can auto-reload + (s.environment as ApplicationEngineEnvironmentReloading).reload() + s.stop() + } +} \ No newline at end of file