feat: vehicle positions and state dismissal

This commit is contained in:
LavaDesu 2025-07-29 20:35:32 +10:00
parent c526269e5d
commit e52274a6ef
Signed by: cilly
GPG key ID: 6500251E087653C9
10 changed files with 163 additions and 42 deletions

View file

@ -17,6 +17,7 @@ import moe.lava.banksia.api.ptv.structures.PtvDeparture
import moe.lava.banksia.api.ptv.structures.PtvDirection
import moe.lava.banksia.api.ptv.structures.PtvRoute
import moe.lava.banksia.api.ptv.structures.PtvRouteType
import moe.lava.banksia.api.ptv.structures.PtvRun
import moe.lava.banksia.api.ptv.structures.PtvStop
import moe.lava.banksia.log
import okio.ByteString.Companion.encodeUtf8
@ -28,6 +29,9 @@ object Responses {
@Serializable
data class PtvRoutesResponse(val routes: List<PtvRoute>)
@Serializable
data class PtvRunsResponse(val runs: List<PtvRun>)
@Serializable
data class PtvStopResponse(val stop: PtvStop)
@Serializable
@ -129,6 +133,20 @@ class PtvService {
return response.routes
}
suspend fun runs(routeId: Int): List<PtvRun> {
val response: Responses.PtvRunsResponse = client.get() {
url {
appendPathSegments(
"runs",
"route",
routeId.toString(),
)
parameter("expand", "VehiclePosition")
}
}.body()
return response.runs
}
suspend fun stopsByRoute(routeId: Int, routeType: PtvRouteType): List<PtvStop> {
val response: Responses.PtvStopsResponse = client.get("stops") {
url {

View file

@ -1,9 +1,46 @@
package moe.lava.banksia.api.ptv.structures
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
// Some datetimes are in local time (no timezone), observed on bus vehicle positions,
// and some datetimes are in UTC, observed on train vehicle positions. We need to handle
// both cases.
private object CustomInstantSerialiser : KSerializer<Instant> {
override val descriptor: SerialDescriptor
get() = PrimitiveSerialDescriptor(
CustomInstantSerialiser::class.qualifiedName!!,
PrimitiveKind.STRING,
)
override fun serialize(
encoder: Encoder,
value: Instant
) {
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder): Instant {
val str = decoder.decodeString()
return runCatching {
Instant.parse(str)
}.getOrElse {
LocalDateTime.parse(str).toInstant(TimeZone.currentSystemDefault())
}
}
}
@Serializable
data class PtvVehiclePosition(
val latitude: Double,
val longitude: Double,
@ -12,8 +49,14 @@ data class PtvVehiclePosition(
val direction: String?,
val bearing: Double?,
val supplier: String?,
@SerialName("datetime_utc") val datetimeUtc: Instant?,
@SerialName("expiry_time") val expiryTime: Instant?,
@Serializable(CustomInstantSerialiser::class)
@SerialName("datetime_utc")
val datetimeUtc: Instant?,
@Serializable(CustomInstantSerialiser::class)
@SerialName("expiry_time")
val expiryTime: Instant?,
)
@Serializable
@ -25,4 +68,5 @@ data class PtvRun(
@SerialName("destination_name") val destinationName: String,
@SerialName("direction_id") val directionId: Int,
@SerialName("status") val status: String,
@SerialName("vehicle_position") val vehiclePosition: PtvVehiclePosition?,
)