diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index f5e115d..c224ad5 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.kotlin/errors/errors-1731969919007.log b/.kotlin/errors/errors-1731969919007.log
new file mode 100644
index 0000000..1219b50
--- /dev/null
+++ b/.kotlin/errors/errors-1731969919007.log
@@ -0,0 +1,4 @@
+kotlin version: 2.0.21
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+ 1. Kotlin compile daemon is ready
+
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/Dispatch.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/Dispatch.kt
index 6e80352..55efc25 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/Dispatch.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/Dispatch.kt
@@ -1,13 +1,10 @@
package com.github.alice.ktx
-import com.github.alice.ktx.api.dialog.DialogApi
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.handlers.Handler
import com.github.alice.ktx.handlers.error.NetworkErrorHandler
import com.github.alice.ktx.middleware.Middleware
import com.github.alice.ktx.middleware.MiddlewareType
-import com.github.alice.ktx.models.FSMStrategy
-import com.github.alice.ktx.models.request.MessageRequest
-import com.github.alice.ktx.context.FSMContext
/**
* Расширение для `Skill.Builder`, позволяющее настроить `Dispatcher`.
@@ -15,21 +12,13 @@ import com.github.alice.ktx.context.FSMContext
* @param body Функция, принимающая объект `Dispatcher` и позволяющая настроить его.
* Эта функция будет вызвана в контексте `Dispatcher`.
*/
+@AliceDsl
fun Skill.Builder.dispatch(body: Dispatcher.() -> Unit) {
dispatcherConfiguration = body
}
-/**
- * Класс `Dispatcher` управляет обработчиками команд, обработчиками сетевых ошибок и мидлварами.
- *
- * @param fsmStrategy Стратегия конечного автомата состояний (FSM), используемая для управления состояниями.
- */
-class Dispatcher internal constructor(
- internal val fsmStrategy: FSMStrategy,
- val dialogApi: DialogApi? = null,
- internal val fsmContext: (message: MessageRequest) -> FSMContext,
- internal val enableApiStorage: Boolean = false
-) {
+@AliceDsl
+class Dispatcher internal constructor() {
internal val commandHandlers = linkedSetOf()
internal val networkErrorHandlers = linkedSetOf()
internal val middlewares = mutableMapOf>()
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/Skill.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/Skill.kt
index 981f462..4d48462 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/Skill.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/Skill.kt
@@ -1,17 +1,17 @@
package com.github.alice.ktx
import com.github.alice.ktx.api.dialog.DialogApi
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.middleware.MiddlewareType
import com.github.alice.ktx.models.FSMStrategy
-import com.github.alice.ktx.models.Request
-import com.github.alice.ktx.models.request
import com.github.alice.ktx.models.request.MessageRequest
import com.github.alice.ktx.models.response.MessageResponse
-import com.github.alice.ktx.models.toEventRequest
import com.github.alice.ktx.server.WebServer
-import com.github.alice.ktx.server.WebServerResponseListener
-import com.github.alice.ktx.context.FSMContext
-import com.github.alice.ktx.context.impl.BaseFSMContext
+import com.github.alice.ktx.server.WebServerListener
+import com.github.alice.ktx.fsm.FSMContext
+import com.github.alice.ktx.fsm.MutableFSMContext
+import com.github.alice.ktx.fsm.impl.BaseFSMContext
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
import com.github.alice.ktx.storage.Storage
import com.github.alice.ktx.storage.apiStorage.EnableApiStorage
import com.github.alice.ktx.storage.impl.memoryStorage
@@ -24,7 +24,8 @@ import kotlinx.serialization.json.Json
* Эта функция будет вызвана в контексте `Skill.Builder`.
* @return Настроенный объект `Skill`.
*/
-fun skill(body: Skill.Builder.() -> Unit): Skill = Skill.Builder().build(body)
+@AliceDsl
+fun skill(body: Skill.Builder.() -> Unit): Skill = Skill.Builder().apply(body).build()
/**
* Класс `Skill` представляет собой навык, который обрабатывает запросы и управляет состоянием.
@@ -34,38 +35,46 @@ fun skill(body: Skill.Builder.() -> Unit): Skill = Skill.Builder().build(body)
*/
class Skill internal constructor(
private val webServer: WebServer,
- private val dispatcher: Dispatcher
+ private val dispatcher: Dispatcher,
+ private val dialogApi: DialogApi?,
+ private val defaultFSMStrategy: FSMStrategy,
+ private val fsmContext: (message: MessageRequest) -> FSMContext,
+ private val enableApiStorage: Boolean = false
) {
/**
* Конструктор `Builder` для создания экземпляра `Skill`.
*/
+ @AliceDsl
class Builder {
- var id: String? = null
- var json: Json = Json { ignoreUnknownKeys = true }
- var dialogApi: DialogApi? = null
lateinit var webServer: WebServer
- var defaultFSMStrategy: FSMStrategy = FSMStrategy.USER
- internal var dispatcherConfiguration: Dispatcher.() -> Unit = { }
+ var skillId: String? = null
+ var json: Json = Json {
+ isLenient = true
+ ignoreUnknownKeys = true
+ encodeDefaults = true
+ }
+
+ var dialogApi: DialogApi? = null
var storage: Storage = memoryStorage()
+ var defaultFSMStrategy: FSMStrategy = FSMStrategy.USER
var fsmContext: (message: MessageRequest) -> FSMContext = { message ->
- BaseFSMContext(storage, defaultFSMStrategy, message, id)
+ BaseFSMContext(storage, defaultFSMStrategy, message, skillId)
}
- internal fun build(body: Builder.() -> Unit): Skill {
- body()
+ internal var dispatcherConfiguration: Dispatcher.() -> Unit = { }
+ fun build(): Skill {
return Skill(
webServer = webServer,
- dispatcher = Dispatcher(
- fsmStrategy = defaultFSMStrategy,
- dialogApi = dialogApi,
- fsmContext = fsmContext,
- enableApiStorage = storage.javaClass.isAnnotationPresent(EnableApiStorage::class.java)
- ).apply(dispatcherConfiguration)
+ dialogApi = dialogApi,
+ defaultFSMStrategy = defaultFSMStrategy,
+ fsmContext = fsmContext,
+ enableApiStorage = storage.javaClass.isAnnotationPresent(EnableApiStorage::class.java),
+ dispatcher = Dispatcher().apply(dispatcherConfiguration)
)
}
}
@@ -83,25 +92,24 @@ class Skill internal constructor(
*
* @return Реализованный объект `WebServerResponseListener`, который обрабатывает входящие сообщения и ошибки.
*/
- private fun webServerResponseCallback(): WebServerResponseListener = object : WebServerResponseListener {
- override suspend fun messageHandle(model: MessageRequest): MessageResponse? {
- val request = dispatcher.request(model)
- val eventRequest = request.toEventRequest()
+ private fun webServerResponseCallback(): WebServerListener = object : WebServerListener {
+ override suspend fun handleRequest(model: MessageRequest): MessageResponse? {
+ val requestEnvironment = createRequestEnvironment(model)
- runMiddlewares(request, MiddlewareType.OUTER)?.let { return it }
+ runMiddlewares(requestEnvironment, MiddlewareType.OUTER)?.let { return it }
dispatcher.commandHandlers.forEach { handler ->
- if (handler.event(eventRequest)) {
- runMiddlewares(request, MiddlewareType.INNER)?.let { return it }
- return handler.handle(request)
+ if (handler.shouldHandle(requestEnvironment)) {
+ runMiddlewares(requestEnvironment, MiddlewareType.INNER)?.let { return it }
+ return handler.processRequest(requestEnvironment)
}
}
return null
}
- override suspend fun responseFailure(model: MessageRequest, ex: Exception): MessageResponse? {
- val request = dispatcher.request(model)
+ override suspend fun handleError(model: MessageRequest, exception: Exception): MessageResponse? {
+ val request = createRequestEnvironment(model)
dispatcher.networkErrorHandlers.forEach { errorHandler ->
- errorHandler.responseFailure(request, ex)?.let { response ->
+ errorHandler.responseFailure(request, exception)?.let { response ->
return response
}
}
@@ -114,13 +122,29 @@ class Skill internal constructor(
* @param type Тип мидлвари, который следует выполнить.
* @return `MessageResponse?` — ответ от мидлвари, или `null`, если обработка не завершена.
*/
- private suspend fun runMiddlewares(request: Request, type: MiddlewareType): MessageResponse? {
+ private suspend fun runMiddlewares(
+ request: ProcessRequestEnvironment,
+ type: MiddlewareType
+ ): MessageResponse? {
dispatcher.middlewares[type]?.forEach { middleware ->
- middleware.invoke(request)?.let { response ->
+ middleware.process(request)?.let { response ->
return response
}
}
return null
}
}
+
+ private suspend fun createRequestEnvironment(message: MessageRequest): ProcessRequestEnvironment {
+ val context = fsmContext(message)
+ context.init()
+
+ return object : ProcessRequestEnvironment {
+ override val message: MessageRequest = message
+ override val context: MutableFSMContext = context
+ override val dialogApi: DialogApi? = this@Skill.dialogApi
+ override val fsmStrategy: FSMStrategy = this@Skill.defaultFSMStrategy
+ override val enableApiStorage: Boolean = this@Skill.enableApiStorage
+ }
+ }
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt
index a06f8a4..225d6d9 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt
@@ -13,7 +13,7 @@ sealed interface Response {
* @param T Тип данных, которые были бы возвращены в успешном ответе.
* @param message Сообщение об ошибке, объясняющее причину неудачи.
*/
- data class Failed(val message: String): Response
+ data class Failed(val message: String, val code: Int): Response
/**
* Представляет успешный ответ.
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt
index a4b1ee9..c91bd95 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt
@@ -16,5 +16,5 @@ suspend inline fun HttpResponse.response(): Response {
return if(status.value in 200..299)
Response.Success(this.body())
else
- Response.Failed(this.body().message)
+ Response.Failed(this.body().message, status.value)
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt
index 2ced355..817d00d 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt
@@ -11,6 +11,7 @@ import com.github.alice.ktx.api.dialog.yandex.models.image.response.Images
import com.github.alice.ktx.api.dialog.yandex.models.sounds.response.SoundUpload
import com.github.alice.ktx.api.dialog.yandex.models.sounds.response.Sounds
import com.github.alice.ktx.api.dialog.yandex.models.status.Status
+import com.github.alice.ktx.common.AliceDsl
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
@@ -24,10 +25,11 @@ import io.ktor.util.*
import kotlinx.serialization.json.Json
import java.io.File
+@AliceDsl
fun Skill.Builder.ktorYandexDialogApi(body: KtorYandexDialogApi.Builder.() -> Unit): KtorYandexDialogApi {
- val id = id
+ val id = skillId
?: throw IllegalArgumentException("Skill ID не может быть null. Убедитесь, что ID установлен перед вызовом метода.")
- return KtorYandexDialogApi.Builder().setJson(json).apply(body).build(id)
+ return KtorYandexDialogApi.Builder().json(json).apply(body).build(id)
}
/**
@@ -41,14 +43,15 @@ class KtorYandexDialogApi(
private val configuration: HttpClientConfig.() -> Unit
): DialogApi {
+ @AliceDsl
class Builder {
lateinit var oauthToken: String
+ lateinit var json: Json
- private lateinit var json: Json
var configuration: HttpClientConfig.() -> Unit = {}
- internal fun setJson(json: Json): Builder {
+ internal fun json(json: Json): Builder {
this.json = json
return this
}
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/image/Image.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/image/Image.kt
index 21e023b..8ee3fed 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/image/Image.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/image/Image.kt
@@ -1,6 +1,6 @@
package com.github.alice.ktx.api.dialog.yandex.models.image
-import com.github.alice.ktx.common.LocalDateTimeSerializer
+import com.github.alice.ktx.common.serializers.LocalDateTimeSerializer
import kotlinx.serialization.Serializable
import java.time.LocalDateTime
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/sounds/Sound.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/sounds/Sound.kt
index 2831b70..588f97d 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/sounds/Sound.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/sounds/Sound.kt
@@ -1,6 +1,6 @@
package com.github.alice.ktx.api.dialog.yandex.models.sounds
-import com.github.alice.ktx.common.LocalDateTimeSerializer
+import com.github.alice.ktx.common.serializers.LocalDateTimeSerializer
import kotlinx.serialization.Serializable
import java.time.LocalDateTime
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Annotations.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Annotations.kt
new file mode 100644
index 0000000..6d64230
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Annotations.kt
@@ -0,0 +1,9 @@
+package com.github.alice.ktx.common
+
+@DslMarker
+@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
+annotation class AliceDsl
+
+@DslMarker
+@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
+annotation class AliceResponseDsl
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Redis.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Redis.kt
new file mode 100644
index 0000000..59760ed
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/Redis.kt
@@ -0,0 +1,57 @@
+package com.github.alice.ktx.common
+
+import io.lettuce.core.RedisClient
+import io.lettuce.core.api.StatefulRedisConnection
+
+/**
+ * Формирует строку URI для подключения к Redis на основе заданных параметров.
+ *
+ * @param host Хост Redis-сервера. По умолчанию "localhost".
+ * @param port Порт Redis-сервера. По умолчанию 6379.
+ * @param username Необязательное имя пользователя для аутентификации. Если null, имя пользователя не указывается.
+ * @param password Необязательный пароль для аутентификации. Если null, пароль не указывается.
+ * @return Строка URI для подключения к Redis.
+ *
+ * Примеры:
+ * - Если указаны только `host` и `port`: "redis://localhost:6379"
+ * - Если указан `password` без `username`: "redis://:password@localhost:6379"
+ * - Если указаны и `username`, и `password`: "redis://username:password@localhost:6379"
+ */
+fun redisUri(
+ host: String = "localhost",
+ port: Int = 6379,
+ username: String? = null,
+ password: String? = null
+): String {
+ return if (password != null) {
+ if (username != null) {
+ "redis://$username:$password@$host:$port"
+ } else {
+ "redis://:$password@$host:$port"
+ }
+ } else {
+ "redis://$host:$port"
+ }
+}
+
+/**
+ * Устанавливает соединение с Redis-сервером, используя параметры подключения.
+ *
+ * Этот метод создает подключение к Redis с использованием клиента, полученного
+ * из URI, сформированного на основе переданных параметров.
+ *
+ * @param host Хост Redis-сервера. По умолчанию "localhost".
+ * @param port Порт Redis-сервера. По умолчанию 6379.
+ * @param username Необязательное имя пользователя для аутентификации. Если null, имя пользователя не указывается.
+ * @param password Необязательный пароль для аутентификации. Если null, пароль не указывается.
+ * @return Объект StatefulRedisConnection, представляющий подключение к Redis.
+ */
+fun connectToRedis(
+ host: String = "localhost",
+ port: Int = 6379,
+ username: String? = null,
+ password: String? = null
+): StatefulRedisConnection {
+ val redisClient = RedisClient.create(redisUri(host, port, username, password))
+ return redisClient.connect()
+}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/LocalDateTimeSerializer.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/serializers/LocalDateTimeSerializer.kt
similarity index 95%
rename from alice-ktx/src/main/kotlin/com/github/alice/ktx/common/LocalDateTimeSerializer.kt
rename to alice-ktx/src/main/kotlin/com/github/alice/ktx/common/serializers/LocalDateTimeSerializer.kt
index 3dc37eb..f20baf9 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/LocalDateTimeSerializer.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/common/serializers/LocalDateTimeSerializer.kt
@@ -1,4 +1,4 @@
-package com.github.alice.ktx.common
+package com.github.alice.ktx.common.serializers
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/FSMContext.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/FSMContext.kt
similarity index 89%
rename from alice-ktx/src/main/kotlin/com/github/alice/ktx/context/FSMContext.kt
rename to alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/FSMContext.kt
index 5dafe6e..ec115cb 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/FSMContext.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/FSMContext.kt
@@ -1,4 +1,4 @@
-package com.github.alice.ktx.context
+package com.github.alice.ktx.fsm
/**
* Интерфейс для доступа к информации состояния конкретного пользователя.
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/MutableFSMContext.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/MutableFSMContext.kt
similarity index 98%
rename from alice-ktx/src/main/kotlin/com/github/alice/ktx/context/MutableFSMContext.kt
rename to alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/MutableFSMContext.kt
index 6f52089..bea4b4a 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/MutableFSMContext.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/MutableFSMContext.kt
@@ -1,4 +1,4 @@
-package com.github.alice.ktx.context
+package com.github.alice.ktx.fsm
import com.github.alice.ktx.models.FSMStrategy
import kotlin.reflect.KClass
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/ReadOnlyFSMContext.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/ReadOnlyFSMContext.kt
similarity index 96%
rename from alice-ktx/src/main/kotlin/com/github/alice/ktx/context/ReadOnlyFSMContext.kt
rename to alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/ReadOnlyFSMContext.kt
index d8a2333..70a3cbe 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/ReadOnlyFSMContext.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/ReadOnlyFSMContext.kt
@@ -1,4 +1,4 @@
-package com.github.alice.ktx.context
+package com.github.alice.ktx.fsm
import com.github.alice.ktx.models.FSMStrategy
import kotlin.reflect.KClass
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/impl/BaseFSMContext.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/impl/BaseFSMContext.kt
similarity index 98%
rename from alice-ktx/src/main/kotlin/com/github/alice/ktx/context/impl/BaseFSMContext.kt
rename to alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/impl/BaseFSMContext.kt
index 357a197..9c57618 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/context/impl/BaseFSMContext.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/fsm/impl/BaseFSMContext.kt
@@ -1,8 +1,8 @@
-package com.github.alice.ktx.context.impl
+package com.github.alice.ktx.fsm.impl
import com.github.alice.ktx.models.FSMStrategy
import com.github.alice.ktx.models.request.MessageRequest
-import com.github.alice.ktx.context.FSMContext
+import com.github.alice.ktx.fsm.FSMContext
import com.github.alice.ktx.storage.Storage
import com.github.alice.ktx.storage.apiStorage.ApiStorageDetails
import com.github.alice.ktx.storage.models.StorageKey
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/Handler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/Handler.kt
index 96b4780..415cd53 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/Handler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/Handler.kt
@@ -1,7 +1,7 @@
package com.github.alice.ktx.handlers
-import com.github.alice.ktx.models.EventRequest
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
/**
@@ -14,10 +14,10 @@ interface Handler {
/**
* Определяет, сработает ли обработчик для данного сообщения.
*
- * @param message Сообщение, которое проверяется на соответствие условиям обработчика.
+ * @param request Запрос, который проверяется на соответствие условиям обработчика.
* @return `true`, если обработчик должен сработать для данного сообщения; `false` в противном случае.
*/
- suspend fun event(request: EventRequest): Boolean
+ suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean
/**
* Выполняет обработку запроса сообщения и возвращает ответ.
@@ -25,5 +25,5 @@ interface Handler {
* @param request Запрос сообщения, который будет обработан.
* @return Ответ на запрос в виде `MessageResponse`.
*/
- suspend fun handle(request: Request): MessageResponse
+ suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ProcessRequestEnvironment.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ProcessRequestEnvironment.kt
new file mode 100644
index 0000000..155ea50
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ProcessRequestEnvironment.kt
@@ -0,0 +1,14 @@
+package com.github.alice.ktx.handlers.environments
+
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.fsm.MutableFSMContext
+import com.github.alice.ktx.models.FSMStrategy
+
+@AliceDsl
+interface ProcessRequestEnvironment : ShouldRequestEnvironment {
+
+ override val context: MutableFSMContext
+
+ val fsmStrategy: FSMStrategy
+ val enableApiStorage: Boolean
+}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ShouldRequestEnvironment.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ShouldRequestEnvironment.kt
new file mode 100644
index 0000000..d61c016
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/environments/ShouldRequestEnvironment.kt
@@ -0,0 +1,18 @@
+package com.github.alice.ktx.handlers.environments
+
+import com.github.alice.ktx.api.dialog.DialogApi
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.fsm.ReadOnlyFSMContext
+import com.github.alice.ktx.handlers.filters.Filter
+import com.github.alice.ktx.models.request.MessageRequest
+
+@AliceDsl
+interface ShouldRequestEnvironment {
+ val message: MessageRequest
+ val context: ReadOnlyFSMContext
+ val dialogApi: DialogApi?
+
+ fun filter(filter: Filter): Boolean {
+ return filter.checkFor(this)
+ }
+}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/error/NetworkErrorHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/error/NetworkErrorHandler.kt
index 1020a6c..60d58ba 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/error/NetworkErrorHandler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/error/NetworkErrorHandler.kt
@@ -1,23 +1,26 @@
package com.github.alice.ktx.handlers.error
import com.github.alice.ktx.Dispatcher
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
import kotlin.reflect.KClass
/**
* Расширение для `Dispatcher`, добавляющее обработку сетевых ошибок с помощью заданных функций.
*
- * @param event Функция, которая вызывается при возникновении ошибки. Принимает `Exception` и возвращает `Boolean`.
+ * @param shouldHandle Функция, которая вызывается при возникновении ошибки. Принимает `Exception` и возвращает `Boolean`.
* Если функция возвращает `true`, вызывается обработчик `handle`.
- * @param handle Функция-обработчик, которая вызывается, если `event` возвращает `true`. Принимает `Exception` и возвращает `MessageResponse?`.
+ * @param processRequest Функция-обработчик, которая вызывается, если `event` возвращает `true`. Принимает `Exception` и возвращает `MessageResponse?`.
*/
+@AliceDsl
fun Dispatcher.responseFailure(
- event: suspend Request.(ex: Exception) -> Boolean,
- handle: suspend Request.(ex: Exception) -> MessageResponse?,
+ shouldHandle: suspend ShouldRequestEnvironment.(exception: Exception) -> Boolean,
+ processRequest: suspend ProcessRequestEnvironment.(exception: Exception) -> MessageResponse?,
) {
networkError { request, ex ->
- if(request.event(ex)) return@networkError request.handle(ex)
+ if(request.shouldHandle(ex)) return@networkError request.processRequest(ex)
null
}
}
@@ -28,7 +31,11 @@ fun Dispatcher.responseFailure(
* @param thClass Класс исключения, которое должно быть обработано.
* @param block Функция-обработчик, которая вызывается, если исключение принадлежит классу `thClass`. Принимает исключение типа `E` и возвращает `MessageResponse?`.
*/
-fun Dispatcher.responseFailure(thClass: KClass, block: suspend Request.(ex: E) -> MessageResponse?) {
+@AliceDsl
+fun Dispatcher.responseFailure(
+ thClass: KClass,
+ block: suspend ProcessRequestEnvironment.(exception: E) -> MessageResponse?
+) {
networkError { request, ex ->
if (thClass.isInstance(ex)) {
@Suppress("UNCHECKED_CAST")
@@ -43,7 +50,8 @@ fun Dispatcher.responseFailure(thClass: KClass, block: suspen
*
* @param block Функция-обработчик, которая вызывается при возникновении ошибки. Принимает `Exception` и возвращает `MessageResponse?`.
*/
-fun Dispatcher.responseFailure(block: suspend Request.(ex: Exception) -> MessageResponse?) {
+@AliceDsl
+fun Dispatcher.responseFailure(block: suspend ProcessRequestEnvironment.(exception: Exception) -> MessageResponse?) {
networkError { request, ex -> block(request, ex) }
}
@@ -53,12 +61,13 @@ fun Dispatcher.responseFailure(block: suspend Request.(ex: Exception) -> Message
* @param responseFailure Функция-обработчик, которая вызывается при возникновении ошибки. Принимает модель запроса и исключение, возвращает `MessageResponse?`.
* По умолчанию, возвращает `null`, что позволяет передать событие следующему обработчику.
*/
+@AliceDsl
fun Dispatcher.networkError(
- responseFailure: suspend (model: Request, ex: Exception) -> MessageResponse? = { _, _ -> null }
+ responseFailure: suspend (model: ProcessRequestEnvironment, exception: Exception) -> MessageResponse? = { _, _ -> null }
) {
val networkErrorHandler = object : NetworkErrorHandler {
- override suspend fun responseFailure(request: Request, ex: Exception): MessageResponse? {
- return responseFailure(request, ex)
+ override suspend fun responseFailure(request: ProcessRequestEnvironment, exception: Exception): MessageResponse? {
+ return responseFailure(request, exception)
}
}
networkError(networkErrorHandler)
@@ -80,11 +89,11 @@ interface NetworkErrorHandler {
/**
* Вызывается при возникновении ошибки
* @param request Запроса, при обработке которого произошла ошибка.
- * @param ex Исключение, которое возникло.
+ * @param exception Исключение, которое возникло.
*
* [responseFailure] должен всегда возвращать null чтобы передать событие следующему хэндлеру.
* Если вы хотите завершить обработку события, вы должны вернуть [MessageResponse]
*
* */
- suspend fun responseFailure(request: Request, ex: Exception): MessageResponse? = null
+ suspend fun responseFailure(request: ProcessRequestEnvironment, exception: Exception): MessageResponse? = null
}
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/filters/Filter.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/filters/Filter.kt
new file mode 100644
index 0000000..ac0db40
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/filters/Filter.kt
@@ -0,0 +1,75 @@
+package com.github.alice.ktx.handlers.filters
+
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
+import com.github.alice.ktx.models.request.RequestContentType
+
+interface Filter {
+ fun checkFor(request: ShouldRequestEnvironment): Boolean = request.predicate()
+ fun ShouldRequestEnvironment.predicate(): Boolean
+
+ infix fun and(otherFilter: Filter): Filter = object : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean =
+ this@Filter.checkFor(this) && otherFilter.checkFor(this)
+ }
+
+ infix fun or(otherFilter: Filter): Filter = object : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean =
+ this@Filter.checkFor(this) || otherFilter.checkFor(this)
+ }
+
+ operator fun not(): Filter = object : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = !this@Filter.checkFor(this)
+ }
+
+ class Custom(private val customPredicate: ShouldRequestEnvironment.() -> Boolean) : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = customPredicate()
+ }
+
+ object All : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = true
+ }
+
+ class Text(private val text: String? = null): Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean {
+ return text?.let {
+ message.request.originalUtterance?.contains(it, ignoreCase = true) == true
+ } ?: (message.request.originalUtterance != null)
+ }
+ }
+
+ class Type(private val type: RequestContentType) : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.request.type == type
+ }
+
+ /**
+ * Пользователь может видеть ответ навыка на экране и открывать ссылки в браузере.
+ * */
+ object Screen : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.meta.interfaces.screen != null
+ }
+
+ /**
+ * У пользователя есть возможность запросить [связку аккаунтов](https://yandex.ru/dev/dialogs/alice/doc/ru/auth/when-to-use).
+ * */
+ object AccountLinking : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.meta.interfaces.accountLinking != null
+ }
+
+ /**
+ * На устройстве пользователя есть аудиоплеер.
+ * */
+ object AudioPlayer : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.meta.interfaces.audioPlayer != null
+ }
+
+ /**
+ * Признак новой сессии.
+ * */
+ object NewSession : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.session.new
+ }
+
+ object Authorized : Filter {
+ override fun ShouldRequestEnvironment.predicate(): Boolean = message.session.user?.userId != null
+ }
+}
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/ButtonPressedHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/ButtonPressedHandler.kt
index 2fb8953..ec7f088 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/ButtonPressedHandler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/ButtonPressedHandler.kt
@@ -1,40 +1,58 @@
package com.github.alice.ktx.handlers.impl
import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.handlers.Handler
-import com.github.alice.ktx.models.EventRequest
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.request.RequestContentType
import com.github.alice.ktx.models.response.MessageResponse
-import com.github.alice.ktx.context.ReadOnlyFSMContext
-data class EventButtonPressed(
- val context: ReadOnlyFSMContext,
- val payload: Map
-)
+@AliceDsl
+data class ButtonPressedShouldHandleEnvironment(
+ private val requestEnvironment: ShouldRequestEnvironment
+): ShouldRequestEnvironment by requestEnvironment {
+ val payload: Map = requestEnvironment.message.request.payload
+}
+
+/**
+ * Функция расширения для `Dispatcher`, которая добавляет обработчик событий для нажатия кнопки.
+ *
+ * Навык получает запрос с типом ButtonPressed, если в предыдущем ответе пользователь нажал:
+ *
+ * 1. отдельную кнопку (свойство hide со значением true) с непустым полем payload;
+ * 2. изображение (тип BigImage) с непустым полем payload в card.button;
+ * 3. элемент списка (тип ItemList) с непустым полем payload в items.button;
+ * 4. изображение из галереи (тип ImageGallery) с непустым полем payload в items.button.
+ *
+ * @param shouldHandle Логика, определяющая, должен ли обработчик сработать для данного события.
+ * @param processRequest Логика обработки запроса, если событие было подтверждено.
+ */
+@AliceDsl
fun Dispatcher.buttonPressed(
- event: suspend EventButtonPressed.() -> Boolean = { true },
- handle: suspend Request.() -> MessageResponse
+ shouldHandle: suspend ButtonPressedShouldHandleEnvironment.() -> Boolean = { true },
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
) {
addHandler(
ButtonPressedHandler(
- eventBlock = event,
- handleBlock = handle
+ shouldHandleBlock = shouldHandle,
+ processRequestBlock = processRequest
)
)
}
internal class ButtonPressedHandler(
- private val eventBlock: suspend EventButtonPressed.() -> Boolean,
- private val handleBlock: suspend Request.() -> MessageResponse
+ private val shouldHandleBlock: suspend ButtonPressedShouldHandleEnvironment.() -> Boolean,
+ private val processRequestBlock: suspend ProcessRequestEnvironment.() -> MessageResponse
) : Handler {
- override suspend fun event(request: EventRequest): Boolean {
+
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean {
return request.message.request.type == RequestContentType.ButtonPressed &&
- eventBlock(EventButtonPressed(context = request.context, payload = request.message.request.payload!!))
+ shouldHandleBlock(ButtonPressedShouldHandleEnvironment(request))
}
- override suspend fun handle(request: Request): MessageResponse {
- return handleBlock(request)
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse {
+ return processRequestBlock(request)
}
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/HelpHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/HelpHandler.kt
index 81c96de..d68ca93 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/HelpHandler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/HelpHandler.kt
@@ -1,24 +1,46 @@
package com.github.alice.ktx.handlers.impl
import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.handlers.Handler
-import com.github.alice.ktx.models.EventRequest
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
+/**
+ * Функция расширения для `Dispatcher`, которая добавляет обработчик для запроса помощи.
+ * Этот обработчик срабатывает, когда пользователь запрашивает помощь.
+ *
+ * @param processRequest Логика обработки запроса, которая будет выполнена, когда сработает обработчик.
+ */
+@AliceDsl
fun Dispatcher.help(
- handle: suspend Request.() -> MessageResponse
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
) {
- addHandler(HelpHandler(handleBlock = handle))
+ addHandler(HelpHandler(processRequestBlock = processRequest))
}
internal class HelpHandler(
- private val handleBlock: suspend Request.() -> MessageResponse
+ private val processRequestBlock: suspend ProcessRequestEnvironment.() -> MessageResponse
) : Handler {
- override suspend fun event(request: EventRequest): Boolean {
- return request.message.request.command == "помощь" || request.message.request.command == "что ты умеешь"
+ /**
+ * Определяет, должен ли обработчик сработать для данного запроса.
+ * Обработчик срабатывает, если команда запроса соответствует "помощь".
+ *
+ * @param request Запрос, который проверяется.
+ * @return `true`, если команда запроса соответствует "помощь";
+ * `false` в противном случае.
+ */
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean {
+ return request.message.request.command == "помощь"
}
- override suspend fun handle(request: Request): MessageResponse = handleBlock(request)
+ /**
+ * Выполняет обработку запроса и возвращает соответствующий ответ.
+ *
+ * @param request Запрос, который будет обработан.
+ * @return Ответ на запрос в виде `MessageResponse`.
+ */
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse = processRequestBlock(request)
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/MessageHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/MessageHandler.kt
index aaaf10d..a9e5353 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/MessageHandler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/MessageHandler.kt
@@ -1,43 +1,83 @@
package com.github.alice.ktx.handlers.impl
import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.handlers.Handler
-import com.github.alice.ktx.models.EventRequest
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
/**
- * Расширение для `Dispatcher`, позволяющее установить обработчик сообщений.
+ * Окружение для проверки, следует ли обрабатывать сообщение.
+ */
+@AliceDsl
+data class MessageShouldHandleEnvironment(
+ private val request: ShouldRequestEnvironment
+) : ShouldRequestEnvironment by request {
+
+ val command = request.message.request.command ?: ""
+ val messageText = request.message.request.originalUtterance ?: ""
+}
+
+/**
+ * Окружение для обработки запроса сообщения.
+ */
+@AliceDsl
+data class MessageProcessRequestEnvironment(
+ private val request: ProcessRequestEnvironment
+) : ProcessRequestEnvironment by request {
+
+ val command = request.message.request.command ?: ""
+ val messageText = request.message.request.originalUtterance ?: ""
+}
+
+/**
+ * Функция расширения для `Dispatcher`, которая добавляет обработчик для сообщений.
+ * Этот обработчик срабатывает, если:
*
- * @param event Функция-условие, определяющая, должен ли обработчик сработать для данного события. Принимает объект `EventMessage` и возвращает `Boolean`.
- * @param handle Функция-обработчик, которая будет вызвана, если условие события возвращает `true`. Принимает объект `Request` и возвращает `MessageResponse`.
+ * 1. Пользователь произносит фразу.
+ * 2. Пользователь нажимает кнопку в бабле из предыдущего ответа навыка (свойство hide со значением false).
+ * 3. Пользователь нажимает отдельную кнопку в предыдущем ответе навыка (свойство hide со значением true) с отсутствующим значением в поле payload.
+ *
+ * @param shouldHandle Логика, которая определяет, следует ли обрабатывать это сообщение.
+ * @param processRequest Логика обработки сообщения, которая будет выполнена при удовлетворении условиям.
*/
+@AliceDsl
fun Dispatcher.message(
- event: suspend EventRequest.() -> Boolean = { true },
- handle: suspend Request.() -> MessageResponse
+ shouldHandle: suspend MessageShouldHandleEnvironment.() -> Boolean = { true },
+ processRequest: suspend MessageProcessRequestEnvironment.() -> MessageResponse
) {
addHandler(
MessageHandler(
- eventBlock = event,
- handleBlock = handle
+ shouldHandleBlock = shouldHandle,
+ processRequestBlock = processRequest
)
)
}
-/**
- * Внутренний класс `MessageHandler`, реализующий интерфейс `Handler`.
- *
- * @param eventBlock Функция, определяющая условие срабатывания обработчика. Принимает объект `MessageRequest` и возвращает `Boolean`.
- * @param handleBlock Функция-обработчик запроса. Принимает объект `MessageRequest` и возвращает `MessageResponse`.
- */
internal class MessageHandler(
- private val eventBlock: suspend EventRequest.() -> Boolean,
- private val handleBlock: suspend Request.() -> MessageResponse
+ private val shouldHandleBlock: suspend MessageShouldHandleEnvironment.() -> Boolean,
+ private val processRequestBlock: suspend MessageProcessRequestEnvironment.() -> MessageResponse
) : Handler {
- override suspend fun event(request: EventRequest): Boolean = eventBlock(request)
-
- override suspend fun handle(request: Request): MessageResponse {
- return handleBlock(request)
+ /**
+ * Определяет, следует ли обрабатывать данный запрос.
+ *
+ * @param request Запрос, который проверяется.
+ * @return `true`, если обработчик должен сработать, в противном случае `false`.
+ */
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean {
+ return request.message.request.command != null &&
+ request.message.request.originalUtterance != null &&
+ shouldHandleBlock(MessageShouldHandleEnvironment(request))
}
+
+ /**
+ * Выполняет обработку запроса и возвращает соответствующий ответ.
+ *
+ * @param request Запрос, который будет обработан.
+ * @return Ответ на запрос в виде `MessageResponse`.
+ */
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse =
+ processRequestBlock(MessageProcessRequestEnvironment(request))
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/NewSessionHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/NewSessionHandler.kt
index 1c2ca29..d2baf4f 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/NewSessionHandler.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/NewSessionHandler.kt
@@ -1,33 +1,55 @@
package com.github.alice.ktx.handlers.impl
import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
import com.github.alice.ktx.handlers.Handler
-import com.github.alice.ktx.models.EventRequest
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
+/**
+ * Функция расширения для `Dispatcher`, которая добавляет обработчик для нового сеанса.
+ * Этот обработчик срабатывает, когда создается новый сеанс, и выполняет соответствующую логику.
+ *
+ * @param shouldHandle Логика, которая определяет, должен ли обработчик сработать для данного запроса.
+ * @param processRequest Логика обработки запроса, которая будет выполнена, когда сработает обработчик.
+ */
+@AliceDsl
fun Dispatcher.newSession(
- event: suspend EventRequest.() -> Boolean = { true },
- handle: suspend Request.() -> MessageResponse
+ shouldHandle: suspend ShouldRequestEnvironment.() -> Boolean = { true },
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
) {
addHandler(
NewSessionHandler(
- eventBlock = event,
- handleBlock = handle
+ shouldHandleBlock = shouldHandle,
+ processRequestBlock = processRequest
)
)
}
internal class NewSessionHandler(
- private val eventBlock: suspend EventRequest.() -> Boolean,
- private val handleBlock: suspend Request.() -> MessageResponse
+ private val shouldHandleBlock: suspend ShouldRequestEnvironment.() -> Boolean,
+ private val processRequestBlock: suspend ProcessRequestEnvironment.() -> MessageResponse
) : Handler {
- override suspend fun event(request: EventRequest): Boolean {
- return request.message.session.new && eventBlock(request)
+ /**
+ * Определяет, сработает ли обработчик для данного запроса.
+ * Обработчик срабатывает, если запрос связан с новым сеансом.
+ *
+ * @param request Запрос, который проверяется.
+ * @return `true`, если запрос относится к новому сеансу и условие `shouldHandle` выполняется.
+ */
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean {
+ return request.message.session.new && shouldHandleBlock(request)
}
- override suspend fun handle(request: Request): MessageResponse {
- return handleBlock(request)
+ /**
+ * Выполняет обработку запроса и возвращает соответствующий ответ.
+ *
+ * @param request Запрос, который будет обработан.
+ * @return Ответ на запрос в виде `MessageResponse`.
+ */
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse {
+ return processRequestBlock(request)
}
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/RequestHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/RequestHandler.kt
new file mode 100644
index 0000000..647a09d
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/RequestHandler.kt
@@ -0,0 +1,63 @@
+package com.github.alice.ktx.handlers.impl
+
+import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.handlers.Handler
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
+import com.github.alice.ktx.handlers.filters.Filter
+import com.github.alice.ktx.models.response.MessageResponse
+
+@AliceDsl
+fun Dispatcher.request(
+ filler: Filter,
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
+) {
+ request(
+ shouldHandle = { filler.checkFor(this) },
+ processRequest = processRequest
+ )
+}
+
+/**
+ * Регистрация обработчика для всех типов запросов.
+ * Этот метод позволяет настроить обработчик для любых запросов,
+ * независимо от их типа.
+ *
+ * @param shouldHandle Логика, определяющая, должен ли обработчик сработать для данного запроса.
+ * @param processRequest Логика обработки запроса, которая выполняется, если запрос должен быть обработан.
+ */
+@AliceDsl
+fun Dispatcher.request(
+ shouldHandle: suspend ShouldRequestEnvironment.() -> Boolean = { true },
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
+) {
+ addHandler(
+ RequestHandler(
+ shouldHandleBlock = shouldHandle,
+ processRequestBlock = processRequest
+ )
+ )
+}
+
+internal class RequestHandler(
+ private val shouldHandleBlock: suspend ShouldRequestEnvironment.() -> Boolean,
+ private val processRequestBlock: suspend ProcessRequestEnvironment.() -> MessageResponse
+) : Handler {
+
+ /**
+ * Метод, который проверяет, должен ли обработчик сработать для данного запроса.
+ *
+ * @param request Запрос, который будет проверен.
+ * @return true, если обработчик должен сработать, иначе false.
+ */
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean = shouldHandleBlock(request)
+
+ /**
+ * Метод, который выполняет обработку запроса и возвращает ответ.
+ *
+ * @param request Запрос, который нужно обработать.
+ * @return Ответ на запрос в виде MessageResponse.
+ */
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse = processRequestBlock(request)
+}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/WhatCanYouDoHandler.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/WhatCanYouDoHandler.kt
new file mode 100644
index 0000000..946da71
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/handlers/impl/WhatCanYouDoHandler.kt
@@ -0,0 +1,46 @@
+package com.github.alice.ktx.handlers.impl
+
+import com.github.alice.ktx.Dispatcher
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.handlers.Handler
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
+import com.github.alice.ktx.handlers.environments.ShouldRequestEnvironment
+import com.github.alice.ktx.models.response.MessageResponse
+
+/**
+ * Функция расширения для `Dispatcher`, которая добавляет обработчик для запроса "что ты умеешь".
+ * Этот обработчик срабатывает, когда пользователь запрашивает информацию о возможностях системы.
+ *
+ * @param processRequest Логика обработки запроса, которая будет выполнена, когда сработает обработчик.
+ */
+@AliceDsl
+fun Dispatcher.whatCanYouDo(
+ processRequest: suspend ProcessRequestEnvironment.() -> MessageResponse
+) {
+ addHandler(WhatCanYouDoHandler(processRequestBlock = processRequest))
+}
+
+internal class WhatCanYouDoHandler(
+ private val processRequestBlock: suspend ProcessRequestEnvironment.() -> MessageResponse
+) : Handler {
+
+ /**
+ * Определяет, должен ли обработчик сработать для данного запроса.
+ * Обработчик срабатывает, если команда запроса соответствует "что ты умеешь".
+ *
+ * @param request Запрос, который проверяется.
+ * @return `true`, если команда запроса соответствует "что ты умеешь";
+ * `false` в противном случае.
+ */
+ override suspend fun shouldHandle(request: ShouldRequestEnvironment): Boolean {
+ return request.message.request.command == "что ты умеешь"
+ }
+
+ /**
+ * Выполняет обработку запроса и возвращает соответствующий ответ.
+ *
+ * @param request Запрос, который будет обработан.
+ * @return Ответ на запрос в виде `MessageResponse`.
+ */
+ override suspend fun processRequest(request: ProcessRequestEnvironment): MessageResponse = processRequestBlock(request)
+}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/Middleware.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/Middleware.kt
index c081246..9568696 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/Middleware.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/Middleware.kt
@@ -1,43 +1,46 @@
package com.github.alice.ktx.middleware
import com.github.alice.ktx.Dispatcher
-import com.github.alice.ktx.models.Request
+import com.github.alice.ktx.common.AliceDsl
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
import com.github.alice.ktx.models.response.MessageResponse
/**
* Расширение для `Dispatcher`, добавляющее внешний мидлварь (outer middleware), который будет вызван при каждом входящем событии.
*
- * @param invoke Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `Request` и возвращает `MessageResponse?`.
+ * @param process Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `Request` и возвращает `MessageResponse?`.
* Мидлварь должен возвращать `null`, чтобы передать событие следующему мидлварю/хэндлеру.
* Если требуется завершить обработку события, необходимо вернуть `MessageResponse`.
*/
-fun Dispatcher.outerMiddleware(invoke: suspend Request.() -> MessageResponse?) {
- val middleware = middleware { request -> invoke(request) }
+@AliceDsl
+fun Dispatcher.outerMiddleware(process: suspend ProcessRequestEnvironment.() -> MessageResponse?) {
+ val middleware = middleware { request -> process(request) }
addMiddleware(middleware, MiddlewareType.OUTER)
}
/**
* Расширение для `Dispatcher`, добавляющее внутренний мидлварь (inner middleware), который будет вызван только при прохождении фильтров.
*
- * @param invoke Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `Request` и возвращает `MessageResponse?`.
+ * @param process Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `Request` и возвращает `MessageResponse?`.
* Мидлварь должен возвращать `null`, чтобы передать событие следующему мидлварю/хэндлеру.
* Если требуется завершить обработку события, необходимо вернуть `MessageResponse`.
*/
-fun Dispatcher.innerMiddleware(invoke: suspend Request.() -> MessageResponse?) {
- val middleware = middleware { request -> invoke(request) }
+@AliceDsl
+fun Dispatcher.innerMiddleware(process: suspend ProcessRequestEnvironment.() -> MessageResponse?) {
+ val middleware = middleware { request -> process(request) }
addMiddleware(middleware, MiddlewareType.INNER)
}
/**
* Создает мидлварь с заданной функцией обработки.
*
- * @param invoke Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `MessageRequest` и возвращает `MessageResponse?`.
+ * @param process Функция, которая будет вызвана для обработки запроса сообщения. Принимает объект `MessageRequest` и возвращает `MessageResponse?`.
* Мидлварь должен возвращать `null`, чтобы передать событие следующему мидлварю/хэндлеру.
* Если требуется завершить обработку события, необходимо вернуть `MessageResponse`.
* @return Реализованный объект `Middleware`.
*/
-fun middleware(invoke: suspend (Request) -> MessageResponse?): Middleware = object : Middleware {
- override suspend fun invoke(request: Request): MessageResponse? = invoke(request)
+fun middleware(process: suspend (ProcessRequestEnvironment) -> MessageResponse?): Middleware = object : Middleware {
+ override suspend fun process(request: ProcessRequestEnvironment): MessageResponse? = process(request)
}
/**
@@ -49,5 +52,5 @@ interface Middleware {
* Если вы хотите завершить обработку события, вы должны вернуть [MessageResponse]
*
* */
- suspend fun invoke(request: Request): MessageResponse?
+ suspend fun process(request: ProcessRequestEnvironment): MessageResponse?
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/MiddlewareType.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/MiddlewareType.kt
index 0cb629d..3e439af 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/MiddlewareType.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/middleware/MiddlewareType.kt
@@ -2,7 +2,7 @@ package com.github.alice.ktx.middleware
/**
* [OUTER] будут вызываться при каждом входящем событиию
- * [INNER] удут вызываться только при прохождении фильтров
+ * [INNER] будут вызываться только при прохождении фильтров
* */
enum class MiddlewareType {
OUTER,
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/EventRequest.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/EventRequest.kt
deleted file mode 100644
index 88d3b50..0000000
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/EventRequest.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.github.alice.ktx.models
-
-import com.github.alice.ktx.models.request.MessageRequest
-import com.github.alice.ktx.context.ReadOnlyFSMContext
-
-internal fun Request.toEventRequest(): EventRequest {
- return EventRequest(
- message = message,
- context = context
- )
-}
-
-data class EventRequest(
- val message: MessageRequest,
- val context: ReadOnlyFSMContext
-)
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/Request.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/Request.kt
deleted file mode 100644
index 5dc398c..0000000
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/Request.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.github.alice.ktx.models
-
-import com.github.alice.ktx.Dispatcher
-import com.github.alice.ktx.models.request.MessageRequest
-import com.github.alice.ktx.context.MutableFSMContext
-
-internal suspend fun Dispatcher.request(message: MessageRequest): Request {
- val context = fsmContext(message)
- context.init()
-
- return Request(
- message = message,
- context = context,
- fsmStrategy = fsmStrategy,
- enableApiStorage = enableApiStorage
- )
-}
-
-data class Request(
- val message: MessageRequest,
- val context: MutableFSMContext,
- internal val fsmStrategy: FSMStrategy,
- internal val enableApiStorage: Boolean
-)
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/audioPlayer/AudioPlayer.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/audioPlayer/AudioPlayer.kt
index e1fb8f3..0f6563f 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/audioPlayer/AudioPlayer.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/audioPlayer/AudioPlayer.kt
@@ -1,9 +1,11 @@
package com.github.alice.ktx.models.audioPlayer
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.response.MessageResponse
import kotlinx.serialization.Serializable
import java.util.*
+@AliceResponseDsl
fun MessageResponse.Builder.audioPlayer(body: AudioPlayer.Builder.() -> Unit) {
val player = AudioPlayer.Builder().build(body)
audioPlayer = player
@@ -18,40 +20,41 @@ data class AudioPlayer internal constructor(
val action: AudioPlayerAction,
val item: AudioPlayerItem
) {
- class Builder {
- var action = AudioPlayerAction.Play
+ @AliceResponseDsl
+ class Builder {
+ var action = AudioPlayerAction.Play
- var url: String? = null
- var token = UUID.randomUUID().toString()
- var offsetMs = 0
+ var url: String? = null
+ var token = UUID.randomUUID().toString()
+ var offsetMs = 0
- var title: String? = null
- var subTitle: String? = null
- var artUrl: String? = null
- var backgroundImageUrl: String? = null
+ var title: String? = null
+ var subTitle: String? = null
+ var artUrl: String? = null
+ var backgroundImageUrl: String? = null
- internal fun build(body: Builder.() -> Unit): AudioPlayer {
- body()
- return AudioPlayer(
- action = action,
- item = AudioPlayerItem(
- stream = AudioPlayerStream(
- url = url,
- offsetMs = offsetMs,
- token = token
- ),
- metadata = AudioPlayerMetadata(
- title = title,
- subTitle = subTitle,
- art = AudioPlayerMetadataArt(
- url = artUrl
- ),
- backgroundImage = AudioPlayerMetadataBackgroundImage(
- url = backgroundImageUrl
- )
- )
- )
- )
- }
- }
+ internal fun build(body: Builder.() -> Unit): AudioPlayer {
+ body()
+ return AudioPlayer(
+ action = action,
+ item = AudioPlayerItem(
+ stream = AudioPlayerStream(
+ url = url,
+ offsetMs = offsetMs,
+ token = token
+ ),
+ metadata = AudioPlayerMetadata(
+ title = title,
+ subTitle = subTitle,
+ art = AudioPlayerMetadataArt(
+ url = artUrl
+ ),
+ backgroundImage = AudioPlayerMetadataBackgroundImage(
+ url = backgroundImageUrl
+ )
+ )
+ )
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/Button.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/Button.kt
index 21d3ba9..dac3a93 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/Button.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/Button.kt
@@ -1,8 +1,10 @@
package com.github.alice.ktx.models.button
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.response.MessageResponse
import kotlinx.serialization.Serializable
+@AliceResponseDsl
fun MessageResponse.Builder.button(body: Button.Builder.() -> Unit) {
val button = Button.Builder().build(body)
addButton(button)
@@ -15,6 +17,7 @@ data class Button(
val url: String?,
val hide: Boolean
) {
+ @AliceResponseDsl
class Builder {
lateinit var title: String
var url: String? = null
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/MediaButton.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/MediaButton.kt
index 4b5bf30..2b2092d 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/MediaButton.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/button/MediaButton.kt
@@ -1,25 +1,30 @@
package com.github.alice.ktx.models.button
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.card.Card
import com.github.alice.ktx.models.card.CardFooter
import com.github.alice.ktx.models.card.CardItem
import kotlinx.serialization.Serializable
+@AliceResponseDsl
fun Card.BigImageBuilder.mediaButton(body: MediaButton.Builder.() -> Unit) {
val mediaButton = MediaButton.Builder().build(body)
button = mediaButton
}
+@AliceResponseDsl
fun CardItem.ImageGalleryBuilder.mediaButton(body: MediaButton.Builder.() -> Unit) {
val mediaButton = MediaButton.Builder().build(body)
button = mediaButton
}
+@AliceResponseDsl
fun CardItem.ItemsListBuilder.mediaButton(body: MediaButton.Builder.() -> Unit) {
val mediaButton = MediaButton.Builder().build(body)
button = mediaButton
}
+@AliceResponseDsl
fun CardFooter.Builder.mediaButton(body: MediaButton.Builder.() -> Unit) {
val mediaButton = MediaButton.Builder().build(body)
button = mediaButton
@@ -31,6 +36,7 @@ data class MediaButton(
val url: String? = null,
val payload: Map? = null
) {
+ @AliceResponseDsl
class Builder {
var text: String? = null
var url: String? = null
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/Card.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/Card.kt
index c73fba2..f0961e2 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/Card.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/Card.kt
@@ -1,5 +1,6 @@
package com.github.alice.ktx.models.card
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.button.MediaButton
import com.github.alice.ktx.models.response.MessageResponse
import kotlinx.serialization.SerialName
@@ -8,6 +9,7 @@ import kotlinx.serialization.Serializable
/**
* [Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response-card-bigimage)
* */
+@AliceResponseDsl
fun MessageResponse.Builder.cardBigImage(body: Card.BigImageBuilder.() -> Unit) {
val card = Card.BigImageBuilder().build(body)
this.card = card
@@ -16,6 +18,7 @@ fun MessageResponse.Builder.cardBigImage(body: Card.BigImageBuilder.() -> Unit)
/**
* [Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response-card-imagegallery)
* */
+@AliceResponseDsl
fun MessageResponse.Builder.cardImageGallery(body: Card.ImageGalleryBuilder.() -> Unit) {
val card = Card.ImageGalleryBuilder().build(body)
this.card = card
@@ -24,6 +27,7 @@ fun MessageResponse.Builder.cardImageGallery(body: Card.ImageGalleryBuilder.() -
/**
* [Source](https://yandex.ru/dev/dialogs/alice/doc/ru/response-card-itemslist)
* */
+@AliceResponseDsl
fun MessageResponse.Builder.cardItemsList(body: Card.ItemsListBuilder.() -> Unit) {
val card = Card.ItemsListBuilder().build(body)
this.card = card
@@ -41,6 +45,7 @@ data class Card internal constructor(
val items: List? = null,
val footer: CardFooter? = null
) {
+ @AliceResponseDsl
class BigImageBuilder {
lateinit var imageId: String
var title: String? = null
@@ -59,6 +64,7 @@ data class Card internal constructor(
}
}
+ @AliceResponseDsl
class ImageGalleryBuilder {
private val items = mutableListOf()
@@ -75,6 +81,7 @@ data class Card internal constructor(
}
}
+ @AliceResponseDsl
class ItemsListBuilder {
private val items = mutableListOf()
lateinit var header: String
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardFooter.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardFooter.kt
index 849ce34..9533070 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardFooter.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardFooter.kt
@@ -1,8 +1,10 @@
package com.github.alice.ktx.models.card
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.button.MediaButton
import kotlinx.serialization.Serializable
+@AliceResponseDsl
fun Card.ItemsListBuilder.footer(body: CardFooter.Builder.() -> Unit) {
val footer = CardFooter.Builder().build(body)
this.footer = footer
@@ -13,6 +15,7 @@ data class CardFooter(
val text: String,
val button: MediaButton? = null
){
+ @AliceResponseDsl
class Builder {
lateinit var text: String
var button: MediaButton? = null
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardItem.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardItem.kt
index ff66867..67ab14c 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardItem.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/card/CardItem.kt
@@ -1,14 +1,17 @@
package com.github.alice.ktx.models.card
+import com.github.alice.ktx.common.AliceResponseDsl
import com.github.alice.ktx.models.button.MediaButton
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+@AliceResponseDsl
fun Card.ImageGalleryBuilder.item(body: CardItem.ImageGalleryBuilder.() -> Unit) {
val item = CardItem.ImageGalleryBuilder().build(body)
addItem(item)
}
+@AliceResponseDsl
fun Card.ItemsListBuilder.item(body: CardItem.ItemsListBuilder.() -> Unit) {
val item = CardItem.ItemsListBuilder().build(body)
addItem(item)
@@ -22,6 +25,7 @@ data class CardItem(
val description: String? = null,
val button: MediaButton? = null
) {
+ @AliceResponseDsl
class ImageGalleryBuilder {
lateinit var imageId: String
var title: String? = null
@@ -37,6 +41,7 @@ data class CardItem(
}
}
+ @AliceResponseDsl
class ItemsListBuilder {
lateinit var imageId: String
var title: String? = null
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Markup.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Markup.kt
new file mode 100644
index 0000000..b95379b
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Markup.kt
@@ -0,0 +1,10 @@
+package com.github.alice.ktx.models.request
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Markup(
+ @SerialName("dangerous_context")
+ val dangerousContext: Boolean
+)
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/MetadataInterfaces.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/MetadataInterfaces.kt
index 7dd7c10..3b4640f 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/MetadataInterfaces.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/MetadataInterfaces.kt
@@ -7,6 +7,8 @@ import kotlinx.serialization.Serializable
data class MetadataInterfaces(
@SerialName("account_linking")
val accountLinking: AccountLinking? = null,
+ @SerialName("audio_player")
+ val audioPlayer: AudioPlayer? = null,
val screen: Screen? = null,
val payments: Payments? = null
)
@@ -18,4 +20,7 @@ class AccountLinking
class Screen
@Serializable
-class Payments
\ No newline at end of file
+class Payments
+
+@Serializable
+class AudioPlayer
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Nlu.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Nlu.kt
new file mode 100644
index 0000000..435cf6b
--- /dev/null
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/Nlu.kt
@@ -0,0 +1,9 @@
+package com.github.alice.ktx.models.request
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Nlu(
+ val tokens: List = emptyList(),
+ val intents: Map = emptyMap(),
+)
\ No newline at end of file
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/RequestContent.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/RequestContent.kt
index bef765b..5ecffb0 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/RequestContent.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/request/RequestContent.kt
@@ -9,5 +9,8 @@ data class RequestContent(
@SerialName("original_utterance")
val originalUtterance: String? = null,
val type: RequestContentType,
- val payload: Map? = null
+ val payload: Map = emptyMap(),
+ val markup: Markup? = null,
+ val nlu: Nlu = Nlu(),
+ val tokens: Map = emptyMap()
)
diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/response/MessageResponse.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/response/MessageResponse.kt
index 909956b..e5d53ec 100644
--- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/response/MessageResponse.kt
+++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/models/response/MessageResponse.kt
@@ -1,27 +1,32 @@
package com.github.alice.ktx.models.response
+import com.github.alice.ktx.common.AliceResponseDsl
+import com.github.alice.ktx.fsm.MutableFSMContext
+import com.github.alice.ktx.fsm.ReadOnlyFSMContext
+import com.github.alice.ktx.handlers.environments.ProcessRequestEnvironment
import com.github.alice.ktx.models.FSMStrategy
-import com.github.alice.ktx.models.Request
import com.github.alice.ktx.models.audioPlayer.AudioPlayer
import com.github.alice.ktx.models.button.Button
import com.github.alice.ktx.models.card.Card
import com.github.alice.ktx.models.request.AccountLinking
import com.github.alice.ktx.models.response.analytics.Analytics
-import com.github.alice.ktx.context.ReadOnlyFSMContext
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-suspend fun Request.response(body: suspend MessageResponse.Builder.() -> Unit): MessageResponse {
- return MessageResponse.Builder(this)
- .setFSMStrategy(fsmStrategy)
- .setEnableApiStorage(enableApiStorage)
- .build(body)
+@AliceResponseDsl
+suspend fun ProcessRequestEnvironment.response(block: MessageResponse.Builder.() -> Unit): MessageResponse {
+ return MessageResponse.Builder(message.version)
+ .fsmStrategy(fsmStrategy)
+ .enableApiStorage(enableApiStorage)
+ .apply(block)
+ .build(context)
}
/**
* [Source](https://yandex.ru/dev/dialogs/alice/doc/ru/auth/when-to-use)
* */
-suspend fun Request.authorization(
+@AliceResponseDsl
+suspend fun ProcessRequestEnvironment.authorization(
onAlreadyAuthenticated: (suspend () -> MessageResponse)? = null,
onAuthorizationFailed: (suspend () -> MessageResponse)? = null
): MessageResponse {
@@ -31,7 +36,7 @@ suspend fun Request.authorization(
if (message.meta.interfaces.accountLinking == null && onAuthorizationFailed != null)
return onAuthorizationFailed()
- return MessageResponse.AuthorizationBuilder(request = this).build()
+ return MessageResponse.AuthorizationBuilder(version = message.version).build()
}
/**
@@ -51,16 +56,18 @@ data class MessageResponse internal constructor(
val startAccountLinking: AccountLinking? = null,
val analytics: Analytics? = null
) {
- class Builder(private val request: Request) {
+ @AliceResponseDsl
+ class Builder(private val version: String) {
var text: String = ""
var tts: String? = null
var endSession: Boolean = false
var shouldListen: Boolean? = null
- var version: String = request.message.version
+ var analytics: Analytics? = null
+
internal var card: Card? = null
internal var audioPlayer: AudioPlayer? = null
+
private val buttons = mutableListOf