Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Kotlin Multiplatform Support to koin-ktor Module #1891

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/quickstart/ktor.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Let's go 🚀

First, add the Koin dependency like below:

For JVM applications:
```kotlin
dependencies {
// Koin for Kotlin apps
Expand All @@ -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:
Expand Down
19 changes: 19 additions & 0 deletions docs/setup/koin.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/support/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ interface KoinContext {
*/
fun getOrNull(): Koin?

/**
* Get Koin Application instance
*/
fun getKoinApplicationOrNull(): KoinApplication?

/**
* Stop current Koin instance
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion projects/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 32 additions & 18 deletions projects/ktor/koin-ktor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
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<KotlinCompile>().all {
kotlinOptions {
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<Jar> 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"))
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,7 +25,7 @@ class Bar2(val name: String = "")
@OptIn(KoinReflectAPI::class)
class KoinFeatureTest {

@After
@AfterTest
fun after(){
stopKoin()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -73,7 +72,7 @@ class KoinPluginRunTest {
}

val s = embeddedServer(
Netty,
CIO,
module = {
val test by inject<String>()
println(test)
Expand All @@ -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<Unit> {
val koinModule = module {
single<String> {
"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 }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Unit> {
val koinModule = module {
single<String> {
"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()
}
}