Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve jar auto updater #22

Merged
merged 3 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ kotlin {

val generateBuildConfig =
tasks.register<GenerateBuildConfigTask>("generateBuildConfig") {
// To allow overriding the current project version
val projectVersion: String? by project

val buildConfigDirectory = project.layout.buildDirectory.dir("generated")

classFullyQualifiedName.set("generated.BuildConfig")
generatedOutputDirectory.set(buildConfigDirectory)
fieldsToGenerate.put("PROJECT_VERSION", libs.versions.project.get())
fieldsToGenerate.put("PROJECT_VERSION", projectVersion ?: libs.versions.project.get())
}

sourceSets.main.configure {
Expand Down
63 changes: 59 additions & 4 deletions sync-script/src/main/kotlin/services/updater/JarAutoUpdater.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package services.updater
import constants.ProjectInfoConstants
import constants.SyncScriptDotMinecraftFiles
import generated.BuildConfig
import gui.dialogs.LoadingIndicatorDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Request
import utils.FileDownloader
import utils.HttpService
import utils.SystemInfoProvider
import utils.buildHtml
import utils.convertBytesToReadableMegabytesAsString
import utils.createFileWithParentDirectoriesOrTerminate
import utils.deleteExistingOrTerminate
import utils.executeAsync
Expand Down Expand Up @@ -38,10 +41,34 @@ object JarAutoUpdater {
}
val latestJarFileDownloadUrl = ProjectInfoConstants.LATEST_SYNC_SCRIPT_JAR_FILE_URL
println("\uD83D\uDD3D Downloading the new JAR file from: $latestJarFileDownloadUrl")

LoadingIndicatorDialog.instance?.updateComponentProperties(
title = "Updating...",
infoText =
"Sending HTTP request...",
progress = 0,
detailsText =
"Initiating network request for the update.",
)
FileDownloader(
downloadUrl = ProjectInfoConstants.LATEST_SYNC_SCRIPT_JAR_FILE_URL,
targetFilePath = newJarFile,
progressListener = null,
progressListener = { downloadedBytes, downloadedProgress, bytesToDownload ->
LoadingIndicatorDialog.instance?.updateComponentProperties(
title = "Updating...",
infoText =
buildHtml {
text("Downloading ")
boldText(ProjectInfoConstants.DISPLAY_NAME)
text(" Update")
}.buildBodyAsText(),
progress = downloadedProgress.toInt(),
// TODO: This is duplicated twice
detailsText =
"${downloadedBytes.convertBytesToReadableMegabytesAsString()} MB /" +
" ${bytesToDownload.convertBytesToReadableMegabytesAsString()} MB",
)
},
).downloadFile()
Result.success(newJarFile)
} catch (e: Exception) {
Expand Down Expand Up @@ -77,6 +104,12 @@ object JarAutoUpdater {
}

private suspend fun shouldUpdate(): Boolean {
LoadingIndicatorDialog.instance?.updateComponentProperties(
title = "Checking for Update...",
infoText = "Checking for a new update...",
progress = 0,
detailsText = "Determining if a new version is available.",
)
val latestProjectVersionString =
getLatestProjectVersion().getOrElse {
println("❌ We couldn't get the latest project version: ${it.message}")
Expand Down Expand Up @@ -126,6 +159,8 @@ object JarAutoUpdater {
return
}

LoadingIndicatorDialog.instance?.isVisible = true

val shouldUpdate = shouldUpdate()
if (!shouldUpdate) {
return
Expand Down Expand Up @@ -164,20 +199,40 @@ object JarAutoUpdater {
}

OperatingSystem.Windows -> {
// On Windows, we can't rename, delete or modify the current running JAR file due to file locking
// On Windows, we can't rename, delete or modify the current running JAR file due to file locking.
// Will create a batch script, execute it in a different windows process
// and close the application immediately; the batch script expects
// the application to be closed after a short delay.
// The batch script will handle the update process

val updateBatScriptFile =
SyncScriptDotMinecraftFiles.SyncScriptData.Temp.path
.resolve("update.bat")
withContext(Dispatchers.IO) {
updateBatScriptFile.createFileWithParentDirectoriesOrTerminate()
}
val secondsToWait = 1

val windowTitle = "Update Complete"
val message = "${ProjectInfoConstants.DISPLAY_NAME} has been updated. Relaunch to use the new version."

val messageVbsFilePath =
SyncScriptDotMinecraftFiles.SyncScriptData.Temp.path
.resolve("updateMessage.vbs")

updateBatScriptFile.writeText(
"""
@echo off
echo Waiting for 2 seconds to ensure application closure...
timeout /t 2 > nul

echo Waiting for $secondsToWait second to ensure application closure...
timeout /t $secondsToWait > nul
del "${currentRunningJarFilePath.absolutePathString()}"
move "${newJarFilePath.absolutePathString()}" "${currentRunningJarFilePath.absolutePathString()}"

echo MsgBox "$message", 64, "$windowTitle" > "${messageVbsFilePath.absolutePathString()}"
cscript //nologo "${messageVbsFilePath.absolutePathString()}"
del "${messageVbsFilePath.absolutePathString()}"

exit
""".trimIndent(),
)
Expand Down