diff --git a/channels/facebook/src/main/kotlin/com/justai/jaicf/channel/facebook/FacebookChannel.kt b/channels/facebook/src/main/kotlin/com/justai/jaicf/channel/facebook/FacebookChannel.kt index bb352a4f..7d0115eb 100644 --- a/channels/facebook/src/main/kotlin/com/justai/jaicf/channel/facebook/FacebookChannel.kt +++ b/channels/facebook/src/main/kotlin/com/justai/jaicf/channel/facebook/FacebookChannel.kt @@ -8,11 +8,10 @@ import com.justai.jaicf.channel.facebook.messenger.Messenger import com.justai.jaicf.channel.http.HttpBotRequest import com.justai.jaicf.channel.http.HttpBotResponse import com.justai.jaicf.channel.http.asTextHttpBotResponse +import com.justai.jaicf.channel.invocationapi.* import com.justai.jaicf.channel.jaicp.JaicpCompatibleAsyncBotChannel import com.justai.jaicf.channel.jaicp.JaicpCompatibleAsyncChannelFactory import com.justai.jaicf.context.RequestContext -import com.justai.jaicf.channel.invocationapi.InvocableBotChannel -import com.justai.jaicf.channel.invocationapi.InvocationRequest import java.util.* class FacebookChannel private constructor( @@ -59,9 +58,15 @@ class FacebookChannel private constructor( internal const val REQUEST_TEMPLATE_PATH = "/FacebookRequestTemplate.json" } + private fun generateRequestFromTemplate(request: InvocationRequest) = + getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH) + .replace("\"{{ timestamp }}\"", System.currentTimeMillis().toString()) + .replace("{{ messageId }}", UUID.randomUUID().toString()) + + override fun processInvocation(request: InvocationRequest, requestContext: RequestContext) { - val template = getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH) - messenger.onReceiveEvents(template, Optional.empty()) { event -> + val generatedRequest = generateRequestFromTemplate(request) + messenger.onReceiveEvents(generatedRequest, Optional.empty()) { event -> FacebookInvocationRequest.create(request, event.asTextMessageEvent())?.let { botApi.process(it, FacebookReactions(messenger, it), requestContext) } diff --git a/channels/slack/src/main/kotlin/com/justai/jaicf/channel/slack/SlackChannel.kt b/channels/slack/src/main/kotlin/com/justai/jaicf/channel/slack/SlackChannel.kt index 1ddd651f..311705e3 100644 --- a/channels/slack/src/main/kotlin/com/justai/jaicf/channel/slack/SlackChannel.kt +++ b/channels/slack/src/main/kotlin/com/justai/jaicf/channel/slack/SlackChannel.kt @@ -9,6 +9,7 @@ import com.justai.jaicf.channel.jaicp.JaicpCompatibleAsyncChannelFactory import com.justai.jaicf.context.RequestContext import com.justai.jaicf.channel.invocationapi.InvocableBotChannel import com.justai.jaicf.channel.invocationapi.InvocationRequest +import com.justai.jaicf.channel.invocationapi.getRequestTemplateFromResources import com.justai.jaicf.helpers.http.toUrl import com.justai.jaicf.helpers.kotlin.PropertyWithBackingField import com.slack.api.Slack @@ -23,6 +24,7 @@ import com.slack.api.methods.MethodsConfig import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.util.* import java.util.concurrent.TimeUnit class SlackChannel private constructor( @@ -99,12 +101,14 @@ class SlackChannel private constructor( botApi.process(request, reactions, RequestContext.fromHttp(httpBotRequest)) } - override fun provideTimestamp(): String = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString() + private fun generateRequestFromTemplate(request: InvocationRequest) = + getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH) + .replace("\"{{ timestamp }}\"", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()) + .replace("{{ messageId }}", UUID.randomUUID().toString()) override fun processInvocation(request: InvocationRequest, requestContext: RequestContext) { val invocationRequest = SlackInvocationRequest.create(request) ?: return - val slackRequest = - buildSlackRequest(getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH).asHttpBotRequest()) + val slackRequest = buildSlackRequest(generateRequestFromTemplate(request).asHttpBotRequest()) botApi.process(invocationRequest, SlackReactions(slackRequest.context), requestContext) } diff --git a/channels/telegram/src/main/kotlin/com/justai/jaicf/channel/telegram/TelegramChannel.kt b/channels/telegram/src/main/kotlin/com/justai/jaicf/channel/telegram/TelegramChannel.kt index 353ccde3..9ace110d 100644 --- a/channels/telegram/src/main/kotlin/com/justai/jaicf/channel/telegram/TelegramChannel.kt +++ b/channels/telegram/src/main/kotlin/com/justai/jaicf/channel/telegram/TelegramChannel.kt @@ -15,6 +15,7 @@ import com.justai.jaicf.context.RequestContext import com.justai.jaicf.helpers.kotlin.PropertyWithBackingField import com.justai.jaicf.channel.invocationapi.InvocableBotChannel import com.justai.jaicf.channel.invocationapi.InvocationRequest +import com.justai.jaicf.channel.invocationapi.getRequestTemplateFromResources import java.util.* import java.util.concurrent.TimeUnit @@ -101,14 +102,15 @@ class TelegramChannel( return null } - override fun getRequestTemplateFromResources(request: InvocationRequest, resourceName: String): String = - super.getRequestTemplateFromResources(request, resourceName) + private fun generateRequestFromTemplate(request: InvocationRequest) = + getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH) .replace("\"{{ timestamp }}\"", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()) .replace("{{ messageId }}", UUID.randomUUID().toString()) + override fun processInvocation(request: InvocationRequest, requestContext: RequestContext) { - val template = getRequestTemplateFromResources(request, REQUEST_TEMPLATE_PATH) - val message = gson.fromJson(template, Update::class.java).message ?: return + val generatedRequest = generateRequestFromTemplate(request) + val message = gson.fromJson(generatedRequest, Update::class.java).message ?: return val telegramRequest = TelegramInvocationRequest.create(request, message) ?: return botApi.process(telegramRequest, TelegramReactions(bot, telegramRequest), requestContext) } diff --git a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocableBotChannel.kt b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocableBotChannel.kt index 4cc454a2..ed77dfdd 100644 --- a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocableBotChannel.kt +++ b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocableBotChannel.kt @@ -24,35 +24,6 @@ interface InvocableBotChannel : WithLogger { * @see InvocableBotChannel */ fun processInvocation(request: InvocationRequest, requestContext: RequestContext) - - /** - * Provides a messageId for substitution in request template - * */ - fun provideMessageId(): String = UUID.randomUUID().toString() - - /** - * Provides a timestamp for substitution in request template - * */ - fun provideTimestamp(): String = System.currentTimeMillis().toString() - - /** - * Loads a channel request template from resources and substitutes essential parameters (clientId, input) in request - * - * @return serialized JSON with substituted request parameters - * */ - @Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") - fun getRequestTemplateFromResources(request: InvocationRequest, resourceName: String) = - this.javaClass.getResource(resourceName).readText() - .replace("{{ clientId }}", request.clientId) - .replace("{{ text }}", request.input) - - .replace("\"{{ timestamp }}\"", provideTimestamp()) - .replace("{{ messageId }}", provideMessageId()) - - .replace("\"{{ randomInt }}\"", randomInt.toString()) - .replace("\"{{ randomLong }}\"", randomLong.toString()) - - .also { logger.trace("Generated template request: $it") } } /** @@ -79,3 +50,17 @@ private val randomInt get() = Random.nextInt() private val randomLong get() = Random.nextLong() +/** + * Loads a channel request template from resources and substitutes essential parameters (clientId, input) in request + * + * @return serialized JSON with substituted request parameters + * */ +fun InvocableBotChannel.getRequestTemplateFromResources(request: InvocationRequest, resourceName: String) = + this.javaClass.getResource(resourceName).readText() + .replace("{{ clientId }}", request.clientId) + .replace("{{ text }}", request.input) + + .replace("\"{{ randomInt }}\"", randomInt.toString()) + .replace("\"{{ randomLong }}\"", randomLong.toString()) + + .also { logger.trace("Generated template request: $it") } \ No newline at end of file diff --git a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationQueryParams.kt b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationQueryParams.kt index 90593ace..f7780605 100644 --- a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationQueryParams.kt +++ b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationQueryParams.kt @@ -24,7 +24,7 @@ internal class InvocationQueryParams(queryParamsMap: Map>) val type: InvocationRequestType = when { event != null -> InvocationRequestType.EVENT query != null -> InvocationRequestType.QUERY - else -> error("event or query must be specified in query parameters") + else -> throw HttpRequestException("event or query must be specified in query parameters") } val input = when (type) { @@ -32,9 +32,8 @@ internal class InvocationQueryParams(queryParamsMap: Map>) InvocationRequestType.QUERY -> requireNotNull(query) } - val clientId: String = requireNotNull(queryParamsMap["clientId"]?.firstOrNull()) { - "clientId path variable must be specified for invocation api call" - } + val clientId: String = queryParamsMap["clientId"]?.firstOrNull() + ?: throw HttpRequestException("clientId path variable must be specified for invocation api call") } /** @@ -42,4 +41,6 @@ internal class InvocationQueryParams(queryParamsMap: Map>) * */ internal enum class InvocationRequestType { EVENT, QUERY; -} \ No newline at end of file +} + +private class HttpRequestException(override val message: String) : RuntimeException() diff --git a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationRouting.kt b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationRouting.kt index 8bcc35fc..8aa42247 100644 --- a/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationRouting.kt +++ b/core/src/main/kotlin/com/justai/jaicf/channel/invocationapi/InvocationRouting.kt @@ -1,7 +1,9 @@ package com.justai.jaicf.channel.invocationapi import io.ktor.application.* +import io.ktor.http.* import io.ktor.request.* +import io.ktor.response.* import io.ktor.routing.* typealias RouteToInvocableChannel = Pair