accounting: show progress window

This commit is contained in:
Bixilon 2022-04-17 15:52:30 +02:00
parent 3541b27354
commit 1c1e8e08b2
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 174 additions and 20 deletions

View File

@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.watcher.DataWatcher.Companion.watched
import de.bixilon.minosoft.config.profile.profiles.eros.server.entries.Server
import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount
@ -48,10 +49,10 @@ abstract class Account(
abstract fun join(serverId: String)
abstract fun logout(clientToken: String)
abstract fun check(clientToken: String)
abstract fun check(latch: CountUpAndDownLatch?, clientToken: String)
@Synchronized
open fun tryCheck(clientToken: String) {
open fun tryCheck(latch: CountUpAndDownLatch?, clientToken: String) {
if (state == AccountStates.CHECKING || state == AccountStates.REFRESHING) {
// already checking
return
@ -60,6 +61,6 @@ abstract class Account(
// Nothing to do
return
}
check(clientToken)
check(latch, clientToken)
}
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.accounts.types.microsoft
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.data.player.properties.PlayerProperties
@ -44,18 +45,23 @@ class MicrosoftAccount(
override fun logout(clientToken: String) = Unit
@Synchronized
override fun check(@Nullable clientToken: String) {
override fun check(latch: CountUpAndDownLatch?, @Nullable clientToken: String) {
if (accessToken != null) {
return
}
val innerLatch = CountUpAndDownLatch(3, latch)
try {
state = AccountStates.REFRESHING
val (xboxLiveToken, userHash) = MicrosoftOAuthUtils.getXboxLiveToken(authorizationToken)
innerLatch.dec()
val xstsToken = MicrosoftOAuthUtils.getXSTSToken(xboxLiveToken)
innerLatch.dec()
accessToken = MicrosoftOAuthUtils.getMinecraftBearerAccessToken(userHash, xstsToken)
innerLatch.dec()
state = AccountStates.WORKING
} catch (exception: Throwable) {
innerLatch.count = 0
this.error = exception
this.state = AccountStates.ERRORED
throw exception

View File

@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.json.JsonUtil.asJsonObject
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.uuid.UUIDUtil.toUUID
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
@ -63,17 +64,19 @@ class MojangAccount(
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang account login successful (username=$username)" }
}
override fun check(clientToken: String) {
override fun check(latch: CountUpAndDownLatch?, clientToken: String) {
if (refreshed) {
return
}
try {
latch?.inc()
refresh(clientToken)
} catch (exception: Throwable) {
this.error = exception
state = AccountStates.ERRORED
throw exception
}
latch?.dec()
}
@Synchronized

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.data.accounts.types.offline
import com.fasterxml.jackson.annotation.JsonIgnore
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.data.player.properties.PlayerProperties
@ -35,7 +36,7 @@ class OfflineAccount(username: String) : Account(username) {
override fun logout(clientToken: String) = Unit
override fun check(clientToken: String) = Unit
override fun check(latch: CountUpAndDownLatch?, clientToken: String) = Unit
override fun toString(): String {
return "OfflineAccount{$username}"

View File

@ -14,12 +14,10 @@
package de.bixilon.minosoft.gui.eros.main
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.minosoft.ShutdownReasons
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatchFX
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.gui.eros.controller.EmbeddedJavaFXController
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController
import de.bixilon.minosoft.gui.eros.main.account.AccountController
@ -150,15 +148,8 @@ class MainErosController : JavaFXWindowController() {
activity = ErosMainActivities.ACCOUNT
return
}
if (account.state == AccountStates.WORKING) {
DefaultThreadPool += { onSuccess(account) }
return
}
if (account.state == AccountStates.CHECKING || account.state == AccountStates.REFRESHING) {
return
}
getController(ErosMainActivities.ACCOUNT).unsafeCast<AccountController>().checkAccount(account, false)
getController(ErosMainActivities.ACCOUNT).unsafeCast<AccountController>().checkAccount(account, false, onSuccess = onSuccess)
}

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.eros.main.account
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.collections.CollectionUtil.extend
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.primitive.BooleanUtil.decide
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.profile.delegate.watcher.entry.MapProfileDelegateWatcher.Companion.profileWatchMapFX
@ -113,17 +114,31 @@ class AccountController : EmbeddedJavaFXController<Pane>() {
}
fun checkAccount(account: Account, select: Boolean, checkOnly: Boolean = false) {
fun checkAccount(account: Account, select: Boolean, checkOnly: Boolean = false, onSuccess: ((Account) -> Unit)? = null) {
if (account.state == AccountStates.WORKING) {
onSuccess?.let { DefaultThreadPool += { it(account) } }
return
}
if (account.state == AccountStates.CHECKING || account.state == AccountStates.REFRESHING) {
return
}
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Checking account $account" }
val latch = CountUpAndDownLatch(2)
val dialog = CheckingDialog(latch, account)
dialog.show()
val profile = ErosProfileManager.selected.general.accountProfile
DefaultThreadPool += {
latch.dec()
try {
account.tryCheck(profile.clientToken) // ToDo: Show error
account.tryCheck(latch, profile.clientToken) // ToDo: Show error
if (select) {
profile.selected = account
}
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Account is working: $account" }
JavaFXUtil.runLater { dialog.close() }
onSuccess?.invoke(account)
} catch (exception: Throwable) {
JavaFXUtil.runLater { dialog.close() }
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Error while checking account $account: $exception" }
exception.printStackTrace()
if (account.state == AccountStates.ERRORED || account.state == AccountStates.EXPIRED) {

View File

@ -0,0 +1,67 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.eros.main.account
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.gui.eros.controller.DialogController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.text
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import javafx.fxml.FXML
import javafx.scene.control.Button
import javafx.scene.control.ProgressBar
import javafx.scene.text.TextFlow
class CheckingDialog(
val latch: CountUpAndDownLatch,
val account: Account,
) : DialogController() {
@FXML private lateinit var headerFX: TextFlow
@FXML private lateinit var progressFX: ProgressBar
@FXML private lateinit var cancelButtonFX: Button
fun show() {
JavaFXUtil.openModalAsync(TITLE, LAYOUT, this) {
update()
stage.show()
latch += { update() }
}
}
override fun init() {
headerFX.text = HEADER
}
private fun update() {
if (latch.count == 0) {
return close()
}
val progress = 1.0 - (latch.count.toDouble() / latch.total)
progressFX.progress = progress
}
@FXML
fun cancel() {
TODO("Not yet implemented!")
}
companion object {
private val LAYOUT = "minosoft:eros/main/account/checking.fxml".toResourceLocation()
private val TITLE = "minosoft:main.account.checking_dialog.title".toResourceLocation()
private val HEADER = "minosoft:main.account.checking_dialog.header".toResourceLocation()
}
}

View File

@ -55,7 +55,7 @@ object MicrosoftOAuthUtils {
account.state = AccountStates.WORKING
account.accessToken = accessToken
account.check("") // client token does not exist for microsoft accounts
account.check(null, "") // client token does not exist for microsoft accounts
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Microsoft account login successful (uuid=${account.uuid})" }

View File

@ -72,7 +72,7 @@
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="cancelButtonFX" onAction="#cancel" text="Cancel" GridPane.columnIndex="1">
<Button fx:id="cancelButtonFX" onAction="#cancel" text="Cancel" disable="true" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Minosoft
~ Copyright (C) 2020-2022 Moritz Zwerger
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<?import javafx.geometry.*?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<VBox xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="110.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17">
<GridPane VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
<RowConstraints minHeight="40.0" vgrow="NEVER"/>
<RowConstraints vgrow="ALWAYS"/>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</VBox.margin>
<TextFlow fx:id="headerFX">
<Text text="Checking account..."/>
<GridPane.margin>
<Insets bottom="10.0"/>
</GridPane.margin>
</TextFlow>
<ProgressBar fx:id="progressFX" maxHeight="Infinity" maxWidth="Infinity" progress="0.5" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</ProgressBar>
<GridPane GridPane.rowIndex="3">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="NEVER"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="cancelButtonFX" disable="true" onAction="#cancel" text="Cancel" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</Button>
<GridPane.margin>
<Insets/>
</GridPane.margin>
</GridPane>
</GridPane>
</VBox>

View File

@ -99,6 +99,9 @@ minosoft:main.account.state.working=Working
minosoft:main.account.state.expired=Expired
minosoft:main.account.state.errored=Errored
minosoft:main.account.checking_dialog.title=Checking account... - Minosoft
minosoft:main.account.checking_dialog.header=Checking account... Please wait
minosoft:main.account.card.connection_count=%1$s connections