Skip to content

Commit

Permalink
feat: improve jar auto updater (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
EchoEllet authored Jul 6, 2024
1 parent 645c0fc commit a6c2735
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
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

0 comments on commit a6c2735

Please sign in to comment.