Skip to content

Instantly share code, notes, and snippets.

@dctremblay
Last active June 26, 2024 02:29
Show Gist options
  • Save dctremblay/98e0d87194cbaef89d3b54f145643412 to your computer and use it in GitHub Desktop.
Save dctremblay/98e0d87194cbaef89d3b54f145643412 to your computer and use it in GitHub Desktop.
Bash Telegram Bot : Send and receive messages in realtime (long polling). Shipped with a simple API wrapper. Usage: adapting recvUpdate() and other stuff to your needs.
#!/bin/bash
# Title: Starter Bash Telegram Bot
# Version: 0.1-alpha
# Date: 2024-06-12
# License: Unlicense
# Author: dctremblay@dasio.ca
#
# Telegram Bot API Documentation:
# https://core.telegram.org/bots/api#making-requests
: ${TELEGRAM_BOT_TOKEN:?required but missing}
botId=$(cut -d':' -f1 <<< "$TELEGRAM_BOT_TOKEN")
: ${BTB_DIR:=$HOME/.local/share/bash-telegram-bot}
: ${BOT_DIR:=$BTB_DIR/$botId}
recvUpdate() {
local text=$(msg .text)
[[ $text != null ]] || return
# important: private bot? dont forget to validate $chatId
local chatId=$(msg .chat.id)
telegramApi sendChatAction chat_id=$chatId action=typing
local answer="hello my $(msg .from.first_name), $text"
telegramApi sendMessage chat_id=$chatId text="$answer"
}
##########
mkdir -p "$BOT_DIR"
cd "$BOT_DIR"
touch offset
msg() { jq -rj "$1" <<< "$message"; }
telegramApi() {
local method=$1; shift
local params=("$@")
local args=()
for arg in "${params[@]}"; do
args+=("--data-urlencode" "$arg")
done
local url="https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/$method"
local response=$(curl -sS -w '%{http_code}' $url "${args[@]}")
echo -n "${response%???}"
[[ ${response: -3:1} == 2 ]] || {
echo "$response" >&2
return 5
}
}
echo "waiting for updates.." >&2
while true; do
resp=$(telegramApi getUpdates timeout=30 offset=$(cat offset))
[[ $(jq .ok <<< "$resp") == true ]] || {
jq <<< "$resp" >&2
sleep 60
continue
}
jq -c '.result[]' <<< "$resp" | while read -r update; do
updateId=$(jq .update_id <<< "$update")
message=$(jq .message <<< "$update")
echo "processing update #$updateId.." >&2
recvUpdate > /dev/null && echo "done" >&2 || {
echo "error occured while calling recvUpdate" >&2
sleep 10
break
}
echo $((updateId + 1)) > offset
done
done

Given you want to communicate thru FIFOs, here's simple example implementation of recvUpdate() plus initialization code.

recvUpdate() {
    local text=$(msg .text)
    [[ $text != null ]] || return
    echo "$text" > "$outputPipe"
    local chatId=$(msg .chat.id)
    telegramApi sendChatAction chat_id=$chatId action=typing
    telegramApi sendMessage chat_id=$chatId text="$(< "$inputPipe")"
}

inputPipe=$BOT_DIR/in.pipe
outputPipe=$BOT_DIR/out.pipe
[[ -p $inputPipe ]] || mkfifo "$inputPipe"
[[ -p $outputPipe ]] || mkfifo "$outputPipe"

Then, to read the top message: cat "$BOT_DIR/out.pipe", and to answer: echo "Hello" > "$BOT_DIR/in.pipe".

Here's example code :

while true; do
    message=$(cat out.pipe)
    echo "roger that" > in.pipe
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment