Class: Botiasloop::Channels::Telegram

Inherits:
Base
  • Object
show all
Defined in:
lib/botiasloop/channels/telegram.rb

Instance Method Summary collapse

Methods inherited from Base

#channel_config, channel_name, #channel_type, #chat_for, #process_message, required_config_keys, requires_config, #send_message

Constructor Details

#initializeTelegram

Initialize Telegram channel

Raises:

  • (Error)

    If bot_token is not configured



21
22
23
24
25
26
27
28
# File 'lib/botiasloop/channels/telegram.rb', line 21

def initialize
  super
  cfg = channel_config
  @bot_token = cfg["bot_token"]
  @allowed_users = cfg["allowed_users"] || []
  @bot = nil
  @thread_id = nil
end

Instance Method Details

#after_process(_source_id, user_id, _response, _raw_message) ⇒ Object

Log successful response after processing

Parameters:

  • source_id (String)

    Source identifier

  • user_id (String)

    Username

  • response (String)

    Response content

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message



109
110
111
# File 'lib/botiasloop/channels/telegram.rb', line 109

def after_process(_source_id, user_id, _response, _raw_message)
  Logger.info "[Telegram] Response sent to @#{user_id}"
end

#authorized?(username) ⇒ Boolean

Check if username is in allowed list

Parameters:

  • username (String, nil)

    Telegram username

Returns:

  • (Boolean)

    True if allowed



136
137
138
139
140
# File 'lib/botiasloop/channels/telegram.rb', line 136

def authorized?(username)
  return false if username.nil? || @allowed_users.empty?

  @allowed_users.include?(username)
end

#before_process(_source_id, user_id, content, _raw_message) ⇒ Object

Log message before processing

Parameters:

  • source_id (String)

    Source identifier

  • user_id (String)

    Username

  • content (String)

    Message text

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message



99
100
101
# File 'lib/botiasloop/channels/telegram.rb', line 99

def before_process(_source_id, user_id, content, _raw_message)
  Logger.info "[Telegram] Message from @#{user_id}: #{content}"
end

#deliver_message(chat_id, formatted_content) ⇒ Object

Deliver a formatted message to Telegram

Parameters:

  • chat_id (String)

    Telegram chat ID (as string)

  • formatted_content (String)

    Formatted message content



146
147
148
149
150
151
152
153
154
# File 'lib/botiasloop/channels/telegram.rb', line 146

def deliver_message(chat_id, formatted_content)
  return if formatted_content.nil? || formatted_content.empty?

  @bot.api.send_message(
    chat_id: chat_id.to_i,
    text: formatted_content,
    parse_mode: "HTML"
  )
end

#extract_content(raw_message) ⇒ String

Extract content from Telegram message object

Parameters:

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message

Returns:

  • (String)

    Message text



80
81
82
# File 'lib/botiasloop/channels/telegram.rb', line 80

def extract_content(raw_message)
  raw_message.text
end

#extract_user_id(_source_id, raw_message) ⇒ String?

Extract username from Telegram message for authorization

Parameters:

  • source_id (String)

    Source identifier (chat_id)

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message

Returns:

  • (String, nil)

    Username from message



89
90
91
# File 'lib/botiasloop/channels/telegram.rb', line 89

def extract_user_id(_source_id, raw_message)
  raw_message.from&.username
end

#format_message(content) ⇒ String

Format message for Telegram

Parameters:

  • content (String)

    Raw message content

Returns:

  • (String)

    Telegram-compatible HTML



160
161
162
163
164
# File 'lib/botiasloop/channels/telegram.rb', line 160

def format_message(content)
  return "" if content.nil? || content.empty?

  to_telegram_html(content)
end

#handle_error(_source_id, _user_id, error, _raw_message) ⇒ Object

Handle errors by logging only (don’t notify user)

Parameters:

  • source_id (String)

    Source identifier

  • user_id (String)

    Username

  • error (Exception)

    The error that occurred

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message



128
129
130
# File 'lib/botiasloop/channels/telegram.rb', line 128

def handle_error(_source_id, _user_id, error, _raw_message)
  Logger.error "[Telegram] Error processing message: #{error.message}"
end

#handle_unauthorized(source_id, user_id, _raw_message) ⇒ Object

Handle unauthorized access with specific logging

Parameters:

  • source_id (String)

    Source identifier

  • user_id (String)

    Username that was denied

  • raw_message (Telegram::Bot::Types::Message)

    Telegram message



118
119
120
# File 'lib/botiasloop/channels/telegram.rb', line 118

def handle_unauthorized(source_id, user_id, _raw_message)
  Logger.warn "[Telegram] Ignored message from unauthorized user @#{user_id} (chat_id: #{source_id})"
end

#running?Boolean

Check if bot is running

Returns:

  • (Boolean)

    True if bot is running



72
73
74
# File 'lib/botiasloop/channels/telegram.rb', line 72

def running?
  !@bot.nil?
end

#start_listeningObject

Start the Telegram bot and listen for messages



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/botiasloop/channels/telegram.rb', line 31

def start_listening
  if @allowed_users.empty?
    Logger.warn "[Telegram] No allowed_users configured. No messages will be processed."
    Logger.warn "[Telegram] Add usernames to telegram.allowed_users in config."
  end

  Logger.info "[Telegram] Starting bot..."

  @bot = ::Telegram::Bot::Client.new(@bot_token)
  register_bot_commands
  @thread_id = Thread.current.object_id

  @bot.run do |bot|
    bot.listen do |message|
      next unless message.is_a?(::Telegram::Bot::Types::Message) && message.text

      process_message(message.chat.id.to_s, message)
    end
  end
rescue Interrupt
  Logger.info "[Telegram] Shutting down..."
end

#stop_listeningObject

Stop the Telegram bot

Interrupts the thread running the bot to gracefully exit the blocking listen loop.



58
59
60
61
62
63
64
65
66
67
# File 'lib/botiasloop/channels/telegram.rb', line 58

def stop_listening
  Logger.info "[Telegram] Stopping bot..."

  return unless @thread_id

  thread = Thread.list.find { |t| t.object_id == @thread_id }
  return unless thread&.alive?

  thread.raise Interrupt
end