2021-01-07 12:17:50 +00:00
|
|
|
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
|
2021-01-06 17:06:48 +00:00
|
|
|
|
2021-06-27 19:00:20 +00:00
|
|
|
import dev.inmo.micro_utils.coroutines.safelyWithResult
|
2021-01-06 17:06:48 +00:00
|
|
|
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
|
|
|
import dev.inmo.tgbotapi.bot.TelegramBot
|
2021-01-07 12:17:50 +00:00
|
|
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
2021-01-06 17:06:48 +00:00
|
|
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
|
|
|
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
|
|
|
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
|
|
|
import dev.inmo.tgbotapi.utils.RiskFeature
|
2021-01-09 16:18:31 +00:00
|
|
|
import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage
|
2021-01-07 06:45:54 +00:00
|
|
|
import kotlinx.coroutines.CancellationException
|
2021-01-06 17:06:48 +00:00
|
|
|
import kotlinx.coroutines.flow.*
|
|
|
|
|
|
|
|
private val cancelledByFilterException = CancellationException("Cancelled by filter precreatedException")
|
|
|
|
|
|
|
|
typealias RequestBuilder<T> = suspend (Update) -> Request<T>
|
|
|
|
typealias NullableRequestBuilder<T> = suspend (Update) -> Request<T>?
|
|
|
|
|
2021-01-07 10:01:25 +00:00
|
|
|
/**
|
|
|
|
* @param initRequest If not null, this request will be sent by [bot] before returning value
|
|
|
|
* @param count If set, result [Flow] will return [count] elements on each [Flow.collect]
|
|
|
|
* @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data
|
|
|
|
* @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say
|
|
|
|
* user that chain of scenario has been cancelled
|
|
|
|
* @param cancelTrigger When this trigger returns true, chain is cancelled
|
|
|
|
* @param filter It is main param, which will be called on each update. When it return not null, result will be returned
|
|
|
|
* as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory]
|
|
|
|
* will be called too), [errorFactory] and then will be returned null
|
|
|
|
*/
|
2021-01-09 16:18:31 +00:00
|
|
|
@RiskFeature(lowLevelRiskFeatureMessage)
|
2021-01-06 17:06:48 +00:00
|
|
|
suspend fun <T> FlowsUpdatesFilter.expectFlow(
|
|
|
|
bot: TelegramBot,
|
|
|
|
initRequest: Request<*>? = null,
|
|
|
|
count: Int? = null,
|
|
|
|
errorFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
2021-01-07 18:22:19 +00:00
|
|
|
filter: suspend (Update) -> List<T>
|
2021-01-06 17:06:48 +00:00
|
|
|
): Flow<T> {
|
2021-01-07 18:22:19 +00:00
|
|
|
val flow = allUpdatesFlow.flatMapConcat {
|
2021-06-27 19:00:20 +00:00
|
|
|
val result = safelyWithResult { filter(it) }
|
|
|
|
(if (result.isFailure || result.getOrThrow().isEmpty()) {
|
2021-01-06 17:06:48 +00:00
|
|
|
if (cancelTrigger(it)) {
|
|
|
|
cancelRequestFactory(it) ?.also {
|
2021-06-27 19:00:20 +00:00
|
|
|
safelyWithResult { bot.execute(it) }
|
2021-01-06 17:06:48 +00:00
|
|
|
throw cancelledByFilterException
|
|
|
|
}
|
|
|
|
}
|
|
|
|
errorFactory(it) ?.also { errorRequest ->
|
|
|
|
safelyWithoutExceptions { bot.execute(errorRequest) }
|
|
|
|
}
|
2021-01-07 18:22:19 +00:00
|
|
|
emptyList()
|
2021-01-06 17:06:48 +00:00
|
|
|
} else {
|
2021-06-27 19:00:20 +00:00
|
|
|
result.getOrThrow()
|
2021-01-07 18:22:19 +00:00
|
|
|
}).asFlow()
|
2021-01-06 17:06:48 +00:00
|
|
|
}
|
|
|
|
val result = if (count == null) {
|
|
|
|
flow
|
|
|
|
} else {
|
|
|
|
flow.take(count)
|
|
|
|
}
|
|
|
|
initRequest ?.also { safelyWithoutExceptions { bot.execute(initRequest) } }
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-01-07 10:01:25 +00:00
|
|
|
/**
|
|
|
|
* @param initRequest If not null, this request will be sent by [bot] before returning value
|
|
|
|
* @param count If set, result [Flow] will return [count] elements on each [Flow.collect]
|
|
|
|
* @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data
|
|
|
|
* @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say
|
|
|
|
* user that chain of scenario has been cancelled
|
|
|
|
* @param cancelTrigger When this trigger returns true, chain is cancelled
|
|
|
|
* @param filter It is main param, which will be called on each update. When it return not null, result will be returned
|
|
|
|
* as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory]
|
|
|
|
* will be called too), [errorFactory] and then will be returned null
|
|
|
|
*/
|
2021-01-07 12:11:01 +00:00
|
|
|
suspend fun <T> BehaviourContext.expectFlow(
|
2021-01-06 17:06:48 +00:00
|
|
|
initRequest: Request<*>? = null,
|
|
|
|
count: Int? = null,
|
|
|
|
errorFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
2021-01-07 18:22:19 +00:00
|
|
|
filter: suspend (Update) -> List<T>
|
2021-01-06 17:06:48 +00:00
|
|
|
) = flowsUpdatesFilter.expectFlow(bot, initRequest, count, errorFactory, cancelRequestFactory, cancelTrigger, filter)
|
|
|
|
|
2021-01-07 10:01:25 +00:00
|
|
|
/**
|
|
|
|
* @param initRequest If not null, this request will be sent by [bot] before returning value
|
|
|
|
* @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data
|
|
|
|
* @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say
|
|
|
|
* user that chain of scenario has been cancelled
|
|
|
|
* @param cancelTrigger When this trigger returns true, chain is cancelled
|
|
|
|
* @param filter It is main param, which will be called on each update. When it return not null, result will be returned
|
|
|
|
* as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory]
|
|
|
|
* will be called too), [errorFactory] and then will be returned null
|
|
|
|
*/
|
2021-01-09 16:18:31 +00:00
|
|
|
@RiskFeature(lowLevelRiskFeatureMessage)
|
2021-01-06 17:06:48 +00:00
|
|
|
suspend fun <T> FlowsUpdatesFilter.expectOne(
|
|
|
|
bot: TelegramBot,
|
|
|
|
initRequest: Request<*>? = null,
|
|
|
|
errorFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
2021-01-07 18:22:19 +00:00
|
|
|
filter: suspend (Update) -> T?
|
|
|
|
): T = expectFlow(bot, initRequest, 1, errorFactory, cancelRequestFactory, cancelTrigger) {
|
|
|
|
listOfNotNull(filter.invoke(it))
|
|
|
|
}.first()
|
2021-01-06 17:06:48 +00:00
|
|
|
|
2021-01-07 10:01:25 +00:00
|
|
|
/**
|
|
|
|
* @param initRequest If not null, this request will be sent by [bot] before returning value
|
|
|
|
* @param errorFactory If set, this factory will be used to produce requests in case when user have sent incorrect data
|
|
|
|
* @param cancelRequestFactory If set, this factory will be used to produce requests in case when it is required to say
|
|
|
|
* user that chain of scenario has been cancelled
|
|
|
|
* @param cancelTrigger When this trigger returns true, chain is cancelled
|
|
|
|
* @param filter It is main param, which will be called on each update. When it return not null, result will be returned
|
|
|
|
* as is, but when it returns null, then will be called [cancelTrigger] (if it will return true - [cancelRequestFactory]
|
|
|
|
* will be called too), [errorFactory] and then will be returned null
|
|
|
|
*/
|
2021-01-07 12:11:01 +00:00
|
|
|
suspend fun <T> BehaviourContext.expectOne(
|
2021-01-06 17:06:48 +00:00
|
|
|
initRequest: Request<*>? = null,
|
|
|
|
errorFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelRequestFactory: NullableRequestBuilder<*> = { null },
|
|
|
|
cancelTrigger: suspend (Update) -> Boolean = { cancelRequestFactory(it) != null },
|
|
|
|
filter: suspend (Update) -> T?
|
|
|
|
) = flowsUpdatesFilter.expectOne(bot, initRequest, errorFactory, cancelRequestFactory, cancelTrigger, filter)
|