feat(Updater): handle failures properly
This commit is contained in:
parent
dd29d5de2f
commit
197bb84c21
5 changed files with 61 additions and 48 deletions
|
|
@ -42,7 +42,6 @@ class ManagerApplication : Application() {
|
|||
// Services
|
||||
modules(module {
|
||||
singleOf(::HttpService)
|
||||
singleOf(::GithubService)
|
||||
singleOf(::AliucordGithubService)
|
||||
singleOf(::AliucordMavenService)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
package com.aliucord.manager.network.services
|
||||
|
||||
import com.aliucord.manager.network.models.BuildInfo
|
||||
import com.aliucord.manager.network.models.GithubRelease
|
||||
import com.aliucord.manager.network.utils.ApiResponse
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.http.HttpHeaders
|
||||
|
||||
class AliucordGithubService(
|
||||
val github: GithubService,
|
||||
val http: HttpService,
|
||||
private val http: HttpService,
|
||||
) {
|
||||
/**
|
||||
* Fetches the build data of Aliucord (excluding Aliuhook).
|
||||
|
|
@ -22,7 +22,15 @@ class AliucordGithubService(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun getManagerReleases() = github.getReleases(ORG, MANAGER_REPO)
|
||||
/**
|
||||
* Fetches all the Manager releases with a 60s local cache.
|
||||
*/
|
||||
suspend fun getManagerReleases(): ApiResponse<List<GithubRelease>> {
|
||||
return http.request {
|
||||
url("https://api.github.com/repos/rushiiMachine/$MANAGER_REPO/releases")
|
||||
header(HttpHeaders.CacheControl, "public, max-age=60, s-maxage=60")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ORG = "Aliucord"
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
package com.aliucord.manager.network.services
|
||||
|
||||
import com.aliucord.manager.network.models.GithubRelease
|
||||
import com.aliucord.manager.network.utils.ApiResponse
|
||||
import io.ktor.client.request.url
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GithubService(
|
||||
private val http: HttpService,
|
||||
) {
|
||||
suspend fun getReleases(owner: String, repo: String): ApiResponse<List<GithubRelease>> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
http.request {
|
||||
url("https://api.github.com/repos/$owner/$repo/releases")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
package com.aliucord.manager.ui.widgets.updater
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aliucord.manager.BuildConfig
|
||||
import com.aliucord.manager.R
|
||||
import com.aliucord.manager.manager.InstallerManager
|
||||
import com.aliucord.manager.manager.InstallerSetting
|
||||
import com.aliucord.manager.manager.download.KtorDownloadManager
|
||||
import com.aliucord.manager.network.services.AliucordGithubService
|
||||
import com.aliucord.manager.network.utils.SemVer
|
||||
import com.aliucord.manager.network.utils.getOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import com.aliucord.manager.network.utils.getOrThrow
|
||||
import com.aliucord.manager.util.showToast
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class UpdaterViewModel(
|
||||
|
|
@ -29,6 +31,17 @@ class UpdaterViewModel(
|
|||
|
||||
private var targetApkUrl: String? = null
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
fetchInfo()
|
||||
} catch (t: Throwable) {
|
||||
Log.e(BuildConfig.TAG, "Failed to check for updates!", t)
|
||||
application.showToast(R.string.updater_fail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dismissDialog() {
|
||||
showDialog = false
|
||||
}
|
||||
|
|
@ -52,34 +65,45 @@ class UpdaterViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
// This updates to the latest release based on the tag name
|
||||
// It finds all releases that have an asset named aliucord-manager-[tagname].apk (this is in case the filename changes in the future)
|
||||
// Then compares the semantic versioning of the tag name which should be in the v1.0.0 format
|
||||
// Finds the latest and downloads/installs it
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val (version, asset) = github.getManagerReleases().getOrNull()
|
||||
?.mapNotNull { release ->
|
||||
val version = SemVer.parseOrNull(release.tagName)
|
||||
?: return@mapNotNull null
|
||||
/**
|
||||
* This fetched the releases data from GitHub and populates the state if there is an update.
|
||||
*
|
||||
* It obtains all the releases that have an asset named `aliucord-manager-[tag].apk`,
|
||||
* then finds the latest release based on the largest semantic version extracted from the tag name (`v1.0.0`),
|
||||
* and populates the state to show to the user.
|
||||
*/
|
||||
private suspend fun fetchInfo() {
|
||||
Log.d(BuildConfig.TAG, "Checking for updates...")
|
||||
|
||||
val asset = release.assets.find { it.name == "aliucord-manager-${release.tagName}.apk" }
|
||||
?: return@mapNotNull null
|
||||
val currentVersion = SemVer.parseOrNull(BuildConfig.VERSION_NAME)
|
||||
?: throw Error("Failed to parse current app version")
|
||||
|
||||
version to asset
|
||||
}
|
||||
?.maxByOrNull { it.first }
|
||||
?: return@launch
|
||||
// Fetch releases from GitHub (60s local cache)
|
||||
val releases = github.getManagerReleases().getOrThrow()
|
||||
|
||||
val currentVersion = SemVer.parseOrNull(BuildConfig.VERSION_NAME)
|
||||
?: throw Error("Failed to parse app version")
|
||||
// Find the latest release + APK release asset
|
||||
val (version, apkUrl) = releases
|
||||
.mapNotNull { release ->
|
||||
val version = SemVer.parseOrNull(release.tagName)
|
||||
?: return@mapNotNull null
|
||||
|
||||
if (currentVersion >= version)
|
||||
return@launch
|
||||
val asset = release.assets.find { it.name == "aliucord-manager-${release.tagName}.apk" }
|
||||
?: return@mapNotNull null
|
||||
|
||||
targetVersion = version.toString()
|
||||
targetApkUrl = asset.browserDownloadUrl
|
||||
showDialog = true
|
||||
version to asset.browserDownloadUrl
|
||||
}
|
||||
.maxByOrNull { it.first }
|
||||
?: return
|
||||
|
||||
// Check if currently installed version is greater
|
||||
if (currentVersion >= version) {
|
||||
Log.d(BuildConfig.TAG, "Already updated to latest version!")
|
||||
return
|
||||
}
|
||||
|
||||
targetVersion = version.toString()
|
||||
targetApkUrl = apkUrl
|
||||
showDialog = true
|
||||
Log.d(BuildConfig.TAG, "Found an update! $targetVersion $targetApkUrl")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@
|
|||
|
||||
<string name="updater_body">A new update has been released for Aliucord Manager! It may be required in order to function properly. Would you like to update?</string>
|
||||
<string name="updater_title">Update to %1$s</string>
|
||||
<string name="updater_fail">Failed to check for updates!</string>
|
||||
|
||||
<string name="downloader_err_unknown">Download failed (Unknown)</string>
|
||||
<string name="downloader_err_timeout">Download failed (Timeout)</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue