Skip to content

Commit

Permalink
Add reparse option to get new features if parsing is enhanced.
Browse files Browse the repository at this point in the history
  • Loading branch information
d4rken committed Feb 28, 2024
1 parent 0676439 commit bf86ea2
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,22 @@ import java.time.Instant
data class IGCFlightEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo(name = "flight_id") override val flightId: Flight.Id,
@ColumnInfo(name = "imported_at") override val importedAt: Instant = Instant.now(),
@ColumnInfo(name = "imported_at") override val importedAt: Instant,
@ColumnInfo(name = "checksum_sha1") override val checksumSha1: String,
@ColumnInfo(name = "flight_source") override val sourceType: Flight.SourceType,
) : FlightEntity
) : FlightEntity


fun IGCFile.toFlightEntity(
id: Long = 0,
flightId: Flight.Id,
importedAt: Instant = Instant.now(),
checksumSha1: String,
sourceType: Flight.SourceType
) = IGCFlightEntity(
id = id,
flightId = flightId,
checksumSha1 = checksumSha1,
importedAt = importedAt,
sourceType = sourceType,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.darken.pgc.flights.core.igc
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import eu.darken.pgc.flights.core.Flight
import eu.darken.pgc.flights.core.database.FlightsDao
import kotlinx.coroutines.flow.Flow
Expand All @@ -28,8 +29,11 @@ interface IGCFlightsDao : FlightsDao {
override fun getBySha1(sha1: String): IGCFlightEntity?

@Insert
suspend fun insert(flight: IGCFlightEntity): Long
suspend fun insert(flight: IGCFlightEntity)

@Update
suspend fun update(flight: IGCFlightEntity)

@Query("DELETE FROM flights_igc WHERE flight_id = :flightId")
suspend fun delete(flightId: Flight.Id): Int
suspend fun delete(flightId: Flight.Id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,19 @@ class IGCStorage @Inject constructor(
log(TAG, VERBOSE) { "add($id, $raw) -> $path" }
}

suspend fun get(id: Flight.Id): IGCFile? = lock.withLock {
suspend fun getRaw(id: Flight.Id): ByteString? = lock.withLock {
log(TAG, VERBOSE) { "get($id)" }
val path = id.toStoragePath()
if (!path.exists()) {
log(TAG, WARN) { "get($id): $path does not exist" }
return@withLock null
}
igcParser.parse(path.readBytes().toByteString())
path.readBytes().toByteString()
}

suspend fun get(id: Flight.Id): IGCFile? {
log(TAG, VERBOSE) { "get($id)" }
return getRaw(id)?.let { igcParser.parse(it) }
}

suspend fun remove(id: Flight.Id): IGCFile? = lock.withLock {
Expand Down
57 changes: 46 additions & 11 deletions app/src/main/java/eu/darken/pgc/importer/core/Ingester.kt
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
package eu.darken.pgc.importer.core

import eu.darken.pgc.common.debug.logging.Logging.Priority.ERROR
import eu.darken.pgc.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.pgc.common.debug.logging.Logging.Priority.WARN
import eu.darken.pgc.common.debug.logging.asLog
import eu.darken.pgc.common.debug.logging.log
import eu.darken.pgc.common.debug.logging.logTag
import eu.darken.pgc.flights.core.Flight
import eu.darken.pgc.flights.core.database.FlightsDatabase
import eu.darken.pgc.flights.core.igc.IGCFlightEntity
import eu.darken.pgc.flights.core.igc.IGCParser
import eu.darken.pgc.flights.core.igc.IGCStorage
import eu.darken.pgc.flights.core.igc.toFlightEntity
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import okio.ByteString
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class Ingester @Inject constructor(
private val igcParser: IGCParser,
private val storage: IGCStorage,
private val igcStorage: IGCStorage,
private val database: FlightsDatabase,
) {

Expand All @@ -27,20 +31,15 @@ class Ingester @Inject constructor(
suspend fun ingest(payload: IngestIGCPayload): Boolean = lock.withLock {
log(TAG) { "ingest($payload)" }

val sha1 = payload.file.sha1().base64()
val sha1 = payload.file.toFlightChecksum()
val existing = database.findBySha1(sha1)
if (existing != null) {
log(TAG, WARN) { "Duplicate flight: $existing" }
return false
}

// Parse early, catch invalid files
val parsed = try {
igcParser.parse(payload.file)
} catch (e: Exception) {
log(TAG, ERROR) { "Parsing failed for $payload: ${e.asLog()}" }
throw e
}
val parsed = payload.file.parseAsIGC()

val newId = Flight.Id()

Expand All @@ -50,7 +49,7 @@ class Ingester @Inject constructor(
throw IllegalArgumentException("COLLISION: $idCollision")
}

val igcFlightEntity = IGCFlightEntity(
val igcFlightEntity = parsed.toFlightEntity(
flightId = newId,
checksumSha1 = sha1,
sourceType = when (payload.sourceType) {
Expand All @@ -60,11 +59,47 @@ class Ingester @Inject constructor(
)

database.flightsIgc.insert(igcFlightEntity)
storage.add(newId, payload.file)
igcStorage.add(newId, payload.file)

return true
}

suspend fun reingest() = lock.withLock {
log(TAG) { "reingest()" }
val igcFlights = database.flightsIgc.getAll()

igcFlights.forEachIndexed { index, flight ->
log(TAG, VERBOSE) { "Reingesting: $index: $flight" }
val igcRaw = igcStorage.getRaw(flight.flightId)!!

// Parse early, catch invalid files
val parsed = igcRaw.parseAsIGC()

withContext(NonCancellable) {
val oldEntity = database.flightsIgc.getById(flight.flightId)!!
val newEntity = parsed.toFlightEntity(
id = oldEntity.id,
flightId = oldEntity.flightId,
importedAt = oldEntity.importedAt,
checksumSha1 = oldEntity.checksumSha1,
sourceType = oldEntity.sourceType,
)
log(TAG, VERBOSE) { "Before (#$index): $oldEntity" }
log(TAG, VERBOSE) { "After (#$index): $newEntity" }
database.flightsIgc.update(newEntity)
}
}
}

private fun ByteString.toFlightChecksum(): String = this.sha1().base64()

private suspend fun ByteString.parseAsIGC() = try {
igcParser.parse(this)
} catch (e: Exception) {
log(TAG, ERROR) { "Parsing failed for $this: ${e.asLog()}" }
throw e
}

companion object {
internal val TAG = logTag("Importer", "Ingester")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ class ImporterFragment : Fragment3(R.layout.importer_fragment) {
setupWithNavController(findNavController())
setOnMenuItemClickListener {
when (it.itemId) {

R.id.action_reparse -> {
vm.reparse()
true
}

else -> super.onOptionsItemSelected(it)
}
Expand Down Expand Up @@ -120,6 +123,6 @@ class ImporterFragment : Fragment3(R.layout.importer_fragment) {
}

companion object {
internal val TAG = logTag("Ingester", "Fragment")
internal val TAG = logTag("Importer", "Fragment")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ class ImporterFragmentVM @Inject constructor(
progressHolder.value = null
}

fun reparse() = launch {
log(TAG) { "reparse()" }
ingester.reingest()
}

sealed interface State {
data class Start(
val idle: Boolean = true
Expand All @@ -135,6 +140,6 @@ class ImporterFragmentVM @Inject constructor(
}

companion object {
internal val TAG = logTag("Ingester", "Fragment", "VM")
internal val TAG = logTag("Importer", "Fragment", "VM")
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package eu.darken.pgc.main.ui.dashboard

import android.net.Uri
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.pgc.common.BuildConfigWrap
Expand All @@ -16,14 +15,11 @@ import eu.darken.pgc.flights.core.FlightStats
import eu.darken.pgc.flights.ui.FlightsGlobalDashCardVH
import eu.darken.pgc.importer.ui.ImporterDashCardVH
import eu.darken.pgc.xctrack.core.XCTrackManager
import eu.darken.pgc.xctrack.ui.XCTrackSetupCardVH
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import net.swiftzer.semver.SemVer
import javax.inject.Inject

Expand Down Expand Up @@ -72,9 +68,8 @@ class DashboardFragmentVM @Inject constructor(
val state = combine(
flightRepo.data,
flightStats.data,
xcTrackManager.state.map { it }.onStart { emit(null as XCTrackManager.State?) },
flowOf("")
) { flightData, flightStats, xcTrackState, _ ->
) { flightData, flightStats, _ ->
val items = mutableListOf<DashboardAdapter.Item>()

if (flightData.flights.isEmpty()) {
Expand All @@ -90,32 +85,9 @@ class DashboardFragmentVM @Inject constructor(
).run { items.add(this) }
}

xcTrackState
.takeIf { !it.isSetupDone && !it.isSetupDismissed }
?.let {
val item = XCTrackSetupCardVH.Item(
state = it,
onContinue = {
launch {
val event = DashboardEvents.GrantXCTrackAccess(xcTrackManager.getAccessIntent())
events.postValue(event)
}
},
onDismiss = {
launch { xcTrackManager.setSetupDismiss(true) }
}
)
items.add(item)
}


State(items = items)
}.asLiveData2()

fun takeXCTrackAccessUri(uri: Uri) = launch {
xcTrackManager.takeAccess(uri)
}

data class State(
val items: List<DashboardAdapter.Item>
)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/importer_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:menu="@menu/menu_importer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:title="@string/importer_title" />
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/res/menu/menu_importer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="eu.darken.pgc.main.ui.MainActivity">
<item
android:id="@+id/action_reparse"
android:orderInCategory="100"
android:title="@string/flights_reparse_data_label"
app:showAsAction="never" />

</menu>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,5 @@
<string name="flights_dash_global_count_msg">Total flights: %d</string>
<string name="flights_dash_global_hours_msg">Flight hours: %.2f</string>
<string name="flights_dash_global_locations_msg">Known locations: %d</string>
<string name="flights_reparse_data_label">Reparse existing data</string>
</resources>

0 comments on commit bf86ea2

Please sign in to comment.