chore: implementiere Ping-Feature mit Repository, Sync-Service und API Client

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-21 17:01:58 +02:00
parent a35dfa1434
commit 319cb52160
3 changed files with 110 additions and 0 deletions
@@ -0,0 +1,41 @@
package at.mocode.frontend.features.ping.data
import at.mocode.ping.api.*
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
/**
* PingApi-Implementierung, die einen bereitgestellten HttpClient verwendet (z. B. den per Dependency Injection
* bereitgestellten "apiClient").
*/
class PingApiKoinClient(private val client: HttpClient) : PingApi {
override suspend fun simplePing(): PingResponse {
return client.get("/api/ping/simple").body()
}
override suspend fun enhancedPing(simulate: Boolean): EnhancedPingResponse {
return client.get("/api/ping/enhanced") {
url.parameters.append("simulate", simulate.toString())
}.body()
}
override suspend fun healthCheck(): HealthResponse {
return client.get("/api/ping/health").body()
}
override suspend fun publicPing(): PingResponse {
return client.get("/api/ping/public").body()
}
override suspend fun securePing(): PingResponse {
return client.get("/api/ping/secure").body()
}
override suspend fun syncPings(since: Long): List<PingEvent> {
return client.get("/api/ping/sync") {
url.parameters.append("since", since.toString())
}.body()
}
}
@@ -0,0 +1,43 @@
package at.mocode.frontend.features.ping.data
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
import at.mocode.frontend.core.localdb.AppDatabase
import at.mocode.frontend.core.sync.SyncableRepository
import at.mocode.ping.api.PingEvent
/**
** ARCH-BLUEPRINT: Dieses Repository implementiert das generische Syncable Repository
** für eine bestimmte Entität und überbrückt so die Lücke zwischen dem Sync-Core und der
** lokalen Datenbank.
*/
class PingEventRepositoryImpl(
private val db: AppDatabase
) : SyncableRepository<PingEvent> {
// Der `since`-Parameter für unsere Synchronisierung ist der Zeitstempel des letzten Ereignisses.
// Das Backend erwartet einen Long (Timestamp), keinen String (UUID).
override suspend fun getLatestSince(): String? {
println("PingEventRepositoryImpl: getLatestSince called - fetching latest timestamp")
// Wir holen den letzten Timestamp aus der DB.
val lastModified = db.appDatabaseQueries.selectLatestPingEventTimestamp().awaitAsOneOrNull()
// Wir geben ihn als String zurück, da das Interface String? erwartet.
// Der SyncManager wird ihn als Parameter "since" an den Request hängen.
// Das Backend erwartet "since" als Long, aber HTTP Parameter sind Strings.
// Spring Boot konvertiert "123456789" automatisch in Long 123456789.
return lastModified?.toString()
}
override suspend fun upsert(items: List<PingEvent>) {
// Führen Sie Massenoperationen immer innerhalb einer Transaktion durch.
db.transaction {
items.forEach { event ->
db.appDatabaseQueries.upsertPingEvent(
id = event.id,
message = event.message,
last_modified = event.lastModified
)
}
}
}
}
@@ -0,0 +1,26 @@
package at.mocode.frontend.features.ping.domain
import at.mocode.frontend.core.sync.SyncManager
import at.mocode.frontend.core.sync.SyncableRepository
import at.mocode.ping.api.PingEvent
/**
* Interface für den Ping-Sync-Dienst zur einfacheren Prüfung und Entkopplung.
*/
interface PingSyncService {
suspend fun syncPings()
}
/**
* Implementierung des PingSyncService unter Verwendung des generischen SyncManager.
*/
class PingSyncServiceImpl(
private val syncManager: SyncManager,
private val repository: SyncableRepository<PingEvent>
) : PingSyncService {
override suspend fun syncPings() {
// Corrected endpoint: /api/ping/sync (singular)
syncManager.performSync(repository, "/api/ping/sync")
}
}