From 44b8b10edfbd311751a47be80ff854e98a10083d Mon Sep 17 00:00:00 2001 From: IppeiMukaida Date: Mon, 27 Jan 2020 01:12:37 +0900 Subject: [PATCH] Implement posting thumbs-up count to firestore --- .../confsched2020/data/firestore/Firestore.kt | 1 + .../data/firestore/internal/FirestoreImpl.kt | 75 +++++++++++++++++++ .../droidkaigi/confsched2020/model/Shard.kt | 3 + .../confsched2020/model/ThumbsUpCounter.kt | 3 + 4 files changed, 82 insertions(+) create mode 100644 model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/Shard.kt create mode 100644 model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/ThumbsUpCounter.kt diff --git a/data/firestore/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/data/firestore/Firestore.kt b/data/firestore/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/data/firestore/Firestore.kt index e6ceccf79..2c1d10ce8 100644 --- a/data/firestore/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/data/firestore/Firestore.kt +++ b/data/firestore/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/data/firestore/Firestore.kt @@ -6,4 +6,5 @@ import kotlinx.coroutines.flow.Flow interface Firestore { fun getFavoriteSessionIds(): Flow> suspend fun toggleFavorite(sessionId: SessionId) + fun thumbsUp(sessionId: SessionId): Flow } diff --git a/data/firestore/src/main/java/io/github/droidkaigi/confsched2020/data/firestore/internal/FirestoreImpl.kt b/data/firestore/src/main/java/io/github/droidkaigi/confsched2020/data/firestore/internal/FirestoreImpl.kt index 0e97bdc9d..77c2c2c01 100644 --- a/data/firestore/src/main/java/io/github/droidkaigi/confsched2020/data/firestore/internal/FirestoreImpl.kt +++ b/data/firestore/src/main/java/io/github/droidkaigi/confsched2020/data/firestore/internal/FirestoreImpl.kt @@ -1,15 +1,20 @@ package io.github.droidkaigi.confsched2020.data.firestore.internal +import com.google.android.gms.tasks.Task +import com.google.android.gms.tasks.Tasks import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.DocumentReference import com.google.firebase.firestore.DocumentSnapshot +import com.google.firebase.firestore.FieldValue import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.Query import com.google.firebase.firestore.QuerySnapshot import com.google.firebase.firestore.Source import io.github.droidkaigi.confsched2020.data.firestore.Firestore import io.github.droidkaigi.confsched2020.model.SessionId +import io.github.droidkaigi.confsched2020.model.Shard +import io.github.droidkaigi.confsched2020.model.ThumbsUpCounter import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -20,8 +25,13 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.tasks.await import timber.log.Timber import timber.log.debug +import kotlin.math.floor +import kotlin.math.sin internal class FirestoreImpl @Inject constructor() : Firestore { + companion object { + const val NUM_SHARDS = 10 + } override fun getFavoriteSessionIds(): Flow> { val setupFavorites = flow { @@ -63,6 +73,15 @@ internal class FirestoreImpl @Inject constructor() : Firestore { Timber.debug { "toggleFavorite: end" } } + override fun thumbsUp(sessionId: SessionId): Flow { + return flow { + signInIfNeeded() + val counterRef = createThumbsUpCounterIfNeeded(sessionId = sessionId, numShards = NUM_SHARDS) + incrementThumbsUpCount(counterRef) + emit(getThumbsUpCount(counterRef)) + } + } + private fun getFavoritesRef(): CollectionReference { val firebaseAuth = FirebaseAuth.getInstance() val firebaseUserId = firebaseAuth.currentUser?.uid ?: throw RuntimeException( @@ -83,6 +102,62 @@ internal class FirestoreImpl @Inject constructor() : Firestore { firebaseAuth.signInAnonymously().await() Timber.debug { "signInIfNeeded end" } } + + private suspend fun createThumbsUpCounterIfNeeded(sessionId: SessionId, numShards: Int): DocumentReference { + val firebaseAuth = FirebaseAuth.getInstance() + val firebaseUserId = firebaseAuth.currentUser?.uid ?: throw RuntimeException( + "RuntimeException" + ) + val counterDocumentRef = FirebaseFirestore + .getInstance() + .collection("confsched/2020/sessions/$sessionId/thumbsup_counters") + .document(firebaseUserId) + + if (counterDocumentRef.fastGet().exists()) { + Timber.debug { "createThumbsUpCounterIfNeeded counter already exists" } + return counterDocumentRef + } + + counterDocumentRef.set(ThumbsUpCounter(numShards)) + .continueWithTask { task -> + if (!task.isSuccessful) { + throw task.exception!! + } + + val tasks = arrayListOf>() + + // Initialize each shard with count=0 + for (i in 0 until numShards) { + val makeShard = counterDocumentRef.collection("shards") + .document(i.toString()) + .set(Shard(count = 0)) + + tasks.add(makeShard) + } + + Tasks.whenAll(tasks) + }.await() + + Timber.debug { "createThumbsUpCounterIfNeeded creating counter completed" } + return counterDocumentRef + } + + private fun incrementThumbsUpCount(counterRef: DocumentReference) { + val shardId = floor(Math.random() * NUM_SHARDS).toInt() + counterRef.collection("shards") + .document(shardId.toString()) + .update("count", FieldValue.increment(1)) + } + + private suspend fun getThumbsUpCount(counterRef: DocumentReference): Int { + val shards = counterRef.collection("shards").fastGet() + var count = 0 + shards.forEach { snap -> + val shard = snap.toObject(Shard::class.java) + count += shard.count + } + return count + } } private suspend fun DocumentReference.fastGet(): DocumentSnapshot { diff --git a/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/Shard.kt b/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/Shard.kt new file mode 100644 index 000000000..e8e832881 --- /dev/null +++ b/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/Shard.kt @@ -0,0 +1,3 @@ +package io.github.droidkaigi.confsched2020.model + +data class Shard(val count: Int) diff --git a/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/ThumbsUpCounter.kt b/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/ThumbsUpCounter.kt new file mode 100644 index 000000000..5a0e99aab --- /dev/null +++ b/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2020/model/ThumbsUpCounter.kt @@ -0,0 +1,3 @@ +package io.github.droidkaigi.confsched2020.model + +data class ThumbsUpCounter(val numShards: Int)