Skip to content

Commit

Permalink
first support of iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
lepicekmichal committed Mar 24, 2024
1 parent c2dfbb7 commit c674a5d
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 71 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

![badge-android](http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat)
![badge-jvm](http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat)
![badge-ios](http://img.shields.io/badge/platform-ios-lightgray?style=flat)

SignalR Kore is a client library connecting to ASP.NET Core server for real-time functionality. Enables server-side code to push content to
clients and vice-versa. Instantly.
Expand All @@ -15,7 +16,7 @@ clients and vice-versa. Instantly.
| | [Official client library](https://learn.microsoft.com/en-us/aspnet/core/signalr/java-client) | SignalR Kore |
|:---------------------------|:--------------------------------------------------------------------------------------------:|:-----------------------------------:|
| Written in | Java | Kotlin |
| KMM / KMP | :heavy_multiplication_x: | Android, JVM |
| KMM / KMP | :heavy_multiplication_x: | Android, JVM, iOS |
| Network | OkHttp only | Ktor (any engine pluggable*) |
| Async | RxJava | Coroutines |
| Serialization | Gson (non-customizable) | Kotlinx Serializable (customizable) |
Expand Down Expand Up @@ -258,7 +259,7 @@ automaticReconnect = AutomaticReconnect.Custom { previousRetryCount, elapsedTime
- [ ] Add tests
- [x] Implement streams
- [x] Extend to JVM
- [ ] Extend to iOS
- [x] Extend to iOS
- [ ] Implement transport fallback
- [x] Implement automatic reconnect

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RELEASE_SIGNING_ENABLED=true

GROUP=eu.lepicekmichal.signalrkore
POM_ARTIFACT_ID=signalrkore
VERSION_NAME=0.5.4
VERSION_NAME=0.6.0

POM_NAME=SignalR Kore
POM_DESCRIPTION=Connect to SignalR Core server with library written in Kotlin and coroutines.
Expand Down
9 changes: 5 additions & 4 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ pluginManagement {
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}

rootProject.name = "SignalRKore"
include(":androidApp")
include(":signalrkore")

enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
include(
":androidApp",
":signalrkore",
)
36 changes: 24 additions & 12 deletions signalrkore/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,35 @@ version = requireNotNull(project.findProperty("VERSION_NAME"))
kotlin {
androidTarget {
publishLibraryVariants("release")
}

targets {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
compilations.all {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
}
jvm {
compilations.all {
kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
}
}

jvm {
compilations.all {
kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
}
}

listOf(
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "SignalRKore"
isStatic = true
}
}

jvmToolchain(17)

sourceSets {
applyDefaultHierarchyTemplate()

all {
languageSettings {
optIn("kotlin.RequiresOptIn")
Expand Down Expand Up @@ -63,7 +72,10 @@ kotlin {
val androidMain by getting {
dependsOn(jvmMain)
}
val androidUnitTest by getting

iosMain.dependencies {

}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package eu.lepicekmichal.signalrkore
import eu.lepicekmichal.signalrkore.transports.LongPollingTransport
import eu.lepicekmichal.signalrkore.transports.ServerSentEventsTransport
import eu.lepicekmichal.signalrkore.transports.WebSocketTransport
import eu.lepicekmichal.signalrkore.utils.dispatchers
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
Expand All @@ -17,7 +16,9 @@ import io.ktor.util.*
import io.ktor.utils.io.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.IO
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelChildren
Expand Down Expand Up @@ -69,7 +70,7 @@ class HubConnection private constructor(
) : HubCommunication() {

private val job = SupervisorJob()
private val scope = CoroutineScope(job + dispatchers.io)
private val scope = CoroutineScope(job + Dispatchers.IO)

private val pingReset = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
private val pingTicker = pingReset
Expand Down Expand Up @@ -158,7 +159,7 @@ class HubConnection private constructor(
throw RuntimeException("Connection closed while trying to connect.")
}

withContext(dispatchers.io) {
withContext(Dispatchers.IO) {
launch {
val handshake = Json.encodeToString(Handshake(protocol = protocol.name, version = protocol.version)) + RECORD_SEPARATOR
transport.send(handshake.toByteArray())
Expand Down Expand Up @@ -298,7 +299,7 @@ class HubConnection private constructor(

_connectionState.value = HubConnectionState.RECONNECTING

scope.launch(dispatchers.io) {
scope.launch(Dispatchers.IO) {
val mark = TimeSource.Monotonic.markNow()
var retryCount = 0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package eu.lepicekmichal.signalrkore.transports

import eu.lepicekmichal.signalrkore.Transport
import eu.lepicekmichal.signalrkore.utils.buildAsHeaders
import eu.lepicekmichal.signalrkore.utils.dispatchers
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.http.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
Expand All @@ -22,7 +23,7 @@ import kotlin.jvm.Volatile
internal class LongPollingTransport(private val headers: Map<String, String>, private val client: HttpClient) : Transport {

private val job = SupervisorJob()
private val scope = CoroutineScope(job + dispatchers.io)
private val scope = CoroutineScope(job + Dispatchers.IO)

private val incoming: MutableSharedFlow<ByteArray> = MutableSharedFlow()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package eu.lepicekmichal.signalrkore.transports

import eu.lepicekmichal.signalrkore.Transport
import eu.lepicekmichal.signalrkore.utils.dispatchers
import io.ktor.client.*
import io.ktor.utils.io.core.*
import io.ktor.client.HttpClient
import io.ktor.utils.io.core.toByteArray
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.Flow
Expand All @@ -14,7 +15,6 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okio.BufferedSource
import okio.Closeable
import okio.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
Expand All @@ -29,7 +29,7 @@ internal class ServerSentEventsTransport(
private val delegate = ServerSentEventsDelegate(client)

private val job = SupervisorJob()
private val scope = CoroutineScope(job + dispatchers.io)
private val scope = CoroutineScope(job + Dispatchers.IO)

private val incoming: MutableSharedFlow<ByteArray> = MutableSharedFlow()

Expand Down Expand Up @@ -65,12 +65,12 @@ internal class ServerSentEventsTransport(
}
}
} finally {
withContext(dispatchers.io) {
withContext(Dispatchers.IO) {
source.close()
}
}
} finally {
withContext(dispatchers.io) {
withContext(Dispatchers.IO) {
response.close()
}
}
Expand Down Expand Up @@ -113,6 +113,5 @@ internal class ServerSentEventsTransport(
override suspend fun stop() {
active = false
job.cancelChildren()
//log("LongPolling transport stopped.")
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package eu.lepicekmichal.signalrkore

import platform.Foundation.NSUUID

actual object UUID {
actual fun randomUUID(): String = NSUUID().UUIDString()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package eu.lepicekmichal.signalrkore.transports

import io.ktor.client.HttpClient

internal actual class ServerSentEventsDelegate actual constructor(client: HttpClient) {

actual fun get(
url: String,
headers: Map<String, String>,
onFailure: (Exception) -> Unit,
onSuccess: (Response) -> Unit,
) {
throw IllegalStateException("iOS does not support Server Sent Events.")
}

actual fun post(url: String, headers: Map<String, String>, message: ByteArray) {
throw IllegalStateException("iOS does not support Server Sent Events.")
}

}

This file was deleted.

This file was deleted.

0 comments on commit c674a5d

Please sign in to comment.