Pular para o conteúdo

Um bot que cresce

O bot como casca: a regra num módulo, o estado fora da memória, e o teste que não precisa do Telegram.

O primeiro bot é um arquivo só, e está certo assim. O segundo mês traz um banco, três tipos de usuário e um relatório — e aí o arquivo único mistura o que o bot faz com como o Telegram recebe, e nenhum dos dois se testa sozinho.

CamadaSabe deNão sabe de
o núcleo (pedidos.df)a regra: o que é um pedido válido, o total, o estadoTelegram, ctx, teclado
o bot (bot.df)comandos, teclados, a conversacomo se calcula o total
o estadoonde a conversa mora entre mensagenso que ela significa
dataforge
adopt Arcane.Telegram as Tg

app := Tg.app("123456:TESTE-exemplo")

// o núcleo: nada aqui sabe que existe um Telegram
action total(itens):
    yield itens >> distill acc, i: acc + i["preco"] * i["qtd"] 0

// a casca: traduz mensagem em chamada, e resultado em texto
mark @app.comando("total")
action comando_total(ctx):
    carrinho := ctx.lembrar("carrinho", [])
    ctx.responder($"Total: R$ {total(carrinho)}")

mark @app.comando("pegar")
action pegar(ctx):
    carrinho := ctx.lembrar("carrinho", [])
    carrinho.append({"preco": 10, "qtd": 2})
    ctx.guardar("carrinho", carrinho)
    ctx.responder("Adicionado.")

assert total([{"preco": 10, "qtd": 3}]) is 30   // o núcleo, sem bot

t := Tg.testar(app)
t.comando("pegar")
t.comando("total")
assert t.ultima() is "Total: R$ 20"

O estado fora da memória#

Tg.estado_em_memoria() some quando o processo reinicia — e o bot reinicia a cada deploy. Para produção, Tg.estado_em_arquivo(caminho), e o carrinho de quem estava no meio de uma compra sobrevive à atualização.

O projeto completo nesse formato está em Bot de atendimento.