Product Promotion
0x5a.live
for different kinds of informations and explorations.
GitHub - lepicekmichal/SignalRKore: A Kotlin multiplatform coroutine-based SignalR client.
A Kotlin multiplatform coroutine-based SignalR client. - lepicekmichal/SignalRKore
Visit SiteGitHub - lepicekmichal/SignalRKore: A Kotlin multiplatform coroutine-based SignalR client.
A Kotlin multiplatform coroutine-based SignalR client. - lepicekmichal/SignalRKore
Powered by 0x5a.live 💗
SignalRKore
SignalRKore 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.
Why should you use this library
Official client library | SignalRKore | |
---|---|---|
Written in | Java | Kotlin |
KMM / KMP | :heavy_multiplication_x: | Android, JVM, iOS |
Network | OkHttp only | Ktor |
Async | RxJava | Coroutines |
Serialization | Gson (non-customizable) | Kotlinx Serializable (customizable) |
Streams | :heavy_check_mark: | :heavy_check_mark: |
Transport fallback | :heavy_multiplication_x: | :heavy_multiplication_x: |
Automatic reconnect | :heavy_multiplication_x: | :heavy_check_mark: |
SSE | :heavy_multiplication_x: | :heavy_check_mark: |
Connection status | :heavy_multiplication_x: | :heavy_check_mark: |
Logging | SLF4J | Custom interface |
MsgPack | :heavy_check_mark: | :heavy_multiplication_x: |
Tested by time & community | :heavy_check_mark: | :heavy_multiplication_x: |
Install
implementation("eu.lepicekmichal.signalrkore:signalrkore:${signalrkoreVersion}")
Usage
Create your hub connection
private val connection: HubConnection = HubConnectionBuilder.create("http://localhost:5000/chat")
Start your connection
connection.start()
Send to server
connection.send("broadcastMessage", "Michal", "Hello")
// or
connection.invoke("broadcastMessage", "Michal", "Hello")
Receive from server
connection.on("broadcastMessage", paramType1 = String::class, paramType2 = String::class).collect { (user, message) ->
println("User $user is saying: $message")
}
Receive from server and return result
connection.on("sneakAttack", paramType1 = Boolean::class, resultType = String::class) { surprise ->
if (surprise) "Wow, you got me"
else "I saw you waaay from over there"
}
maximizing shorthand style
connection.on("sneakAttack") { surprise: Boolean ->
if (surprise) "Wow, you got me"
else "I saw you waaay from over there"
}
Don't forget to stop the connection
connection.stop()
Send and Receive complex data types
// 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).collect { (message) ->
println(message.toString())
}
We got streams too
// Receiving
connection.stream(
method = "Counter",
itemType = Int::class,
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)
}
})
Receiving stream invocation and responding to it is in
Keep up with connection status
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")
}
}
Connection configuration
HubConnectionBuilder
.create(url) {
transportEnum = ...
httpClient = ...
protocol = ...
skipNegotiate = ...
automaticReconnect = ...
accessToken = ...
handshakeResponseTimeout = ...
headers = ...
json = ...
logger = ...
}
Supported transports
- TransportEnum.All (default, automatic choice based on availability)
- TransportEnum.WebSockets
- TransportEnum.ServerSentEvents
- TransportEnum.LongPolling
Add your own ktor http client
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 and other plugins installed
HttpClient {
install(WebSockets)
install(SSE)
install(HttpTimeout)
install(ContentNegotiation) { json() }
}
You may pass your own HubProtocol
With custom parsing and encoding
class MyHubProtocol : HubProtocol {
fun parseMessages(payload: ByteArray): List<HubMessage> {
// your implementation
}
fun writeMessage(message: HubMessage): ByteArray {
// your implementation
}
}
Logs are available
Just decide what to do with the message
logger = Logger { severity, msg, cause ->
Napier.v("SignalRKore is saying: $ms")
}
Do not forget your own instance of Json
If your kotlinx-serialization Json is customized or it has modules registered in it, then don't forget to pass it.
Reconnect if server wants you to
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))
}
TODO list
- 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
- Reacting to stream invocation from server
All functionality was possible to implement only thanks to AzureSignalR ChatRoomLocal sample
Kotlin Resources
are all listed below.
Made with ❤️
to provide different kinds of informations and resources.