Make datetime storage more consistent
authorTheSaminator <TheSaminator@users.noreply.github.com>
Wed, 9 Feb 2022 15:14:27 +0000 (10:14 -0500)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Wed, 9 Feb 2022 15:14:27 +0000 (10:14 -0500)
src/commonMain/kotlin/starshipfights/game/util.kt
src/jvmMain/kotlin/starshipfights/auth/providers.kt
src/jvmMain/kotlin/starshipfights/auth/utils.kt
src/jvmMain/kotlin/starshipfights/data/admiralty/battle_records.kt
src/jvmMain/kotlin/starshipfights/data/auth/user_sessions.kt
src/jvmMain/kotlin/starshipfights/game/server_game.kt
src/jvmMain/kotlin/starshipfights/game/server_matchmaking.kt
src/jvmMain/kotlin/starshipfights/info/views_user.kt

index 416bf473c5bc22616e4e97a9303e5e6aa7b0512f..b43515f53b3d27e878ac800cd937a840afe2b016 100644 (file)
@@ -5,10 +5,7 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.isActive
 import kotlinx.serialization.json.Json
-import kotlin.math.abs
 import kotlin.math.roundToInt
-import kotlin.math.sign
-import kotlin.math.sqrt
 
 val jsonSerializer = Json {
        classDiscriminator = "\$ktClass"
index 381071056d6b51c575e092918e475c6a34f35628..4bc3359f1ba29c0e1581d4daffd900595aa3c992 100644 (file)
@@ -33,6 +33,8 @@ import starshipfights.data.createNonce
 import starshipfights.game.AdmiralRank
 import starshipfights.game.Faction
 import starshipfights.info.*
+import java.time.Instant
+import java.time.temporal.ChronoUnit
 
 interface AuthProvider {
        fun installApplication(app: Application) = Unit
@@ -167,8 +169,8 @@ interface AuthProvider {
                                get("/logout") {
                                        call.getUserSession()?.let { sess ->
                                                launch {
-                                                       val newTime = System.currentTimeMillis() - 100
-                                                       UserSession.update(UserSession::id eq sess.id, setValue(UserSession::expirationMillis, newTime))
+                                                       val newTime = Instant.now().minusMillis(100)
+                                                       UserSession.update(UserSession::id eq sess.id, setValue(UserSession::expiration, newTime))
                                                }
                                        }
                                        
@@ -180,8 +182,8 @@ interface AuthProvider {
                                        val id = Id<UserSession>(call.parameters.getOrFail("id"))
                                        call.getUserSession()?.let { sess ->
                                                launch {
-                                                       val newTime = System.currentTimeMillis() - 100
-                                                       UserSession.update(and(UserSession::id eq id, UserSession::user eq sess.user), setValue(UserSession::expirationMillis, newTime))
+                                                       val newTime = Instant.now().minusMillis(100)
+                                                       UserSession.update(and(UserSession::id eq id, UserSession::user eq sess.user), setValue(UserSession::expiration, newTime))
                                                }
                                        }
                                        
@@ -191,8 +193,8 @@ interface AuthProvider {
                                get("/logout-all") {
                                        call.getUserSession()?.let { sess ->
                                                launch {
-                                                       val newTime = System.currentTimeMillis() - 100
-                                                       UserSession.update(and(UserSession::user eq sess.user, UserSession::id ne sess.id), setValue(UserSession::expirationMillis, newTime))
+                                                       val newTime = Instant.now().minusMillis(100)
+                                                       UserSession.update(and(UserSession::user eq sess.user, UserSession::id ne sess.id), setValue(UserSession::expiration, newTime))
                                                }
                                        }
                                        
@@ -239,7 +241,7 @@ object TestAuthProvider : AuthProvider {
                                                        user = user.id,
                                                        clientAddresses = listOf(originAddress),
                                                        userAgent = userAgent,
-                                                       expirationMillis = System.currentTimeMillis() + 3_600_000L
+                                                       expiration = Instant.now().plus(1, ChronoUnit.DAYS)
                                                ).also {
                                                        UserSession.put(it)
                                                }
@@ -400,7 +402,7 @@ class ProductionAuthProvider(val discordLogin: DiscordLogin) : AuthProvider {
                                                user = user.id,
                                                clientAddresses = listOf(call.request.origin.remoteHost),
                                                userAgent = userAgent,
-                                               expirationMillis = System.currentTimeMillis() + EXPIRATION_TIME
+                                               expiration = Instant.now().plus(1, ChronoUnit.DAYS)
                                        )
                                        
                                        launch { User.put(user) }
index 5be91d886dcc5667da1a24cc074d6125944b2599..35cc75538bad6b20632b3550d9df573af264e21a 100644 (file)
@@ -7,15 +7,15 @@ import io.ktor.sessions.*
 import starshipfights.data.Id
 import starshipfights.data.auth.User
 import starshipfights.data.auth.UserSession
-
-const val EXPIRATION_TIME = 86_400_000
+import java.time.Instant
+import java.time.temporal.ChronoUnit
 
 suspend fun Id<UserSession>.resolve(userAgent: String) = UserSession.get(this)?.takeIf { session ->
-       session.userAgent == userAgent && session.expirationMillis > System.currentTimeMillis()
+       session.userAgent == userAgent && session.expiration.isAfter(Instant.now())
 }
 
 suspend fun UserSession.renewed(clientAddress: String) = copy(
-       expirationMillis = System.currentTimeMillis() + EXPIRATION_TIME,
+       expiration = Instant.now().plus(1, ChronoUnit.DAYS),
        clientAddresses = if (clientAddresses.last() != clientAddress) clientAddresses + clientAddress else clientAddresses
 ).also { UserSession.put(it) }
 
index f248eeb1ff12e0100bc314d66b1f456832de4ed5..f510b00a301ff16690e360aa17c2cadc610bceea 100644 (file)
@@ -16,6 +16,7 @@ data class BattleRecord(
        @SerialName("_id")
        override val id: Id<BattleRecord> = Id(),
        
+       val whenStarted: @Contextual Instant,
        val whenEnded: @Contextual Instant,
        
        val hostUser: Id<User>,
index 019e1e3ab7e1f334dfaca9378d2736b626d978ed..2be729ab7eb87704370fafcee036442b40843496 100644 (file)
@@ -1,12 +1,14 @@
 package starshipfights.data.auth
 
 import io.ktor.auth.*
+import kotlinx.serialization.Contextual
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
 import starshipfights.data.DataDocument
 import starshipfights.data.DocumentTable
 import starshipfights.data.Id
 import starshipfights.data.invoke
+import java.time.Instant
 
 @Serializable
 data class User(
@@ -40,7 +42,7 @@ data class UserSession(
        val user: Id<User>,
        val clientAddresses: List<String>,
        val userAgent: String,
-       val expirationMillis: Long
+       val expiration: @Contextual Instant
 ) : DataDocument<UserSession>, Principal {
        companion object Table : DocumentTable<UserSession> by DocumentTable.create({
                index(UserSession::user)
index 86a7d614a3f58f708a5e036510bfeb1753db3397..265182527d0bf8cb63f09b9efddd5f0983c4c7ad 100644 (file)
@@ -33,13 +33,16 @@ object GameManager {
                
                val session = GameSession(gameState)
                DocumentTable.launch {
+                       session.gameStart.join()
+                       val startedAt = Instant.now()
+                       
                        val end = session.gameEnd.await()
+                       val endedAt = Instant.now()
                        
-                       val now = Instant.now()
-                       val destroyedShipStatus = DrydockStatus.InRepair(now.plus(12, ChronoUnit.HOURS))
-                       val damagedShipStatus = DrydockStatus.InRepair(now.plus(9, ChronoUnit.HOURS))
-                       val intactShipStatus = DrydockStatus.InRepair(now.plus(6, ChronoUnit.HOURS))
-                       val escapedShipStatus = DrydockStatus.InRepair(now.plus(3, ChronoUnit.HOURS))
+                       val destroyedShipStatus = DrydockStatus.InRepair(endedAt.plus(12, ChronoUnit.HOURS))
+                       val damagedShipStatus = DrydockStatus.InRepair(endedAt.plus(9, ChronoUnit.HOURS))
+                       val intactShipStatus = DrydockStatus.InRepair(endedAt.plus(6, ChronoUnit.HOURS))
+                       val escapedShipStatus = DrydockStatus.InRepair(endedAt.plus(3, ChronoUnit.HOURS))
                        
                        val shipWrecks = session.state.value.destroyedShips
                        val destroyedShips = shipWrecks.filterValues { !it.isEscape }.keys.map { it.reinterpret<ShipInDrydock>() }.toSet()
@@ -61,7 +64,8 @@ object GameManager {
                        }
                        
                        val battleRecord = BattleRecord(
-                               whenEnded = now,
+                               whenStarted = startedAt,
+                               whenEnded = endedAt,
                                
                                hostUser = hostInfo.user.id.reinterpret(),
                                guestUser = guestInfo.user.id.reinterpret(),
@@ -114,7 +118,16 @@ class GameSession(gameState: GameState) {
                                true
                        } ?: false
                }
-       }.also { if (!it) onPacket(player.other, PlayerAction.TimeOut) }
+       }.also {
+               if (it)
+                       _gameStart.complete()
+               else
+                       onPacket(player.other, PlayerAction.TimeOut)
+       }
+       
+       private val _gameStart = Job()
+       val gameStart: Job
+               get() = _gameStart
        
        private val stateMutable = MutableStateFlow(gameState)
        private val stateMutex = Mutex()
index 2dbfbc2bd4f66da6561bc5cb3bb21caa54852d76..87d406f047a5ef9d30840cf328d29d87ce931d1e 100644 (file)
@@ -7,7 +7,6 @@ import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.channels.ClosedSendChannelException
 import kotlinx.coroutines.launch
-import starshipfights.auth.getUser
 import starshipfights.data.admiralty.getInGameAdmiral
 import starshipfights.data.auth.User
 
index 02716bfa026dafe4bee8e40a149598a47f0a86fc..a9b740e836dd8f24afa0a1b783115e4edfc4c257 100644 (file)
@@ -120,10 +120,10 @@ suspend fun ApplicationCall.manageUserPage(): HTML.() -> Unit {
                                        th { +"Client IPs" }
                                        th { +Entities.nbsp }
                                }
-                               val now = System.currentTimeMillis()
+                               val now = Instant.now()
                                val expiredSessions = mutableListOf<UserSession>()
                                allUserSessions.forEach { session ->
-                                       if (session.expirationMillis < now) {
+                                       if (session.expiration.isBefore(now)) {
                                                expiredSessions += session
                                                return@forEach
                                        }
@@ -164,7 +164,7 @@ suspend fun ApplicationCall.manageUserPage(): HTML.() -> Unit {
                                                        +"Expired at "
                                                        span(classes = "moment") {
                                                                style = "display:none"
-                                                               +session.expirationMillis.toString()
+                                                               +session.expiration.toEpochMilli().toString()
                                                        }
                                                }
                                        }
@@ -303,7 +303,7 @@ suspend fun ApplicationCall.admiralPage(): HTML.() -> Unit {
                )
        ) {
                section {
-                       h1 { +admiral.fullName }
+                       h1 { +admiral.name }
                        p {
                                +admiral.fullName
                                +" is a flag officer of the "
@@ -328,12 +328,16 @@ suspend fun ApplicationCall.admiralPage(): HTML.() -> Unit {
                                                        }
                                                }
                                                td {
-                                                       val now = Instant.now()
-                                                       +when (ship.status) {
-                                                               DrydockStatus.Ready -> "Ready"
+                                                       when (ship.status) {
+                                                               DrydockStatus.Ready -> +"Ready"
                                                                is DrydockStatus.InRepair -> {
-                                                                       val distance = (ship.status.until.epochSecond - now.epochSecond) / 3600 + 1
-                                                                       "Repairing (ready in ${distance}h)"
+                                                                       +"Repairing"
+                                                                       br
+                                                                       +"Will be ready at "
+                                                                       span(classes = "moment") {
+                                                                               style = "display:none"
+                                                                               +ship.status.until.toEpochMilli().toString()
+                                                                       }
                                                                }
                                                        }
                                                }
@@ -356,6 +360,13 @@ suspend fun ApplicationCall.admiralPage(): HTML.() -> Unit {
                                records.sortedBy { it.whenEnded }.forEach { record ->
                                        tr {
                                                td {
+                                                       +"Started at "
+                                                       span(classes = "moment") {
+                                                               style = "display:none"
+                                                               +record.whenStarted.toEpochMilli().toString()
+                                                       }
+                                                       br
+                                                       +"Ended at "
                                                        span(classes = "moment") {
                                                                style = "display:none"
                                                                +record.whenEnded.toEpochMilli().toString()