# frozen_string_literal: true module Telegram module Bot class Api ENDPOINTS = %w[ getUpdates setWebhook deleteWebhook getWebhookInfo getMe sendMessage forwardMessage sendPhoto sendAudio sendDocument sendVideo sendVoice sendVideoNote sendMediaGroup sendLocation editMessageLiveLocation stopMessageLiveLocation sendVenue sendContact sendChatAction getUserProfilePhotos getFile kickChatMember unbanChatMember restrictChatMember promoteChatMember leaveChat getChat getChatAdministrators exportChatInviteLink setChatPhoto deleteChatPhoto setChatTitle setChatDescription pinChatMessage unpinChatMessage getChatMembersCount getChatMember setChatStickerSet deleteChatStickerSet answerCallbackQuery editMessageText editMessageCaption editMessageReplyMarkup deleteMessage sendSticker getStickerSet uploadStickerFile createNewStickerSet addStickerToSet setStickerPositionInSet deleteStickerFromSet answerInlineQuery sendInvoice answerShippingQuery answerPreCheckoutQuery sendGame setGameScore getGameHighScores setPassportDataErrors editMessageMedia sendAnimation sendPoll stopPoll setChatPermissions setChatAdministratorCustomTitle sendDice getMyCommands setMyCommands deleteMyCommands setStickerSetThumb logOut close copyMessage createChatInviteLink editChatInviteLink revokeChatInviteLink approveChatJoinRequest declineChatJoinRequest banChatSenderChat unbanChatSenderChat answerWebAppQuery setChatMenuButton getChatMenuButton setMyDefaultAdministratorRights getMyDefaultAdministratorRights createInvoiceLink editGeneralForumTopic closeGeneralForumTopic reopenGeneralForumTopic hideGeneralForumTopic unhideGeneralForumTopic ].freeze attr_reader :token, :url, :environment def initialize(token, url: 'https://api.telegram.org', environment: :production) @token = token @url = url @environment = environment.downcase.to_sym end def method_missing(method_name, *args, &block) endpoint = method_name.to_s endpoint = camelize(endpoint) if endpoint.include?('_') ENDPOINTS.include?(endpoint) ? call(endpoint, *args) : super end def respond_to_missing?(*args) method_name = args[0].to_s method_name = camelize(method_name) if method_name.include?('_') ENDPOINTS.include?(method_name) || super end def call(endpoint, raw_params = {}) params = build_params(raw_params) path = build_path(endpoint) response = conn.post(path, params) unless response.status == 200 raise Exceptions::ResponseError.new(response), 'Telegram API has returned the error.' end JSON.parse(response.body) end private def build_params(params) params.transform_values do |value| sanitize_value(value) end end def build_path(endpoint) path = "/bot#{token}/" path += 'test/' if environment == :test path + endpoint end def sanitize_value(value) jsonify_value(value) end def jsonify_value(value) jsonify_value?(value) ? value.to_json : value end def jsonify_value?(value) value.respond_to?(:to_compact_hash) || value.is_a?(Array) end def camelize(method_name) words = method_name.split('_') words.drop(1).map(&:capitalize!) words.join end def conn @conn ||= Faraday.new(url: url) do |faraday| faraday.request :multipart faraday.request :url_encoded faraday.adapter Telegram::Bot.configuration.adapter faraday.options.timeout = Telegram::Bot.configuration.connection_timeout faraday.options.open_timeout = Telegram::Bot.configuration.connection_open_timeout end end end end end