KNETNetworkEventBus to centralna magistrala zdarze艅 sieciowych.
Umo偶liwia reagowanie na zdarzenia HTTP w ca艂ej aplikacji.
import rip.nerd.kitsunenet.util.KNETNetworkEventBus
import rip.nerd.kitsunenet.util.KNETNetworkEventBus.NetworkEvent
import rip.nerd.kitsunenet.util.collectIn
val eventBus = KNETNetworkEventBus.create()
// Dodaj jako interceptor
val client = KNETClient.builder()
.addInterceptor(eventBus.interceptor())
.build()
// Obserwuj zdarzenia (Flow)
lifecycleScope.launch {
eventBus.events.collect { event ->
when (event) {
is NetworkEvent.RequestStarted -> showLoading()
is NetworkEvent.RequestCompleted -> {
hideLoading()
if (!event.isSuccess) showError()
}
is NetworkEvent.RequestFailed -> {
hideLoading()
showError(event.error.message)
}
else -> {}
}
}
}
sealed class NetworkEvent {
// Request rozpocz臋ty
data class RequestStarted(
val id: Long,
val timestamp: Long,
val request: KNETRequest
)
// Request zako艅czony
data class RequestCompleted(
val id: Long,
val timestamp: Long,
val request: KNETRequest,
val response: KNETResponse,
val durationMs: Long
) {
val statusCode: Int
val isSuccess: Boolean
}
// Request nieudany (wyj膮tek)
data class RequestFailed(
val id: Long,
val timestamp: Long,
val request: KNETRequest,
val error: Throwable,
val durationMs: Long
)
// Wolny request
data class SlowRequest(
val id: Long,
val timestamp: Long,
val request: KNETRequest,
val response: KNETResponse?,
val durationMs: Long,
val thresholdMs: Long
)
}
// Tylko errors
lifecycleScope.launch {
eventBus.errors.collect { event ->
analytics.logError(event.error)
}
}
// Tylko completed
lifecycleScope.launch {
eventBus.requestsCompleted.collect { event ->
metrics.recordLatency(event.durationMs)
}
}
// Tylko slow requests
lifecycleScope.launch {
eventBus.slowRequests.collect { event ->
Log.w("Perf", "Slow: ${event.request.url} (${event.durationMs}ms)")
}
}
// Na konkretny status code
val unsubscribe401 = eventBus.onStatusCode(401) { event ->
// Token wygas艂 - refresh
authManager.refreshToken()
}
// Na 401 Unauthorized (shortcut)
eventBus.onUnauthorized { event ->
navigateToLogin()
}
// Na 403 Forbidden
eventBus.onForbidden { event ->
showAccessDenied()
}
// Na 404 Not Found
eventBus.onNotFound { event ->
showNotFound()
}
// Na wszystkie server errors (5xx)
eventBus.onServerError { event ->
showServerError()
}
// Na wszystkie b艂臋dy (4xx i 5xx)
eventBus.onError { event ->
if (event.statusCode in 500..599) {
showServerError()
} else {
showClientError()
}
}
// Anuluj subskrypcj臋
unsubscribe401()
// Custom slow threshold
val eventBus = KNETNetworkEventBus.create()
val interceptor = eventBus.interceptor(slowThresholdMs = 2000)
// Singleton
val eventBus = KNETNetworkEventBus.instance
val stats = eventBus.getStats()
println("Total requests: ${stats.totalRequests}")
println("Successful: ${stats.totalSuccessful}")
println("Failed: ${stats.totalFailed}")
println("Slow: ${stats.totalSlowRequests}")
println("Success rate: ${stats.successRate}%")
println("Active listeners: ${stats.activeListeners}")
// Reset
eventBus.resetStats()
class LoadingManager(private val eventBus: KNETNetworkEventBus) {
private var activeRequests = AtomicInteger(0)
val isLoading: StateFlow<Boolean> get() = _isLoading
private val _isLoading = MutableStateFlow(false)
init {
CoroutineScope(Dispatchers.Main).launch {
eventBus.events.collect { event ->
when (event) {
is NetworkEvent.RequestStarted -> {
activeRequests.incrementAndGet()
_isLoading.value = true
}
is NetworkEvent.RequestCompleted,
is NetworkEvent.RequestFailed -> {
if (activeRequests.decrementAndGet() == 0) {
_isLoading.value = false
}
}
else -> {}
}
}
}
}
}
// W UI
loadingManager.isLoading.collect { isLoading ->
progressBar.isVisible = isLoading
}
class ErrorHandler(
private val eventBus: KNETNetworkEventBus,
private val snackbarHost: SnackbarHostState
) {
init {
eventBus.onError { event ->
val message = when (event.statusCode) {
401 -> "Sesja wygas艂a. Zaloguj si臋 ponownie."
403 -> "Brak dost臋pu do tego zasobu."
404 -> "Nie znaleziono."
in 500..599 -> "B艂膮d serwera. Spr贸buj p贸藕niej."
else -> "Wyst膮pi艂 b艂膮d: ${event.statusCode}"
}
CoroutineScope(Dispatchers.Main).launch {
snackbarHost.showSnackbar(message)
}
}
eventBus.onUnauthorized {
// Navigate to login
navigationController.navigate("login")
}
}
}
class NetworkAnalytics(
private val eventBus: KNETNetworkEventBus,
private val analytics: FirebaseAnalytics
) {
init {
CoroutineScope(Dispatchers.IO).launch {
eventBus.requestsCompleted.collect { event ->
analytics.logEvent("http_request") {
param("url", event.request.url)
param("method", event.request.method)
param("status", event.statusCode.toLong())
param("duration_ms", event.durationMs)
param("success", event.isSuccess.toString())
}
}
}
CoroutineScope(Dispatchers.IO).launch {
eventBus.errors.collect { event ->
analytics.logEvent("http_error") {
param("url", event.request.url)
param("error", event.error.message ?: "unknown")
}
}
}
}
}
class PerformanceMonitor(private val eventBus: KNETNetworkEventBus) {
init {
eventBus.interceptor(slowThresholdMs = 3000)
CoroutineScope(Dispatchers.IO).launch {
eventBus.slowRequests.collect { event ->
// Alert do monitoring
monitoring.alert(
level = AlertLevel.WARNING,
title = "Slow HTTP Request",
message = "${event.request.method} ${event.request.url}",
data = mapOf(
"duration_ms" to event.durationMs,
"threshold_ms" to event.thresholdMs
)
)
}
}
}
}
class MainViewModel(
private val eventBus: KNETNetworkEventBus
) : ViewModel() {
private val _networkState = MutableStateFlow<NetworkState>(NetworkState.Idle)
val networkState: StateFlow<NetworkState> = _networkState
init {
eventBus.collectIn(viewModelScope) { event ->
_networkState.value = when (event) {
is NetworkEvent.RequestStarted -> NetworkState.Loading
is NetworkEvent.RequestCompleted -> {
if (event.isSuccess) NetworkState.Success
else NetworkState.Error(event.statusCode)
}
is NetworkEvent.RequestFailed -> NetworkState.Error(0)
else -> _networkState.value
}
}
}
}
sealed class NetworkState {
object Idle : NetworkState()
object Loading : NetworkState()
object Success : NetworkState()
data class Error(val code: Int) : NetworkState()
}
KNETNetworkEventBus| Property/Metoda | Opis |
|---|---|
events | Flow wszystkich zdarze艅 |
requestsStarted | Flow RequestStarted |
requestsCompleted | Flow RequestCompleted |
errors | Flow RequestFailed |
slowRequests | Flow SlowRequest |
interceptor(slowThresholdMs) | Tworzy interceptor |
onStatusCode(code, callback) | Listener na status |
onUnauthorized(callback) | Listener na 401 |
onForbidden(callback) | Listener na 403 |
onNotFound(callback) | Listener na 404 |
onServerError(callback) | Listener na 5xx |
onError(callback) | Listener na b艂臋dy |
getStats() | Statystyki |
clearListeners() | Usuwa listener贸w |