diff --git a/src/main/kotlin/chatserver/MessageResult.kt b/src/main/kotlin/chatserver/MessageResult.kt index 56f4c5e..d75564e 100644 --- a/src/main/kotlin/chatserver/MessageResult.kt +++ b/src/main/kotlin/chatserver/MessageResult.kt @@ -1,15 +1,16 @@ package chatserver import chatserver.ReadChatRepository.ReadResult +import chatserver.messages.SupabaseMessageRepository.* data class MessageResult( override val isOk: Boolean, - override val item: List, + override val item: List, override val error: Exception?, ) : - ReadResult> { + ReadResult> { companion object { - fun ok(item: List): MessageResult = MessageResult(true, item, null) + fun ok(item: List): MessageResult = MessageResult(true, item, null) fun fail(e: Exception? = null): MessageResult = MessageResult(false, emptyList(), e) } diff --git a/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt new file mode 100644 index 0000000..d29affd --- /dev/null +++ b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt @@ -0,0 +1,66 @@ +package chatserver.messages + +import chatserver.MessageResult +import chatserver.ReadChatRepository +import chatserver.SubscribeChatRepository +import chatserver.WriteChatRepository +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.annotations.SupabaseExperimental +import io.github.jan.supabase.auth.auth +import io.github.jan.supabase.postgrest.from +import io.github.jan.supabase.realtime.selectAsFlow +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import kotlinx.datetime.Clock +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import java.util.UUID + +class SupabaseMessageRepository( + private val client: SupabaseClient, + private val scope: CoroutineScope, +) : ReadChatRepository, WriteChatRepository, SubscribeChatRepository { + private val messages: MutableStateFlow = MutableStateFlow(MessageResult.ok(emptyList())) + + override fun latest(): MessageResult = messages.value + + override fun observe(): Flow = messages.asStateFlow() + + @OptIn(SupabaseExperimental::class) + override fun subscribe() { + client.from("messages") + .selectAsFlow(Message::id) + .map { MessageResult.ok(it) } + .onEach { messages.value = it } + .catch { println(it) } + .launchIn(scope) + } + + override fun write(item: String) { + scope.launch { + client.from("messages").insert(item.toChatMessage()) + } + } + + private fun String.toChatMessage() = + Message( + id = UUID.randomUUID().toString(), + profileId = client.auth.currentUserOrNull()?.id.orEmpty(), + content = this, + createdAt = Clock.System.now().toString(), + ) + + override fun unsubscribe() { + scope.cancel() + } + + @Serializable + data class Message( + @SerialName("id") val id: String, + @SerialName("profile_id") val profileId: String, + @SerialName("content") val content: String, + @SerialName("created_at") val createdAt: String, + ) +}