feat: optimize network stack (#404)

* feat: optimize network stack and connection management

Refactor OkHttp connection pools, consolidate Gson serialization, add network-aware WebSocket reconnects, and deduplicate concurrent requests.

* test: update mapping assertions for AuthExpired

* refactor: address PR review feedback on network stack

Simplify health check, improve authenticator cookie matching robustness, resolve nit imports, and add unit tests.
This commit is contained in:
M57 authored and GitHub committed 2026-06-27 00:45:48 +03:00
1 parent 9344c3bd6e
commit 85c4662537
19 files changed
+455 -206

No files matched your search

@@ -10,6 +10,7 @@ import com.m57.hermescontrol.data.remote.safeApiCall
import com.m57.hermescontrol.ui.common.ToastHost
import com.m57.hermescontrol.ui.common.safeLaunchLoad
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -29,26 +30,32 @@ data class SkillsUiState(
val saveContentSuccess: Boolean = false,
)
class SkillsViewModel : ViewModel(), ToastHost {
class SkillsViewModel :
ViewModel(),
ToastHost {
private val _uiState = MutableStateFlow(SkillsUiState())
val uiState: StateFlow<SkillsUiState> = _uiState.asStateFlow()
private var loadJob: Job? = null
fun loadSkills() {
safeLaunchLoad(
apiCall = { safeApiCall { ApiClient.hermesApi.getSkills() } },
onStart = { _uiState.update { it.copy(isLoading = true, errorMessage = null) } },
onSuccess = { data ->
_uiState.update { it.copy(isLoading = false, skills = data.orEmpty()) }
},
onError = { errorMsg ->
_uiState.update {
it.copy(
isLoading = false,
errorMessage = "Failed to load skills: $errorMsg",
)
}
},
)
loadJob =
safeLaunchLoad(
currentJob = loadJob,
apiCall = { safeApiCall { ApiClient.hermesApi.getSkills() } },
onStart = { _uiState.update { it.copy(isLoading = true, errorMessage = null) } },
onSuccess = { data ->
_uiState.update { it.copy(isLoading = false, skills = data.orEmpty()) }
},
onError = { errorMsg ->
_uiState.update {
it.copy(
isLoading = false,
errorMessage = "Failed to load skills: $errorMsg",
)
}
},
)
}
fun toggleSkill(skill: Skill) {