KNET oferuje pełną obsługę WebSocket z auto-reconnect, heartbeat i typowanymi wiadomościami.
val ws = KNETWebSocket.connect("wss://api.example.com/ws")
// Nasłuchuj wiadomości
ws.onMessage { message ->
println("Otrzymano: $message")
}
// Nasłuchuj eventów
ws.onOpen {
println("Połączono!")
ws.send("Hello Server!")
}
ws.onClose { code, reason ->
println("Zamknięto: $code - $reason")
}
ws.onError { error ->
println("Błąd: ${error.message}")
}
// Wyślij wiadomość
ws.send("Hello!")
// Wyślij JSON
ws.sendJson(mapOf("type" to "ping"))
// Zamknij połączenie
ws.close()
val ws = KNETWebSocket.builder("wss://api.example.com/ws")
.headers(mapOf(
"Authorization" to "Bearer $token",
"X-Client-ID" to clientId
))
.connectTimeout(10_000)
.readTimeout(0) // Brak timeout dla WebSocket
.pingInterval(30_000) // Ping co 30s
.autoReconnect(true)
.reconnectDelay(5_000)
.maxReconnectAttempts(10)
.build()
// Połącz
ws.connect()
// Lub z callback
ws.connect { success, error ->
if (success) {
println("Połączono!")
} else {
println("Błąd: ${error?.message}")
}
}
val ws = KNETWebSocket.builder(url)
.autoReconnect(true)
.reconnectDelay(5_000) // Początkowy delay
.maxReconnectDelay(60_000) // Max delay (exponential backoff)
.maxReconnectAttempts(10) // Max prób (0 = unlimited)
.build()
// Eventy reconnect
ws.onReconnecting { attempt, delay ->
showNotification("Ponowne łączenie... próba $attempt")
}
ws.onReconnected {
showNotification("Połączono ponownie!")
resubscribeToChannels()
}
// Definiuj typy
data class ChatMessage(
val type: String,
val userId: String,
val content: String,
val timestamp: Long
)
// Nasłuchuj z deserializacją
ws.onMessage<ChatMessage> { message ->
when (message.type) {
"chat" -> displayMessage(message)
"typing" -> showTypingIndicator(message.userId)
"read" -> markAsRead(message)
}
}
// Wyślij typowane
ws.sendJson(ChatMessage(
type = "chat",
userId = currentUserId,
content = "Hello!",
timestamp = System.currentTimeMillis()
))
// Wzorzec pub/sub
ws.subscribe("chat:room123") { message ->
displayChatMessage(message)
}
ws.subscribe("notifications") { notification ->
showNotification(notification)
}
// Anuluj subskrypcję
ws.unsubscribe("chat:room123")
// Przykładowa implementacja
class WebSocketChannel(
private val ws: KNETWebSocket,
private val channel: String
) {
fun subscribe() {
ws.sendJson(mapOf(
"action" to "subscribe",
"channel" to channel
))
}
fun unsubscribe() {
ws.sendJson(mapOf(
"action" to "unsubscribe",
"channel" to channel
))
}
fun send(data: Any) {
ws.sendJson(mapOf(
"action" to "message",
"channel" to channel,
"data" to data
))
}
}
// WebSocket jako Flow
val messagesFlow: Flow<String> = ws.asFlow()
// Użycie w ViewModel
class ChatViewModel : ViewModel() {
private val ws = KNETWebSocket.connect(wsUrl)
val messages: StateFlow<List<Message>> = ws.asFlow()
.map { json -> parseMessage(json) }
.scan(emptyList<Message>()) { acc, msg -> acc + msg }
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
fun sendMessage(text: String) {
ws.sendJson(mapOf("text" to text))
}
override fun onCleared() {
ws.close()
}
}
val ws = KNETWebSocket.builder(url)
.pingInterval(30_000) // Wyślij ping co 30s
.pongTimeout(10_000) // Czekaj max 10s na pong
.build()
// Własna logika heartbeat
ws.onOpen {
startHeartbeat()
}
private fun startHeartbeat() {
heartbeatJob = scope.launch {
while (isActive) {
delay(30_000)
ws.sendJson(mapOf("type" to "ping"))
}
}
}
ws.onMessage { message ->
if (message.contains("pong")) {
lastPongTime = System.currentTimeMillis()
}
}
// Wyślij binary
val imageBytes = loadImage()
ws.sendBinary(imageBytes)
// Odbierz binary
ws.onBinaryMessage { bytes ->
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
displayImage(bitmap)
}
class ChatRepository(private val token: String) {
private var ws: KNETWebSocket? = null
private val _messages = MutableStateFlow<List<ChatMessage>>(emptyList())
val messages: StateFlow<List<ChatMessage>> = _messages
private val _connectionState = MutableStateFlow<ConnectionState>(ConnectionState.Disconnected)
val connectionState: StateFlow<ConnectionState> = _connectionState
fun connect(roomId: String) {
ws = KNETWebSocket.builder("wss://chat.example.com/rooms/$roomId")
.headers(mapOf("Authorization" to "Bearer $token"))
.autoReconnect(true)
.build()
ws?.onOpen {
_connectionState.value = ConnectionState.Connected
}
ws?.onClose { _, _ ->
_connectionState.value = ConnectionState.Disconnected
}
ws?.onReconnecting { attempt, _ ->
_connectionState.value = ConnectionState.Reconnecting(attempt)
}
ws?.onMessage<ChatMessage> { message ->
_messages.update { it + message }
}
ws?.connect()
}
fun sendMessage(text: String) {
ws?.sendJson(ChatMessage(
type = "message",
content = text,
userId = currentUserId,
timestamp = System.currentTimeMillis()
))
}
fun disconnect() {
ws?.close()
ws = null
}
}
sealed class ConnectionState {
object Disconnected : ConnectionState()
object Connected : ConnectionState()
data class Reconnecting(val attempt: Int) : ConnectionState()
}