https://kotlinlang.org logo
Title
b

benkuly

09/13/2021, 8:36 AM
Is there a way, to have unique singleton coroutines? Background: If someone requests a message, it get's decrypted in a new corountine. But when someone requests the same message again, it should not start a secound coroutine to decrypt it, because there is already a coroutine, which decrypts it.
j

Joffrey

09/13/2021, 8:46 AM
Maybe a
Map<Message, Deferred<DecryptedMessage>>
could help? You would start decryption coroutines with
async {}
and store the returned
Deferred
so that other clients would immediately get the same
Deferred
without starting new coroutines. You then have to decide when you want to evict from this map. Probably as soon as the coroutine is over, but you could also use it as cache
1
💯 1
b

benkuly

09/13/2021, 9:01 AM
Thanks for your idea! Actually it's on client site. I have a Store, which contains (as cache for a db) a list of StateFlow<Message>. Because the UI and the Store should not be aware of how to encrypt message, I have a Service, which acts as middleware. As soon as the UI asks for the message, the Service launches a coroutine to decrypt the Message and update the StateFlow. This works very well, but I'm worried, that multiple coroutines decrypt the same message. This could happen, when the UI asks for the same Message multiple times and the encryption takes a long time (due to fetching of decryption keys). I wanted to prevent to use a Map, because it's not thread-safe.
j

Joffrey

09/13/2021, 12:20 PM
You can always use a concurrent map or protect its accesses by a mutex or something. There are definitely options to use a map safely 😉 Also if your client is Kotlin/JS, then you don't even have multiple threads, so you should be safe 😄
I initially thought that you wanted the decryption method to actually return the decrypted message. If you don't need that (if you just update StateFlows asynchronously) then the map could be even simpler (actually just a set of already decrypted messages), but it depends on how you update your stateflows etc. I have trouble understanding the overall flow here. For instance, how is the UI aware of messages to be decrypted? How does the service know which stateflow to update? etc.
b

benkuly

09/14/2021, 7:37 AM
Maybe it helps to see some code: https://gitlab.com/benkuly/trixnity/-/blob/main/trixnity-client/src/commonMain/kotlin/net/folivo/trixnity/client/room/RoomManager.kt#L468 This is the function, that acts as middleware between the store (which caches the StateFlow of TimelineEvents from a database) and the UI, which just calls this method to retrieve that flow and start the encryption. I think the current implemenation is a good compromise, because the overhead of creating a coroutine should not be that much. But ideally, It would be cool to force the coroutineContext to only hold one coroutine with the same name and drop newer coroutines. Maybe I could iterate over the childrens of the coroutineContext 🤔