Skip to content

Heroku

Preview reading

It is recommended to visit our pages about UpdatesFilters and Webhooks to have more clear understanding about what is happening in this examples page

Heroku is a popular place for bots hosting. In common case you will need to configure webhooks for your server to include getting updates without problems. There are several things related to heroku you should know:

  • Heroku apps by default accessible via https://<app name>.herokuapp.com/
  • Heroku provide one port to be proxied for the link above. You can retrieve number of this port by calling System.getenv("PORT").toInt()
  • Currently (Sat Aug 15 5:04:21 +00 2020) there is only one official server engine for ktor which is correctly working with Heroku: Tomcat server engine

Server configuration alternatives

Here will be presented variants of configuration of webhooks and starting server. You always able to set webhook manualy, create your own ktor server and include webhooks handling in it or create and start server with only webhooks handling. More info you can get on page Webhooks

Short example with Behaviour Builder

suspend fun main {
    // This subroute will be used as random webhook subroute to improve security according to the recommendations of Telegram
    val subroute = uuid4().toString()
    // Input/Output coroutines scope more info here: https://kotlinlang.org/docs/coroutines-guide.html
    val scope = CoroutineScope(Dispatchers.IO)
    // Here will be automatically created bot and available inside of lambda where you will setup your bot behaviour
    telegramBotWithBehaviour(
        // Pass TOKEN inside of your application environment variables
        System.getenv("TOKEN"),
        scope = scope
    ) {
        // Set up webhooks and start to listen them
        setWebhookInfoAndStartListenWebhooks(
            // Automatic env which will be passed by heroku to the app
            System.getenv("PORT").toInt(),
            // Server engine. More info here: https://ktor.io/docs/engines.html
            Tomcat,
            // Pass URL environment variable via settings of application. It must looks like https://<app name>.herokuapp.com
            SetWebhook("${System.getenv("URL").removeSuffix("/")}/$subroute"),
            // Just callback which will be called when exceptions will happen inside of webhooks
            {
                it.printStackTrace()
            },
            // Set up listen requests from outside
            "0.0.0.0",
            // Set up subroute to listen webhooks to
            subroute,
            // BehaviourContext is the CoroutineScope and it is recommended to pass it inside of webhooks server
            scope = this,
            // BehaviourContext is the FlowsUpdatesFilter and it is recommended to pass its asUpdateReceiver as a block to retrieve all the updates
            block = asUpdateReceiver
        )
        // Test reaction on each command with reply and text `Got it`
        onUnhandledCommand {
            reply(it, "Got it")
        }
    }
    // Just potentially infinite await of bot completion
    scope.coroutineContext.job.join()
}

Configuration example without Behaviour Builder

// This subroute will be used as random webhook subroute to improve security according to the recommendations of Telegram
val subroute = uuid4().toString()
val bot = telegramBot(TOKEN)
val scope = CoroutineScope(Dispatchers.Default)

val filter = flowsUpdatesFilter {
  messageFlow.onEach {
    println(it) // will be printed 
  }.launchIn(scope)
}

val subroute = UUID.randomUUID().toString() // It will be used as subpath for security target as recommended by https://core.telegram.org/bots/api#setwebhook

val server = bot.setWebhookInfoAndStartListenWebhooks(
  // Automatic env which will be passed by heroku to the app
  System.getenv("PORT").toInt(),
  // Server engine. More info here: https://ktor.io/docs/engines.html
  Tomcat,
  // Pass URL environment variable via settings of application. It must looks like https://<app name>.herokuapp.com
  SetWebhook("${System.getenv("URL").removeSuffix("/")}/$subroute"),
  // Just callback which will be called when exceptions will happen inside of webhooks
  {
    it.printStackTrace()
  },
  // Set up listen requests from outside
  "0.0.0.0",
  // Set up subroute to listen webhooks to
  subroute,
  scope = scope,
  block = filter.asUpdateReceiver
)

server.environment.connectors.forEach {
  println(it)
}
server.start(false)