Current section

Files

Jump to
telega src telega.gleam
Raw

src/telega.gleam

import gleam/result.{try}
import gleam/dynamic.{type Dynamic}
import telega/api
import wisp.{type Request, type Response}
import logging
type MessageUpdate {
MessageUpdate(message: Message)
}
pub type Chat {
Chat(id: Int)
}
pub type Message {
TextMessage(text: String, chat: Chat)
}
pub type Handler =
fn(Bot, Message) -> Result(Nil, Nil)
pub opaque type Bot {
Bot(
token: String,
server_url: String,
secret: String,
handlers: List(Handler),
)
}
pub fn new(
token token: String,
url server_url: String,
secret secret: String,
) -> Bot {
Bot(token: token, server_url: server_url, secret: secret, handlers: [])
}
pub fn set_webhook(bot: Bot) -> Result(Bool, String) {
let webhook_url = bot.server_url <> "/" <> bot.secret
use response <- try(api.set_webhook(bot.token, webhook_url))
case response.status {
200 -> Ok(True)
_ -> Error("Failed to set webhook")
}
}
fn decode_message(json: Dynamic) -> Result(Message, dynamic.DecodeErrors) {
let message_update_decoder =
dynamic.decode1(
MessageUpdate,
dynamic.field(
"message",
dynamic.decode2(
TextMessage,
dynamic.field("text", dynamic.string),
dynamic.field(
"chat",
dynamic.decode1(Chat, dynamic.field("id", dynamic.int)),
),
),
),
)
use message_update <- try(message_update_decoder(json))
Ok(message_update.message)
}
pub fn is_bot_request(bot: Bot, req: Request) -> Bool {
case wisp.path_segments(req) {
[segment] if segment == bot.secret -> True
_ -> False
}
}
fn handle_update_loop(
bot: Bot,
message: Message,
handlers: List(Handler),
) -> Nil {
case handlers {
[handler, ..rest] -> {
case handler(bot, message) {
Ok(_) -> handle_update_loop(bot, message, rest)
Error(_) -> {
logging.log(logging.Error, "Failed to handle message")
Nil
}
}
}
_ -> Nil
}
}
fn handle_update(bot: Bot, message: Message) -> Nil {
handle_update_loop(bot, message, bot.handlers)
}
pub fn bot_handler(bot: Bot, req: Request) -> Response {
use json <- wisp.require_json(req)
case decode_message(json) {
Ok(message) -> {
logging.log(logging.Info, "Received message: " <> message.text)
handle_update(bot, message)
wisp.ok()
}
Error(_) -> {
logging.log(logging.Error, "Failed to decode message")
wisp.ok()
}
}
}
pub fn reply(bot: Bot, message: Message, text: String) -> Result(Nil, Nil) {
api.send_text(bot.token, message.chat.id, text)
|> result.map(fn(_) { Nil })
|> result.nil_error
}
pub fn add_handler(bot: Bot, handler: Handler) -> Bot {
Bot(..bot, handlers: [handler, ..bot.handlers])
}