Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Telegram bots with Kotlin

Telegram bots with Kotlin

Telegram Bots are third-party applications that run inside Telegram. Users can interact with bots by sending them messages, commands and inline requests. The bots are controlled using HTTPS requests to Telegram's bot API.

We can create bots to get customized notifications and news, integrate with other services, accept payments from Telegram users, create custom tools, build games and social services and do virtually anything else.

In this talk we will deep into details about how we can start creating these awesome bots and all the possibilities we have with them. Moreover, we will work with one of the programming languages of the moment, Kotlin, that will let us creating these bots in a really easy and elegant way.

Other Decks in Programming

Transcript

  1. What can I do with Telegram Bots? • Get customized

    notifications and news (NewsBot)
  2. What can I do with Telegram Bots? • Get customized

    notifications and news (NewsBot) • Integrate with other services (GIFBot)
  3. What can I do with Telegram Bots? • Get customized

    notifications and news (NewsBot) • Integrate with other services (GIFBot) • Accept payments from Telegram users (InviteMember)
  4. What can I do with Telegram Bots? • Get customized

    notifications and news (NewsBot) • Integrate with other services (GIFBot) • Accept payments from Telegram users (InviteMember) • Build games (GameBot)
  5. What can I do with Telegram Bots? • Get customized

    notifications and news (NewsBot) • Integrate with other services (GIFBot) • Accept payments from Telegram users (InviteMember) • Build games (GameBot) • Whatever you want...
  6. How do bots work? • At the core, Telegram Bots

    are special accounts that do not require an additional phone number to set up
  7. How do bots work? • At the core, Telegram Bots

    are special accounts that do not require an additional phone number to set up • Messages, commands and requests sent by users are passed to the software running on our servers
  8. Telegram servers Telegram intermediary servers Our bot server bot api

    operations operations /updates bot updates Telegram clients
  9. Telegram servers Telegram intermediary servers Our bot server bot api

    operations operations /updates bot updates Telegram clients BOT API
  10. Making requests to bot API https://api.telegram.org/bot<token>/METHOD_NAME • GET and POST

    HTTP methods • Four ways of passing parameters ◦ Query params ◦ application/x-www-form-urlencoded ◦ application/json (except for uploading files) ◦ application/form-data (for uploading file)
  11. Bot API responses { "ok": true, "result": [] } {

    "ok": false, "error_code": 401, "description": "Unauthorized" }
  12. Listening to user updates • There are two ways of

    receiving updates for a bot: ◦ getUpdates API method -> Long polling ◦ setWebhook API method -> Webhook • They are mutually exclusive
  13. { "ok": true, "result": [ { "update_id": 911858287, "message": {

    "message_id": 20, "from": { "id": 187395179, "is_bot": false, "first_name": "Victor J", "last_name": "Garcia Granado", "username": "vjgarciag96", "language_code": "en" }, "chat": { "id": 187395179, "first_name": "Victor J", "last_name": "Garcia Granado", "username": "vjgarciag96", "type": "private" }, "date": 1572202802, "text": "hehehe" } }, ... ] }
  14. • Say something when /padrino command is received • Answer

    inline queries with Github repos search results Let’s create our first bot
  15. TelegramBot telegramBot = new TelegramBot("976951878:AAETlyNbC0ocEilDj..."); telegramBot.setUpdatesListener(updates -> { updates.forEach(update ->

    { if (update.message() != null && update.message().text() != null && update.message().text().equals("/padrino")) { } }); return UpdatesListener.CONFIRMED_UPDATES_ALL; });
  16. TelegramBot telegramBot = new TelegramBot("976951878:AAETlyNbC0ocEilDj..."); telegramBot.setUpdatesListener(updates -> { updates.forEach(update ->

    { if (update.message() != null && update.message().text() != null && update.message().text().equals("/padrino")) { long chatId = update.message().chat().id(); telegramBot.execute(new SendMessage(chatId, "Algún día, y ...")); } }); return UpdatesListener.CONFIRMED_UPDATES_ALL; });
  17. TelegramBot telegramBot = new TelegramBot("976951878:AAETlyNbC0ocEilDj..."); telegramBot.setUpdatesListener(updates -> { updates.forEach(update ->

    { if (update.message() != null && update.message().text() != null && update.message().text().equals("/padrino")) { long chatId = update.message().chat().id(); telegramBot.execute(new SendMessage(chatId, "Algún día, y ...")); } }); return UpdatesListener.CONFIRMED_UPDATES_ALL; });
  18. TelegramBot telegramBot = new TelegramBot("976951878:AAETlyNbC0ocEilDj..."); telegramBot.setUpdatesListener(updates -> { updates.forEach(update ->

    { if (update.message() != null && update.message().text() != null && update.message().text().equals("/padrino")) { sayHi(telegramBot, update.message()); return; } if (update.inlineQuery() != null) { showGithubReposSearchResult(telegramBot, update.inlineQuery()); return; } }); return UpdatesListener.CONFIRMED_UPDATES_ALL; });
  19. private static void showGithubReposSearchResults(TelegramBot telegramBot, InlineQuery inlineQuery) { String queryText

    = inlineQuery.query(); if (queryText.trim().isEmpty()) return; GithubApi.search(queryText, githubRepos -> { }); }
  20. private static void showGithubReposSearchResults(TelegramBot telegramBot, InlineQuery inlineQuery) { String queryText

    = inlineQuery.query(); if (queryText.trim().isEmpty()) return; GithubApi.search(queryText, githubRepos -> { List<InlineQueryResultArticle> queryResults = githubRepos.stream() .map(repo -> ) .collect(Collectors.toList()); }); }
  21. private static void showGithubReposSearchResults(TelegramBot telegramBot, InlineQuery inlineQuery) { String queryText

    = inlineQuery.query(); if (queryText.trim().isEmpty()) return; GithubApi.search(queryText, githubRepos -> { List<InlineQueryResultArticle> queryResults = githubRepos.stream() .map(repo -> new InlineQueryResultArticle(UUID.randomUUID().toString(), repo.getName(), repo.getDescription(), repo.getOwner().getAvatarUrl(), new InputTextMessageContent(repo.getUrl())) .collect(Collectors.toList()); }); }
  22. private static void showGithubReposSearchResults(TelegramBot telegramBot, InlineQuery inlineQuery) { String queryText

    = inlineQuery.query(); if (queryText.trim().isEmpty()) return; GithubApi.search(queryText, githubRepos -> { List<InlineQueryResultArticle> queryResults = githubRepos.stream() .map(repo -> new InlineQueryResultArticle(UUID.randomUUID().toString(), repo.getName(), repo.getDescription(), repo.getOwner().getAvatarUrl(), new InputTextMessageContent(repo.getUrl())) .collect(Collectors.toList()); telegramBot.execute(new AnswerInlineQuery(inlineQuery.id(), queryResults))); }); }
  23. • Null safety • Immutability • Functions as first-class citizens

    • Extension functions • Data classes • Sealed classes • Java interoperability • DSLs • etc...
  24. fun aFun(anotherFun: () -> Unit) { anotherFun() } • Use

    of lambdas outside of function parentheses
  25. fun aFun(anotherFun: () -> Unit) { anotherFun() } aFun({println("HelloWorld!!")}) aFun

    {println("HelloWorld!!")} • Use of lambdas outside of function parentheses
  26. • Use of lambdas outside of function parentheses • Extension

    functions fun String.isBlankOrEmpty() = isBlank() or isEmpty()
  27. • Use of lambdas outside of function parentheses • Extension

    functions • Lambdas with receivers fun aFun(anotherFun: String.() -> Unit) { "Hello-World-!!".anotherFun() }
  28. • Use of lambdas outside of function parentheses • Extension

    functions • Lambdas with receivers fun aFun(anotherFun: String.() -> Unit) { "Hello-World-!!".anotherFun() } aFun { println(split("-").joinToString(" ")) }
  29. Kotlin DSLs <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="vertical" tools:context=".MainActivity"> <EditText android:id="@+id/nameInput" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" /> <Button android:id="@+id/sayHelloButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Say Hello" tools:ignore="HardcodedText" /> </LinearLayout>
  30. Kotlin DSLs class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) sayHelloButton.setOnClickListener { val name = nameInput.text?.toString() name?.let { Toast.makeText(this, "Hello, $it", Toast.LENGTH_SHORT).show() } } } }
  31. Kotlin DSLs verticalLayout { val name = editText() button("Say Hello")

    { onClick { toast("Hello, ${name.text}!") } } } ANDROID VIEW DSL
  32. person { name = "John" age = 25 address {

    street = "Main Street" number = 42 city = "London" } }
  33. data class Person(var name: String? = null, var age: Int?

    = null, var address: Address? = null) data class Address(var street: String? = null, var number: Int? = null, var city: String? = null)
  34. fun person(block: (Person) -> Unit): Person { val p =

    Person() block(p) return p } person { it.name = "John" it.age = 25 }
  35. fun person(block: Person.() -> Unit): Person { val p =

    Person() p.block() return p } fun person(block: Person.() -> Unit): Person = Person().apply(block)
  36. person { name = "John" age = 25 } fun

    person(block: Person.() -> Unit): Person { val p = Person() p.block() return p } fun person(block: Person.() -> Unit): Person = Person().apply(block)
  37. fun person(block: Person.() -> Unit): Person = Person().apply(block) fun Person.address(block:

    Address.() -> Unit) { address = Address().apply(block) } person { name = "John" age = 25 address { street = "Main Street" number = 42 city = "London" } }
  38. bot("976951878:AAETlyNbC0ocEilD...") { command("padrino") { bot, message -> bot.sendMessage(message.chat().id(), "Algún día,

    y ...") } inlineQuery { bot, inlineQuery -> bot.showGithubReposSearchResult(inlineQuery) } }
  39. private fun Bot.showGithubReposSearchResult(inlineQuery: InlineQuery) { val queryText = inlineQuery.query() if

    (queryText.isBlankOrEmpty()) return GithubApi.search(queryText) { repos -> } }
  40. private fun Bot.showGithubReposSearchResult(inlineQuery: InlineQuery) { val queryText = inlineQuery.query() if

    (queryText.isBlankOrEmpty()) return GithubApi.search(queryText) { repos -> val reposInlineResult = repos.map(GithubRepo::toInlineResult) } } private fun GithubRepo.toInlineResult(): InlineQueryResultArticle = InlineQueryResultArticle( UUID.randomUUID().toString(), name, description, owner.avatarUrl, InputTextMessageContent(url) )
  41. private fun Bot.showGithubReposSearchResult(inlineQuery: InlineQuery) { val queryText = inlineQuery.query() if

    (queryText.isBlankOrEmpty()) return GithubApi.search(queryText) { repos -> val reposInlineResult = repos.map(GithubRepo::toInlineResult) answerInlineQuery(inlineQuery.id(), reposInlineResult) } } private fun GithubRepo.toInlineResult(): InlineQueryResultArticle = InlineQueryResultArticle( UUID.randomUUID().toString(), name, description, owner.avatarUrl, InputTextMessageContent(url) )
  42. TelegramBot telegramBot = new TelegramBot("976951878:AAETlyNbC0ocEilDj..."); telegramBot.setUpdatesListener(updates -> { updates.forEach(update ->

    { if (update.message() != null && update.message().text() != null && update.message().text().equals("/padrino")) { sayHi(telegramBot, update.message()); return; } if (update.inlineQuery() != null) { showGithubReposSearchResults(telegramBot, update.inlineQuery()); return; } }); return UpdatesListener.CONFIRMED_UPDATES_ALL; });
  43. What we covered • What’s a Telegram bot? • What

    can I do with Telegram Bots? • How do bots works?
  44. What we covered • What’s a Telegram bot? • What

    can I do with Telegram Bots? • How do bots works? • How do I create a bot?
  45. What we covered • What’s a Telegram bot? • What

    can I do with Telegram Bots? • How do bots works? • How do I create a bot? • Bot API
  46. What we covered • What’s a Telegram bot? • What

    can I do with Telegram Bots? • How do bots works? • How do I create a bot? • Bot API • Sample implementation
  47. What we covered • What’s a Telegram bot? • What

    can I do with Telegram Bots? • How do bots works? • How do I create a bot? • Bot API • Sample implementation • Kotlin DSLs