From 1542cdd088837d80afc1c0cec37ee2f2a446c4ab Mon Sep 17 00:00:00 2001 From: atytsky Date: Mon, 9 Nov 2015 21:26:17 +0500 Subject: [PATCH] Added soul --- Gemfile | 3 + bot.rb | 57 +++++++++++++++ lib/telegram/bot.rb | 10 +++ lib/telegram/bot/api.rb | 71 +++++++++++++++++++ lib/telegram/bot/botan.rb | 21 ++++++ lib/telegram/bot/botan/api.rb | 23 ++++++ lib/telegram/bot/client.rb | 64 +++++++++++++++++ lib/telegram/bot/exceptions.rb | 2 + lib/telegram/bot/exceptions/base.rb | 7 ++ lib/telegram/bot/exceptions/response_error.rb | 28 ++++++++ lib/telegram/bot/null_logger.rb | 11 +++ lib/telegram/bot/types.rb | 17 +++++ lib/telegram/bot/types/audio.rb | 14 ++++ lib/telegram/bot/types/base.rb | 9 +++ lib/telegram/bot/types/chat.rb | 14 ++++ lib/telegram/bot/types/contact.rb | 12 ++++ lib/telegram/bot/types/document.rb | 13 ++++ lib/telegram/bot/types/file.rb | 11 +++ lib/telegram/bot/types/force_reply.rb | 10 +++ lib/telegram/bot/types/location.rb | 10 +++ lib/telegram/bot/types/message.rb | 31 ++++++++ lib/telegram/bot/types/photo_size.rb | 12 ++++ lib/telegram/bot/types/reply_keyboard_hide.rb | 10 +++ .../bot/types/reply_keyboard_markup.rb | 12 ++++ lib/telegram/bot/types/sticker.rb | 13 ++++ lib/telegram/bot/types/update.rb | 10 +++ lib/telegram/bot/types/user.rb | 12 ++++ lib/telegram/bot/types/video.rb | 15 ++++ lib/telegram/bot/types/voice.rb | 12 ++++ lib/telegram/bot/version.rb | 5 ++ 30 files changed, 539 insertions(+) create mode 100644 Gemfile create mode 100644 bot.rb create mode 100644 lib/telegram/bot.rb create mode 100644 lib/telegram/bot/api.rb create mode 100644 lib/telegram/bot/botan.rb create mode 100644 lib/telegram/bot/botan/api.rb create mode 100644 lib/telegram/bot/client.rb create mode 100644 lib/telegram/bot/exceptions.rb create mode 100644 lib/telegram/bot/exceptions/base.rb create mode 100644 lib/telegram/bot/exceptions/response_error.rb create mode 100644 lib/telegram/bot/null_logger.rb create mode 100644 lib/telegram/bot/types.rb create mode 100644 lib/telegram/bot/types/audio.rb create mode 100644 lib/telegram/bot/types/base.rb create mode 100644 lib/telegram/bot/types/chat.rb create mode 100644 lib/telegram/bot/types/contact.rb create mode 100644 lib/telegram/bot/types/document.rb create mode 100644 lib/telegram/bot/types/file.rb create mode 100644 lib/telegram/bot/types/force_reply.rb create mode 100644 lib/telegram/bot/types/location.rb create mode 100644 lib/telegram/bot/types/message.rb create mode 100644 lib/telegram/bot/types/photo_size.rb create mode 100644 lib/telegram/bot/types/reply_keyboard_hide.rb create mode 100644 lib/telegram/bot/types/reply_keyboard_markup.rb create mode 100644 lib/telegram/bot/types/sticker.rb create mode 100644 lib/telegram/bot/types/update.rb create mode 100644 lib/telegram/bot/types/user.rb create mode 100644 lib/telegram/bot/types/video.rb create mode 100644 lib/telegram/bot/types/voice.rb create mode 100644 lib/telegram/bot/version.rb diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..fa75df1 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gemspec diff --git a/bot.rb b/bot.rb new file mode 100644 index 0000000..7bd1e73 --- /dev/null +++ b/bot.rb @@ -0,0 +1,57 @@ +#require 'telegram/bot' +require './lib/telegram/bot' +require './lib/tytsky' + +token = '146479675:AAHmWFBCFpMCAqymM6HjUbcBBP9aHMR0bc0' + +at = Tytsky.instance + +answers = + Telegram::Bot::Types::ReplyKeyboardMarkup + .new(keyboard: [%w(Заклинание Рандом), %w(Задача? Стэндап?), %w(Монолог)], one_time_keyboard: false) + +Telegram::Bot::Client.run(token) do |bot| + bot.listen do |message| + message.to_json + case message.text + when 'Монолог' + kb = Telegram::Bot::Types::ReplyKeyboardHide.new(hide_keyboard: true) + rand(10).times do + bot.api.send_message(chat_id: message.chat.id, text: "#{at.talk}", reply_markup: kb) + sleep(2) + end + bot.api.send_message( + chat_id: message.chat.id, + text: "#{at.talk}", + reply_markup: answers + ) + when 'Рандом' + bot.api.send_message( + chat_id: message.chat.id, + text: "#{at.talk}", + reply_markup: answers + ) + when 'Заклинание' + bot.api.send_message( + chat_id: message.chat.id, + text: "#{at.cast}", + reply_markup: answers + ) + when 'Задача?' + bot.api.send_message( + chat_id: message.chat.id, + text: "#{at.command}", + reply_markup: answers + ) + when 'Стэндап?' + bot.api.send_message( + chat_id: message.chat.id, + text: "#{at.standup_time}", + reply_markup: answers + ) + when '/start' + question = 'Что вы от меня хотите?' + bot.api.send_message(chat_id: message.chat.id, text: question, reply_markup: answers) + end + end +end \ No newline at end of file diff --git a/lib/telegram/bot.rb b/lib/telegram/bot.rb new file mode 100644 index 0000000..a314e4a --- /dev/null +++ b/lib/telegram/bot.rb @@ -0,0 +1,10 @@ +require 'httmultiparty' +require 'persistent_httparty' +require 'virtus' + +require 'telegram/bot/types' +require 'telegram/bot/exceptions' +require 'telegram/bot/api' +require 'telegram/bot/null_logger' +require 'telegram/bot/client' +require 'telegram/bot/version' diff --git a/lib/telegram/bot/api.rb b/lib/telegram/bot/api.rb new file mode 100644 index 0000000..b5aba28 --- /dev/null +++ b/lib/telegram/bot/api.rb @@ -0,0 +1,71 @@ +module Telegram + module Bot + class Api + include HTTMultiParty + + ENDPOINTS = %w( + getMe sendMessage forwardMessage sendPhoto sendAudio sendDocument + sendSticker sendVideo sendVoice sendLocation sendChatAction + getUserProfilePhotos getUpdates setWebhook getFile + ).freeze + REPLY_MARKUP_TYPES = [ + Telegram::Bot::Types::ReplyKeyboardMarkup, + Telegram::Bot::Types::ReplyKeyboardHide, + Telegram::Bot::Types::ForceReply + ].freeze + POOL_SIZE = ENV.fetch('TELEGRAM_BOT_POOL_SIZE', 1).to_i.freeze + + attr_reader :token + + base_uri 'https://api.telegram.org' + persistent_connection_adapter pool_size: POOL_SIZE, + keep_alive: 30, + force_retry: true + + def initialize(token) + @token = token + 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 call(endpoint, raw_params = {}) + params = build_params(raw_params) + response = self.class.post("/bot#{token}/#{endpoint}", query: params) + if response.code == 200 + response.to_hash + else + fail Exceptions::ResponseError.new(response), + 'Telegram API has returned the error.' + end + end + + private + + def build_params(h) + h.each_with_object({}) do |(key, value), params| + params[key] = sanitize_value(value) + end + end + + def sanitize_value(value) + jsonify_reply_markup(value) + end + + def jsonify_reply_markup(value) + return value unless REPLY_MARKUP_TYPES.include?(value.class) + value.to_h.to_json + end + + def camelize(method_name) + words = method_name.split('_') + words.drop(1).map(&:capitalize!) + words.join + end + end + end +end diff --git a/lib/telegram/bot/botan.rb b/lib/telegram/bot/botan.rb new file mode 100644 index 0000000..9a5e843 --- /dev/null +++ b/lib/telegram/bot/botan.rb @@ -0,0 +1,21 @@ +require 'telegram/bot/botan/api' + +module Telegram + module Bot + module Botan + attr_reader :botan + + def enable_botan!(token) + @botan ||= Botan::Api.new(token) + end + + def track(*args) + botan.track(*args) if defined?(botan) + end + end + end +end + +if defined?(Telegram::Bot::Client) + Telegram::Bot::Client.send(:include, Telegram::Bot::Botan) +end diff --git a/lib/telegram/bot/botan/api.rb b/lib/telegram/bot/botan/api.rb new file mode 100644 index 0000000..9820d83 --- /dev/null +++ b/lib/telegram/bot/botan/api.rb @@ -0,0 +1,23 @@ +module Telegram + module Bot + module Botan + class Api + include HTTParty + + attr_reader :token + + base_uri 'https://api.botan.io' + + def initialize(token) + @token = token + end + + def track(event, uid, properties = {}) + self.class.post('/track', + query: { token: token, name: event, uid: uid }, + body: properties.to_json) + end + end + end + end +end diff --git a/lib/telegram/bot/client.rb b/lib/telegram/bot/client.rb new file mode 100644 index 0000000..5b47c0c --- /dev/null +++ b/lib/telegram/bot/client.rb @@ -0,0 +1,64 @@ +module Telegram + module Bot + class Client + TIMEOUT_EXCEPTIONS = [Timeout::Error] + TIMEOUT_EXCEPTIONS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout) + + attr_reader :api, :offset, :timeout, :logger + + def self.run(*args, &block) + new(*args).run(&block) + end + + def initialize(token, h = {}) + options = default_options.merge(h) + @api = Api.new(token) + @offset = options[:offset] + @timeout = options[:timeout] + @logger = options[:logger] + end + + def run + yield self + end + + def listen(&block) + logger.info('Starting bot') + running = true + Signal.trap('INT') { running = false } + fetch_updates(&block) while running + exit + end + + def fetch_updates + response = api.getUpdates(offset: offset, timeout: timeout) + return unless response['ok'] + + response['result'].each do |data| + update = Types::Update.new(data) + @offset = update.update_id.next + log_incoming_message(update.message) + yield update.message + end + rescue *TIMEOUT_EXCEPTIONS + retry + end + + private + + def default_options + { offset: 0, timeout: 20, logger: NullLogger.new } + end + + def log_incoming_message(message) + logger.info( + format( + 'Incoming message: text="%s" uid=%i', + message.text, + message.from.id + ) + ) + end + end + end +end diff --git a/lib/telegram/bot/exceptions.rb b/lib/telegram/bot/exceptions.rb new file mode 100644 index 0000000..5c2b920 --- /dev/null +++ b/lib/telegram/bot/exceptions.rb @@ -0,0 +1,2 @@ +require 'telegram/bot/exceptions/base' +require 'telegram/bot/exceptions/response_error' diff --git a/lib/telegram/bot/exceptions/base.rb b/lib/telegram/bot/exceptions/base.rb new file mode 100644 index 0000000..2900d61 --- /dev/null +++ b/lib/telegram/bot/exceptions/base.rb @@ -0,0 +1,7 @@ +module Telegram + module Bot + module Exceptions + class Base < StandardError; end + end + end +end diff --git a/lib/telegram/bot/exceptions/response_error.rb b/lib/telegram/bot/exceptions/response_error.rb new file mode 100644 index 0000000..d9f9c4b --- /dev/null +++ b/lib/telegram/bot/exceptions/response_error.rb @@ -0,0 +1,28 @@ +module Telegram + module Bot + module Exceptions + class ResponseError < Base + attr_reader :response + + def initialize(response) + @response = response + end + + def to_s + super + + format(' (%s)', data.map { |k, v| %(#{k}: "#{v}") }.join(', ')) + end + + private + + def data + @data ||= begin + JSON.parse(response.body) + rescue JSON::ParserError + { error_code: response.code, uri: response.request.last_uri.to_s } + end + end + end + end + end +end diff --git a/lib/telegram/bot/null_logger.rb b/lib/telegram/bot/null_logger.rb new file mode 100644 index 0000000..dc6803a --- /dev/null +++ b/lib/telegram/bot/null_logger.rb @@ -0,0 +1,11 @@ +module Telegram + module Bot + class NullLogger < Logger + def initialize(*) + end + + def add(*) + end + end + end +end diff --git a/lib/telegram/bot/types.rb b/lib/telegram/bot/types.rb new file mode 100644 index 0000000..8c48e44 --- /dev/null +++ b/lib/telegram/bot/types.rb @@ -0,0 +1,17 @@ +require 'telegram/bot/types/base' +require 'telegram/bot/types/user' +require 'telegram/bot/types/audio' +require 'telegram/bot/types/photo_size' +require 'telegram/bot/types/document' +require 'telegram/bot/types/sticker' +require 'telegram/bot/types/video' +require 'telegram/bot/types/voice' +require 'telegram/bot/types/contact' +require 'telegram/bot/types/location' +require 'telegram/bot/types/chat' +require 'telegram/bot/types/message' +require 'telegram/bot/types/update' +require 'telegram/bot/types/reply_keyboard_markup' +require 'telegram/bot/types/reply_keyboard_hide' +require 'telegram/bot/types/force_reply' +require 'telegram/bot/types/file' diff --git a/lib/telegram/bot/types/audio.rb b/lib/telegram/bot/types/audio.rb new file mode 100644 index 0000000..4b8f33b --- /dev/null +++ b/lib/telegram/bot/types/audio.rb @@ -0,0 +1,14 @@ +module Telegram + module Bot + module Types + class Audio < Base + attribute :file_id, String + attribute :duration, Integer + attribute :performer, String + attribute :title, String + attribute :mime_type, String + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/base.rb b/lib/telegram/bot/types/base.rb new file mode 100644 index 0000000..ceef170 --- /dev/null +++ b/lib/telegram/bot/types/base.rb @@ -0,0 +1,9 @@ +module Telegram + module Bot + module Types + class Base + include Virtus.model + end + end + end +end diff --git a/lib/telegram/bot/types/chat.rb b/lib/telegram/bot/types/chat.rb new file mode 100644 index 0000000..94cc448 --- /dev/null +++ b/lib/telegram/bot/types/chat.rb @@ -0,0 +1,14 @@ +module Telegram + module Bot + module Types + class Chat < Base + attribute :id, Integer + attribute :type, String + attribute :title, String + attribute :username, String + attribute :first_name, String + attribute :last_name, String + end + end + end +end diff --git a/lib/telegram/bot/types/contact.rb b/lib/telegram/bot/types/contact.rb new file mode 100644 index 0000000..90bbc44 --- /dev/null +++ b/lib/telegram/bot/types/contact.rb @@ -0,0 +1,12 @@ +module Telegram + module Bot + module Types + class Contact < Base + attribute :phone_number, String + attribute :first_name, String + attribute :last_name, String + attribute :user_id, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/document.rb b/lib/telegram/bot/types/document.rb new file mode 100644 index 0000000..7a8a337 --- /dev/null +++ b/lib/telegram/bot/types/document.rb @@ -0,0 +1,13 @@ +module Telegram + module Bot + module Types + class Document < Base + attribute :file_id, String + attribute :thumb, PhotoSize + attribute :file_name, String + attribute :mime_type, String + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/file.rb b/lib/telegram/bot/types/file.rb new file mode 100644 index 0000000..3671a8e --- /dev/null +++ b/lib/telegram/bot/types/file.rb @@ -0,0 +1,11 @@ +module Telegram + module Bot + module Types + class File < Base + attribute :file_id, String + attribute :file_size, Integer + attribute :file_path, String + end + end + end +end diff --git a/lib/telegram/bot/types/force_reply.rb b/lib/telegram/bot/types/force_reply.rb new file mode 100644 index 0000000..c935083 --- /dev/null +++ b/lib/telegram/bot/types/force_reply.rb @@ -0,0 +1,10 @@ +module Telegram + module Bot + module Types + class ForceReply < Base + attribute :force_reply, Boolean + attribute :selective, Boolean, default: false + end + end + end +end diff --git a/lib/telegram/bot/types/location.rb b/lib/telegram/bot/types/location.rb new file mode 100644 index 0000000..1156100 --- /dev/null +++ b/lib/telegram/bot/types/location.rb @@ -0,0 +1,10 @@ +module Telegram + module Bot + module Types + class Location < Base + attribute :longitude, Float + attribute :latitude, Float + end + end + end +end diff --git a/lib/telegram/bot/types/message.rb b/lib/telegram/bot/types/message.rb new file mode 100644 index 0000000..b4ec0e8 --- /dev/null +++ b/lib/telegram/bot/types/message.rb @@ -0,0 +1,31 @@ +module Telegram + module Bot + module Types + class Message < Base + attribute :message_id, Integer + attribute :from, User + attribute :date, Integer + attribute :forward_from, User + attribute :forward_date, Integer + attribute :reply_to_message, Message + attribute :text, String + attribute :audio, Audio + attribute :document, Document + attribute :photo, Array[PhotoSize] + attribute :sticker, Sticker + attribute :video, Video + attribute :voice, Voice + attribute :caption, String + attribute :contact, Contact + attribute :location, Location + attribute :new_chat_participant, User + attribute :left_chat_participant, User + attribute :new_chat_title, String + attribute :new_chat_photo, Array[PhotoSize] + attribute :delete_chat_photo, Boolean + attribute :group_chat_created, Boolean + attribute :chat, Chat + end + end + end +end diff --git a/lib/telegram/bot/types/photo_size.rb b/lib/telegram/bot/types/photo_size.rb new file mode 100644 index 0000000..cba685b --- /dev/null +++ b/lib/telegram/bot/types/photo_size.rb @@ -0,0 +1,12 @@ +module Telegram + module Bot + module Types + class PhotoSize < Base + attribute :file_id, String + attribute :width, Integer + attribute :height, Integer + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/reply_keyboard_hide.rb b/lib/telegram/bot/types/reply_keyboard_hide.rb new file mode 100644 index 0000000..92e984e --- /dev/null +++ b/lib/telegram/bot/types/reply_keyboard_hide.rb @@ -0,0 +1,10 @@ +module Telegram + module Bot + module Types + class ReplyKeyboardHide < Base + attribute :hide_keyboard, Boolean + attribute :selective, Boolean, default: false + end + end + end +end diff --git a/lib/telegram/bot/types/reply_keyboard_markup.rb b/lib/telegram/bot/types/reply_keyboard_markup.rb new file mode 100644 index 0000000..e9916ef --- /dev/null +++ b/lib/telegram/bot/types/reply_keyboard_markup.rb @@ -0,0 +1,12 @@ +module Telegram + module Bot + module Types + class ReplyKeyboardMarkup < Base + attribute :keyboard, Array[Array[String]] + attribute :resize_keyboard, Boolean, default: false + attribute :one_time_keyboard, Boolean, default: false + attribute :selective, Boolean, default: false + end + end + end +end diff --git a/lib/telegram/bot/types/sticker.rb b/lib/telegram/bot/types/sticker.rb new file mode 100644 index 0000000..2f30e4b --- /dev/null +++ b/lib/telegram/bot/types/sticker.rb @@ -0,0 +1,13 @@ +module Telegram + module Bot + module Types + class Sticker < Base + attribute :file_id, String + attribute :width, Integer + attribute :height, Integer + attribute :thumb, PhotoSize + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/update.rb b/lib/telegram/bot/types/update.rb new file mode 100644 index 0000000..b985740 --- /dev/null +++ b/lib/telegram/bot/types/update.rb @@ -0,0 +1,10 @@ +module Telegram + module Bot + module Types + class Update < Base + attribute :update_id, Integer + attribute :message, Message + end + end + end +end diff --git a/lib/telegram/bot/types/user.rb b/lib/telegram/bot/types/user.rb new file mode 100644 index 0000000..701e1fb --- /dev/null +++ b/lib/telegram/bot/types/user.rb @@ -0,0 +1,12 @@ +module Telegram + module Bot + module Types + class User < Base + attribute :id, Integer + attribute :first_name, String + attribute :last_name, String + attribute :username, String + end + end + end +end diff --git a/lib/telegram/bot/types/video.rb b/lib/telegram/bot/types/video.rb new file mode 100644 index 0000000..ffccf3f --- /dev/null +++ b/lib/telegram/bot/types/video.rb @@ -0,0 +1,15 @@ +module Telegram + module Bot + module Types + class Video < Base + attribute :file_id, String + attribute :width, Integer + attribute :height, Integer + attribute :duration, Integer + attribute :thumb, PhotoSize + attribute :mime_type, String + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/types/voice.rb b/lib/telegram/bot/types/voice.rb new file mode 100644 index 0000000..3e894c4 --- /dev/null +++ b/lib/telegram/bot/types/voice.rb @@ -0,0 +1,12 @@ +module Telegram + module Bot + module Types + class Voice < Base + attribute :file_id, String + attribute :duration, Integer + attribute :mime_type, String + attribute :file_size, Integer + end + end + end +end diff --git a/lib/telegram/bot/version.rb b/lib/telegram/bot/version.rb new file mode 100644 index 0000000..e747543 --- /dev/null +++ b/lib/telegram/bot/version.rb @@ -0,0 +1,5 @@ +module Telegram + module Bot + VERSION = '0.3.10' + end +end