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.
Official client library | SignalR Kore | |
---|---|---|
Written in | Java | Kotlin |
KMM / KMP | ✖️ | Android, JVM, iOS |
Network | OkHttp only | Ktor (any engine pluggable*) |
Async | RxJava | Coroutines |
Serialization | Gson (non-customizable) | Kotlinx Serializable (customizable) |
Streams | ✔️ | ✔️ |
Transport fallback | ✖️ | ✖️ |
Automatic reconnect | ✖️ | ✔️ |
SSE | ✖️ | ✔️ ** |
Connection status | ✖️ | ✔️ |
Logging | SLF4J | Custom interface |
MsgPack | ✔️ | ✖️ |
Tested by time & community | ✔️ | ✖️ |
* Except for SSE which uses only OkHttp at the moment
** Only for android and jvm for now
Even though this library has many advantages over official client library, SignalR Kore would not exist without it as implementation of the SignalR standard is much inspired in it. Therefore I thank the authors from Microsoft.
implementation("eu.lepicekmichal.signalrkore:signalrkore:${signalrkoreVersion}")
private val connection: HubConnection = HubConnectionBuilder.create("http://localhost:5000/chat")
connection.start()
connection.send("broadcastMessage", "Michal", "Hello")
// or
connection.invoke("broadcastMessage", "Michal", "Hello")
connection.on("broadcastMessage", String::class, String::class) { user, message ->
println("User $user is saying: $message")
}
connection.stop()
// Serializable class
@Serializable
data class Message(
val id: String,
val author: String,
val date: String,
val text: String,
)
// Sending message
val message = Message(
id = UUID.next(),
author = "Michal",
date = "2022-11-30T21:37:11Z",
text = "Hello",
)
connection.send("broadcastMessage", message)
// Receiving messages
connection.on("broadcastMessage", Message::class) { message ->
println(message.toString())
}
// Receiving
connection.stream(
itemType = Int::class,
method = "Counter",
arg1 = 10, // up to
arg2 = 500, // delay
).collect {
println("Countdown: ${10 - it}")
}
// Uploading
// send, invoke or stream methods
connection.send("UploadStream", flow<Int> {
var data = 0
while (data < 10) {
emit(++data)
delay(500)
}
})
connection.connectionState.collect {
when (it) {
HubConnectionState.CONNECTED -> println("Yay, we online")
HubConnectionState.DISCONNECTED -> println("Shut off!")
HubConnectionState.CONNECTING -> println("Almost there")
HubConnectionState.RECONNECTING -> println("Down again")
}
}
HubConnectionBuilder
.create(url) {
transportEnum = ...
httpClient = ...
protocol = ...
skipNegotiate = ...
automaticReconnect = ...
accessToken = ...
handshakeResponseTimeout = ...
headers = ...
json = ...
logger = ...
}
- TransportEnum.All (default, automatic choice based on availability)
- TransportEnum.WebSockets
- TransportEnum.ServerSentEvents (only for android and jvm, only okhttp engine)
- TransportEnum.LongPolling
For example one with okhttp engine and its builder containing interceptors
httpClient = HttpClient(OkHttp) {
engine {
preconfigured = okHttpBuilder.build()
}
}
But if you do opt-in to pass the http client, make sure it has websockets installed
HttpClient {
install(WebSockets)
}
With custom parsing and encoding
class MyHubProtocol : HubProtocol {
fun parseMessages(payload: ByteArray): List<HubMessage> {
// your implementation
}
fun writeMessage(message: HubMessage): ByteArray {
// your implementation
}
}
Just decide what to do with the message
logger = Logger {
Napier.v("SignalR Kore is saying: $it")
}
If your kotlinx-serialization Json is customized or it has modules registered in it, then don't forget to pass it.
SignalR Core server can send close message with allowReconnect property set to true.
Automatic reconnect is not default behaviour, but can be simply set up.
import kotlin.random.Random
/** Default, reconnect turned off **/
automaticReconnect = AutomaticReconnect.Inactive
/**
* Basic reconnect policy
* waits 0、2、10 and 30 seconds before each attempt to reconnect
* If all four attempts are unsucessful, reconnect is aborted
*/
automaticReconnect = AutomaticReconnect.Active
/**
* Extra reconnect policy
* Each attempt to reconnect is suspended with delay of exponential backoff time
* In default settings
* initially waits 1 second, then 1.5 times more seconds each time
* at most 15 tries with highest delay of 60 seconds
* all can be adjusted
*/
automaticReconnect = AutomaticReconnect.exponentialBackoff()
/**
* Custom reconnect policy
* You can implement anything you find plausible
*/
automaticReconnect = AutomaticReconnect.Custom { previousRetryCount, elapsedTime ->
// before each attempt wait random time
// but at most only the time that we are already trying to reconnect
delay(Random.nextLong(elapsedTime.inWholeMilliseconds))
}
- Readme
- Documentation
- Add example project
- Fix up ServerSentEvents' http client
- Add logging
- Error handling
- Add tests
- Implement streams
- Extend to JVM
- Extend to iOS
- Implement transport fallback
- Implement automatic reconnect
Special thanks goes to AzureSignalR ChatRoomLocal sample without which I would never start to write this library client.