require "http" require "./utils.cr" module Telepathy class Bot enum Control Done end def initialize(@api_token : String) @request_base = "https://api.telegram.org/bot#{@api_token}" @this_user = uninitialized User? @this_user = get_me @last_update_id = uninitialized Int64? @last_update_id = nil @command_hooks = {} of String => Update, Array(String) -> Void @message_hooks = [] of Update -> Void @poll_start_hooks = [] of -> Void @poll_end_hooks = [] of -> Void @poll_channel = Channel(Int64?|Control).new @update_channel = Channel(Array(Update)|Control).new @poll_running = false end def get_me Utils.get_me(@api_token) end def get_updates(timeout = 0) Utils.get_updates(@api_token, timeout, @last_update_id) end def send_message(chat_id : String | Int64, text : String, parse_mode : Utils::ParseMode = Utils::ParseMode::Normal, disable_web_preview : Bool = false, disable_notification : Bool = false, reply_to_message_id : Int64? = nil) Utils.send_message(@api_token, chat_id, text, parse_mode, disable_web_preview, disable_notification, reply_to_message_id) end def send_photo(chat_id : String | Int64, photo : String | File, caption : String? = nil, disable_notification : Bool = false, reply_to_message_id : Int64? = nil) Utils.send_photo(@api_token, chat_id, photo, caption, disable_notification, reply_to_message_id) end def command(command_name, &block: Update, Array(String) -> Void) @command_hooks[command_name] = block end def message(&block: Update -> Void) @message_hooks.push(block) end def poll_start(&block: -> Void) @poll_start_hooks.push(block); end def poll_end(&block: -> Void) @poll_end_hooks.push(block); end private def process_updates(updates) updates.each do |update| if message = update.message @message_hooks.each &.call(update) if entity = message.entities.try { |it| it.first? } text = message.text.as String if entity.offset == 0 && entity.type == "bot_command" divider_index = (text.index /\s|@/) || text.size first_space_index = (text.index /\s/) || text.size command = text[1...divider_index] remaining = text[first_space_index..text.size] params = remaining.empty? ? ([] of String) : (remaining[1...remaining.size].split ' ') @command_hooks[command]?.try { |command| command.call(update, params) } end end end end end private def spawn_worker spawn do while @poll_running begin updates = get_updates 10 process_updates updates @last_update_id = updates.last?.try &.update_id.+(1) || @last_update_id rescue end end @poll_end_hooks.each do |hook| hook.call end end end def poll if !@poll_running @poll_running = true @poll_start_hooks.each do |hook| hook.call end spawn_worker end end def end_poll @poll_running = false end end end