aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/ledger/modules/UpdateChecker.kt
blob: 0d89ca12c3db7b752fe4aac37136279666d4a8d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package moe.nea.ledger.modules

import com.google.gson.JsonElement
import com.google.gson.JsonPrimitive
import moe.nea.ledger.DevUtil
import moe.nea.ledger.LedgerLogger
import moe.nea.ledger.TriggerCommand
import moe.nea.ledger.config.LedgerConfig
import moe.nea.ledger.config.MainOptions
import moe.nea.ledger.events.RegistrationFinishedEvent
import moe.nea.ledger.events.TriggerEvent
import moe.nea.ledger.gen.BuildConfig
import moe.nea.ledger.utils.ErrorUtil
import moe.nea.ledger.utils.MinecraftExecutor
import moe.nea.ledger.utils.di.Inject
import moe.nea.ledger.utils.network.RequestUtil
import moe.nea.libautoupdate.CurrentVersion
import moe.nea.libautoupdate.GithubReleaseUpdateData
import moe.nea.libautoupdate.GithubReleaseUpdateSource
import moe.nea.libautoupdate.PotentialUpdate
import moe.nea.libautoupdate.UpdateContext
import moe.nea.libautoupdate.UpdateData
import moe.nea.libautoupdate.UpdateTarget
import moe.nea.libautoupdate.UpdateUtils
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChatStyle
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.util.concurrent.CompletableFuture

class UpdateChecker @Inject constructor(
	val errorUtil: ErrorUtil,
	val requestUtil: RequestUtil,
) {

	@Inject
	lateinit var minecraftExecutor: MinecraftExecutor

	val updater = UpdateContext(
		NightlyAwareGithubUpdateSource("nea89o", "LocalTransactionLedger"),
		if (DevUtil.isDevEnv) UpdateTarget { listOf() }
		else UpdateTarget.deleteAndSaveInTheSameFolder(UpdateChecker::class.java),
		object : CurrentVersion {
			override fun display(): String {
				return BuildConfig.VERSION
			}

			override fun isOlderThan(element: JsonElement?): Boolean {
				if (element !is JsonPrimitive || !element.isString) return true
				val newHash = element.asString // TODO: change once i support non nightly update streams
				val length = minOf(newHash.length, BuildConfig.GIT_COMMIT.length)
				if (newHash.substring(0, length).equals(BuildConfig.GIT_COMMIT.substring(0, length), ignoreCase = true))
					return false
				return true
			}


			override fun toString(): String {
				return "{gitversion:${BuildConfig.GIT_COMMIT}, version:${BuildConfig.FULL_VERSION}}"
			}
		},
		"ledger"
	)

	class NightlyAwareGithubUpdateSource(owner: String, repository: String) :
		GithubReleaseUpdateSource(owner, repository) {
		override fun selectUpdate(updateStream: String, releases: List<GithubRelease>): UpdateData? {
			if (updateStream == "nightly") {
				return findAsset(releases.find { it.tagName == "nightly" })
			}
			return super.selectUpdate(updateStream, releases.filter { it.tagName != "nightly" })
		}

		val releaseRegex = "commit: `(?<hash>[a-f0-9]+)`".toPattern()

		override fun findAsset(release: GithubRelease?): UpdateData? {
			val update = super.findAsset(release) as GithubReleaseUpdateData? ?: return null
			return GithubReleaseUpdateData(
				update.versionName,
				releaseRegex.matcher(update.releaseDescription)
					.takeIf { it.find() }
					?.run { group("hash") }
					?.let(::JsonPrimitive)
					?: update.versionNumber,
				update.sha256,
				update.download,
				update.releaseDescription,
				update.targetCommittish,
				update.createdAt,
				update.publishedAt,
				update.htmlUrl
			)
		}
	}

	init {
		UpdateUtils.patchConnection {
			this.requestUtil.enhanceConnection(it)
		}
	}

	var latestUpdate: PotentialUpdate? = null
	var hasNotified = false

	@SubscribeEvent
	fun onStartup(event: RegistrationFinishedEvent) {
		if (config.main.updateCheck == MainOptions.UpdateCheckBehaviour.NONE) return
		launchUpdateCheck()
	}

	fun launchUpdateCheck() {
		errorUtil.listenToFuture(
			updater.checkUpdate("nightly")
				.thenAcceptAsync(
					{
						latestUpdate = it
						informAboutUpdates(it)
					}, minecraftExecutor)
		)
	}

	@Inject
	lateinit var config: LedgerConfig

	@Inject
	lateinit var triggerCommand: TriggerCommand

	val installTrigger = "execute-download"

	@Inject
	lateinit var logger: LedgerLogger
	fun informAboutUpdates(potentialUpdate: PotentialUpdate) {
		if (hasNotified) return
		hasNotified = true
		if (!potentialUpdate.isUpdateAvailable) return
		logger.printOut(
			ChatComponentText("§aThere is a new update for LocalTransactionLedger. Click here to automatically download and install it.")
				.setChatStyle(ChatStyle().setChatClickEvent(triggerCommand.getTriggerCommandLine(installTrigger))))
		if (config.main.updateCheck == MainOptions.UpdateCheckBehaviour.FULL) {
			downloadUpdate()
		}
	}

	var updateFuture: CompletableFuture<Void>? = null

	fun downloadUpdate() {
		val l = latestUpdate ?: return
		if (updateFuture != null) return
		// TODO: inject into findAsset to overwrite the tag id with the commit id
		logger.printOut("§aTrying to download ledger update ${l.update.versionName}")
		updateFuture =
			latestUpdate?.launchUpdate()
				?.thenAcceptAsync(
					{
						logger.printOut("§aLedger update downloaded. It will automatically apply after your next restart.")
					}, minecraftExecutor)
				?.let(errorUtil::listenToFuture)
	}

	@SubscribeEvent
	fun onTrigger(event: TriggerEvent) {
		if (event.action == installTrigger) {
			event.isCanceled = true
			downloadUpdate()
		}
	}

}