/
RemoteBotRepository.kt
85 lines (74 loc) · 2.83 KB
/
RemoteBotRepository.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package de.inovex.blog.aidldemo.chatbot.client
import android.content.Context
import de.inovex.blog.aidldemo.chatbot.lib.Bot
import de.inovex.blog.aidldemo.chatbot.lib.BotDetails
import de.inovex.blog.aidldemo.chatbot.lib.BotManager
import de.inovex.blog.aidldemo.chatbot.lib.IBotService
import de.inovex.blog.aidldemo.chatbot.lib.Message
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.retry
import kotlinx.coroutines.flow.shareIn
import timber.log.Timber
/**
* Repository to consume our API from the client side. Utilizes SharedFlow to have
* a common connection for all calls and automatically handles retries, connection losses
* and tear-downs when no subscriber are registered anymore.
*/
class RemoteBotRepository(
private val context: Context,
coroutineScope: CoroutineScope
) {
private val sharedConnectedBot = callbackFlow<Bot?> {
BotManager.connect(context, object : BotManager.BotServiceCallback {
override fun onConnected(service: IBotService) {
Timber.d("onConnected() called with: service = [$service]")
trySend(Bot(service))
}
override fun onConnectionLost() {
Timber.d("onConnectionLost() called")
cancel("connection to bot service lost")
}
override fun onConnectionFailed(e: Exception) {
Timber.d("onConnectionFailed() called with: e = [$e]")
cancel("connection to bot service failed", e)
}
})
awaitClose {
Timber.d("disconnecting from bot service")
BotManager.disconnect(context)
}
}
.retry(3) {
Timber.d("retry: will retry connection after delay")
delay(1_000L)
return@retry true
}
.catch { emit(null) }
.shareIn(
coroutineScope,
SharingStarted.WhileSubscribed(1_000L, 0),
1
)
@OptIn(ExperimentalCoroutinesApi::class)
fun getMessages(): Flow<List<Message>> =
sharedConnectedBot.flatMapLatest { it?.getMessages() ?: emptyFlow() }
suspend fun getBotDetails(): BotDetails? =
sharedConnectedBot.first()?.getBotDetails()
suspend fun sendMessage(message: Message) {
sharedConnectedBot.first()?.sendMessage(message)
}
suspend fun newSession() {
sharedConnectedBot.first()?.newSession()
}
}