tgbot 0.1.6 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +9 -9
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +126 -21
- data/Rakefile +1 -10
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/lib/api.yaml +5328 -0
- data/lib/tgbot.rb +291 -5
- data/lib/tgbot/version.rb +3 -3
- data/tgbot.gemspec +30 -30
- data/tool/gen.rb +34 -0
- metadata +11 -26
- data/example.rb +0 -110
- data/lib/methods.json +0 -1
- data/lib/tgbot/core.rb +0 -145
- data/lib/tgbot/dsl.rb +0 -59
- data/lib/tgbot/runner.rb +0 -46
- data/lib/tgbot/update.rb +0 -83
- data/lib/types.json +0 -1
- data/tools/gen_methods_json.rb +0 -19
- data/tools/gen_methods_txt.rb +0 -15
- data/tools/gen_types_json.rb +0 -15
- data/tools/gen_types_txt.rb +0 -21
- data/tools/methods.json +0 -1
- data/tools/methods.txt +0 -372
- data/tools/types.json +0 -1
- data/tools/types.txt +0 -605
- data/usage.md +0 -97
data/example.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'faraday'
|
3
|
-
require './helper'
|
4
|
-
save_pid
|
5
|
-
require 'tgbot'
|
6
|
-
Garage = load_data.shuffle
|
7
|
-
Cache = {}
|
8
|
-
TOKEN =
|
9
|
-
Tgbot.run TOKEN, proxy: 'http://127.0.0.1:1080' do |bot|
|
10
|
-
|
11
|
-
bot.start do
|
12
|
-
log "\e[33m#{bot.name}\e[32m, at your service.", 2
|
13
|
-
end
|
14
|
-
bot.finish do
|
15
|
-
log "byebye.", 2
|
16
|
-
end
|
17
|
-
|
18
|
-
bot.get 'start' do
|
19
|
-
send_message(<<~EOF, parse_mode: 'Markdown')
|
20
|
-
```
|
21
|
-
start : 显示此帮助信息
|
22
|
-
drive : 随机返回一张车库里的图
|
23
|
-
对该图回复 “原图” : 返回原图
|
24
|
-
exchange 100 CNY to JPY : 汇率转换
|
25
|
-
register : 添加自定义功能(会先提交给作者)
|
26
|
-
```
|
27
|
-
EOF
|
28
|
-
end
|
29
|
-
|
30
|
-
bot.get 'drive' do
|
31
|
-
pic = Garage.pop
|
32
|
-
log ">> Sending #{File.basename(pic)} to @#{message.from.username} ##{id}", 6
|
33
|
-
bytes = File.size pic
|
34
|
-
size = hsize bytes
|
35
|
-
reply "正在发车 (#{size} #{htime(bytes / 30720)})"
|
36
|
-
x = reply_photo pic, caption: File.basename(pic, '.*')
|
37
|
-
if self.done = x['ok']
|
38
|
-
Cache["drive_#{x['result']['message_id']}"] = pic
|
39
|
-
end
|
40
|
-
self.done! if self.count > 1
|
41
|
-
end
|
42
|
-
bot.get '原图' do
|
43
|
-
x = message&.reply_to_message&.message_id
|
44
|
-
pic = Cache["drive_#{x}"]
|
45
|
-
unless pic
|
46
|
-
reply '没找到原图,重开'
|
47
|
-
next
|
48
|
-
end
|
49
|
-
log ">> Sending original #{File.basename(pic)} to @#{message.from.username} ##{id}", 6
|
50
|
-
reply_document pic
|
51
|
-
end
|
52
|
-
|
53
|
-
bot.get 'exchange' do
|
54
|
-
x = text&.match /([-+]?[1-9]\d*(\.\d+)?)\s*([A-Z]+)\s*to\s*([A-Z]+)/
|
55
|
-
unless x
|
56
|
-
reply 'Usage: exchange 100 CNY to JPY'
|
57
|
-
next
|
58
|
-
end
|
59
|
-
n, f, t = x.values_at 1, 3, 4
|
60
|
-
n = Float(n) rescue next
|
61
|
-
Cache["exchange_#{f}"] ||= JSON.parse Faraday.get("http://api.fixer.io/latest?base=#{f}").body
|
62
|
-
next unless Cache["exchange_#{f}"] && !Cache["exchange_#{f}"]['error']
|
63
|
-
next unless Cache["exchange_#{f}"]['rates'][t]
|
64
|
-
n *= Cache["exchange_#{f}"]['rates'][t]
|
65
|
-
t = Cache["exchange_#{f}"]['date']
|
66
|
-
reply "#{'%.2f' % n} (#{t})"
|
67
|
-
end
|
68
|
-
|
69
|
-
bot.before do |update|
|
70
|
-
log ">> Processing ##{update.id}"
|
71
|
-
log "@#{update.message&.from&.first_name}: #{update.text}", 3
|
72
|
-
end
|
73
|
-
bot.after do |update|
|
74
|
-
if update.done?
|
75
|
-
log "=> Success ##{update.id}", 2
|
76
|
-
else
|
77
|
-
log "?> Retry ##{update.id}", 3
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
bot.get 'register' do
|
82
|
-
e = message&.entities&.find { |e| e.type == 'pre' }
|
83
|
-
if e.nil?
|
84
|
-
send_message(<<~EOF)
|
85
|
-
register <功能名>
|
86
|
-
```
|
87
|
-
get /command/ do |matched|
|
88
|
-
# your code here
|
89
|
-
end
|
90
|
-
```
|
91
|
-
EOF
|
92
|
-
next
|
93
|
-
end
|
94
|
-
open 'register.rb', 'a' do |f|
|
95
|
-
f.puts text[e.offset, e.length]
|
96
|
-
end
|
97
|
-
reply '脚本已备分'
|
98
|
-
end
|
99
|
-
|
100
|
-
bot.get 'coin' do
|
101
|
-
send_message Array.new(text&.match(/\d+/)&.to_s.to_i || 1){ ['🌞', '🌚'].sample }.join
|
102
|
-
end
|
103
|
-
bot.get 'roll' do
|
104
|
-
send_message rand(text&.match(/\d+/)&.to_s.to_i.nonzero? || 100).to_s
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
save_data Garage
|
110
|
-
delete_pid
|
data/lib/methods.json
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"getUpdates":{"ret":"[Update]","params":{"offset":{"type":"Integer","optional":true},"limit":{"type":"Integer","optional":true},"timeout":{"type":"Integer","optional":true},"allowed_updates":{"type":"[String]","optional":true}}},"setWebhook":{"ret":"True","params":{"url":{"type":"String","optional":false},"certificate":{"type":"InputFile","optional":true},"max_connections":{"type":"Integer","optional":true},"allowed_updates":{"type":"[String]","optional":true}}},"deleteWebhook":{"ret":"True","params":{}},"getWebhookInfo":{"ret":"WebhookInfo","params":{}},"getMe":{"ret":"User","params":{}},"sendMessage":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"text":{"type":"String","optional":false},"parse_mode":{"type":"String","optional":true},"disable_web_page_preview":{"type":"Boolean","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"forwardMessage":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"from_chat_id":{"type":"Integer|String","optional":false},"disable_notification":{"type":"Boolean","optional":true},"message_id":{"type":"Integer","optional":false}}},"sendPhoto":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"photo":{"type":"InputFile|String","optional":false},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendAudio":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"audio":{"type":"InputFile|String","optional":false},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"duration":{"type":"Integer","optional":true},"performer":{"type":"String","optional":true},"title":{"type":"String","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendDocument":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"document":{"type":"InputFile|String","optional":false},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendVideo":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"video":{"type":"InputFile|String","optional":false},"duration":{"type":"Integer","optional":true},"width":{"type":"Integer","optional":true},"height":{"type":"Integer","optional":true},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"supports_streaming":{"type":"Boolean","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendVoice":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"voice":{"type":"InputFile|String","optional":false},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"duration":{"type":"Integer","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendVideoNote":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"video_note":{"type":"InputFile|String","optional":false},"duration":{"type":"Integer","optional":true},"length":{"type":"Integer","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendMediaGroup":{"ret":"[Message]","params":{"chat_id":{"type":"Integer|String","optional":false},"media":{"type":"[InputMedia]","optional":false},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true}}},"sendLocation":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"latitude":{"type":"Float","optional":false},"longitude":{"type":"Float","optional":false},"live_period":{"type":"Integer","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"editMessageLiveLocation":{"ret":"Message|True","params":{"chat_id":{"type":"Integer|String","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true},"latitude":{"type":"Float","optional":false},"longitude":{"type":"Float","optional":false},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"stopMessageLiveLocation":{"ret":"Message|True","params":{"chat_id":{"type":"Integer|String","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"sendVenue":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"latitude":{"type":"Float","optional":false},"longitude":{"type":"Float","optional":false},"title":{"type":"String","optional":false},"address":{"type":"String","optional":false},"foursquare_id":{"type":"String","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendContact":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"phone_number":{"type":"String","optional":false},"first_name":{"type":"String","optional":false},"last_name":{"type":"String","optional":false},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"sendChatAction":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"action":{"type":"String","optional":false}}},"getUserProfilePhotos":{"ret":"UserProfilePhotos","params":{"user_id":{"type":"Integer","optional":false},"offset":{"type":"Integer","optional":true},"limit":{"type":"Integer","optional":true}}},"getFile":{"ret":"File","params":{"file_id":{"type":"String","optional":false}}},"kickChatMember":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"user_id":{"type":"Integer","optional":false},"until_date":{"type":"Integer","optional":true}}},"unbanChatMember":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"user_id":{"type":"Integer","optional":false}}},"restrictChatMember":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"user_id":{"type":"Integer","optional":false},"until_date":{"type":"Integer","optional":true},"can_send_messages":{"type":"Boolean","optional":true},"can_send_media_messages":{"type":"Boolean","optional":true},"can_send_other_messages":{"type":"Boolean","optional":true},"can_add_web_page_previews":{"type":"Boolean","optional":true}}},"promoteChatMember":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"user_id":{"type":"Integer","optional":false},"can_change_info":{"type":"Boolean","optional":true},"can_post_messages":{"type":"Boolean","optional":true},"can_edit_messages":{"type":"Boolean","optional":true},"can_delete_messages":{"type":"Boolean","optional":true},"can_invite_users":{"type":"Boolean","optional":true},"can_restrict_members":{"type":"Boolean","optional":true},"can_pin_messages":{"type":"Boolean","optional":true},"can_promote_members":{"type":"Boolean","optional":true}}},"exportChatInviteLink":{"ret":"String","params":{"chat_id":{"type":"Integer|String","optional":false}}},"setChatPhoto":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"photo":{"type":"InputFile","optional":false}}},"deleteChatPhoto":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false}}},"setChatTitle":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"title":{"type":"String","optional":false}}},"setChatDescription":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"description":{"type":"String","optional":true}}},"pinChatMessage":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"message_id":{"type":"Integer","optional":false},"disable_notification":{"type":"Boolean","optional":true}}},"unpinChatMessage":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false}}},"leaveChat":{"ret":"Boolean","params":{"chat_id":{"type":"Integer|String","optional":false}}},"getChat":{"ret":"Chat","params":{"chat_id":{"type":"Integer|String","optional":false}}},"getChatAdministrators":{"ret":"[ChatMember]","params":{"chat_id":{"type":"Integer|String","optional":false}}},"getChatMembersCount":{"ret":"Integer","params":{"chat_id":{"type":"Integer|String","optional":false}}},"getChatMember":{"ret":"ChatMember","params":{"chat_id":{"type":"Integer|String","optional":false},"user_id":{"type":"Integer","optional":false}}},"setChatStickerSet":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"sticker_set_name":{"type":"String","optional":false}}},"deleteChatStickerSet":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false}}},"answerCallbackQuery":{"ret":"True","params":{"callback_query_id":{"type":"String","optional":false},"text":{"type":"Boolean","optional":true},"show_alert":{"type":"Boolean","optional":true},"url":{"type":"String","optional":true},"cache_time":{"type":"Integer","optional":true}}},"editMessageText":{"ret":"Message|True","params":{"chat_id":{"type":"Integer|String","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true},"text":{"type":"String","optional":false},"parse_mode":{"type":"String","optional":true},"disable_web_page_preview":{"type":"Boolean","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"editMessageCaption":{"ret":"Message|True","params":{"chat_id":{"type":"Integer|String","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true},"caption":{"type":"String","optional":true},"parse_mode":{"type":"String","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"editMessageReplyMarkup":{"ret":"Message|True","params":{"chat_id":{"type":"Integer|String","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"deleteMessage":{"ret":"True","params":{"chat_id":{"type":"Integer|String","optional":false},"message_id":{"type":"Integer","optional":false}}},"sendSticker":{"ret":"Message","params":{"chat_id":{"type":"Integer|String","optional":false},"sticker":{"type":"InputFile|String","optional":false},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup|ReplyKeyboardMarkup|ReplyKeyboardRemove|ForceReply","optional":true}}},"getStickerSet":{"ret":"StickerSet","params":{"name":{"type":"String","optional":false}}},"uploadStickerFile":{"ret":"File","params":{"user_id":{"type":"Integer","optional":false},"png_sticker":{"type":"InputFile","optional":false}}},"createNewStickerSet":{"ret":"True","params":{"name":{"type":"String","optional":false},"title":{"type":"String","optional":false},"png_sticker":{"type":"InputFile|String","optional":false},"emojis":{"type":"String","optional":false},"contains_masks":{"type":"Boolean","optional":true},"mask_position":{"type":"MaskPosition","optional":true}}},"addStickerToSet":{"ret":"True","params":{"user_id":{"type":"Integer","optional":false},"name":{"type":"String","optional":false},"png_sticker":{"type":"InputFile|String","optional":false},"emojis":{"type":"String","optional":false},"mask_position":{"type":"MaskPosition","optional":true}}},"setStickerPositionInSet":{"ret":"True","params":{"sticker":{"type":"String","optional":false},"position":{"type":"Integer","optional":false}}},"deleteStickerFromSet":{"ret":"True","params":{"sticker":{"type":"String","optional":false}}},"answerInlineQuery":{"ret":"Boolean","params":{"inline_query_id":{"type":"String","optional":false},"results":{"type":"[InlineQueryResult]","optional":false},"cache_time":{"type":"Integer","optional":true},"is_personal":{"type":"Boolean","optional":true},"next_offset":{"type":"String","optional":true},"switch_pm_text":{"type":"String","optional":true},"switch_pm_parameter":{"type":"String","optional":true}}},"sendInvoice":{"ret":"Message","params":{"chat_id":{"type":"Integer","optional":false},"title":{"type":"String","optional":false},"description":{"type":"String","optional":false},"payload":{"type":"String","optional":false},"provider_token":{"type":"String","optional":false},"start_parameter":{"type":"String","optional":false},"currency":{"type":"String","optional":false},"prices":{"type":"[LabeledPrice]","optional":false},"provider_data":{"type":"String","optional":true},"photo_url":{"type":"String","optional":true},"photo_size":{"type":"Integer","optional":true},"photo_width":{"type":"Integer","optional":true},"photo_height":{"type":"Integer","optional":true},"need_name":{"type":"Boolean","optional":true},"need_phone_number":{"type":"Boolean","optional":true},"need_email":{"type":"Boolean","optional":true},"need_shipping_address":{"type":"Boolean","optional":true},"is_flexible":{"type":"Boolean","optional":true},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"answerShippingQuery":{"ret":"True","params":{"shipping_query_id":{"type":"String","optional":false},"ok":{"type":"Boolean","optional":false},"shipping_options":{"type":"[ShippingOption]","optional":true},"error_message":{"type":"String","optional":true}}},"answerPreCheckoutQuery":{"ret":"True","params":{"pre_checkout_query_id":{"type":"String","optional":false},"ok":{"type":"Boolean","optional":false},"error_message":{"type":"String","optional":true}}},"sendGame":{"ret":"Message","params":{"chat_id":{"type":"Integer","optional":false},"game_short_name":{"type":"String","optional":false},"disable_notification":{"type":"Boolean","optional":true},"reply_to_message_id":{"type":"Integer","optional":true},"reply_markup":{"type":"InlineKeyboardMarkup","optional":true}}},"setGameScore":{"ret":"Message|True","params":{"user_id":{"type":"Integer","optional":false},"score":{"type":"Integer","optional":false},"force":{"type":"Boolean","optional":true},"disable_edit_message":{"type":"Boolean","optional":true},"chat_id":{"type":"Integer","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true}}},"getGameHighScores":{"ret":"[GameHighScore]","params":{"user_id":{"type":"Integer","optional":false},"chat_id":{"type":"Integer","optional":true},"message_id":{"type":"Integer","optional":true},"inline_message_id":{"type":"String","optional":true}}}}
|
data/lib/tgbot/core.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'faraday'
|
3
|
-
|
4
|
-
module Tgbot
|
5
|
-
API_URL = 'https://api.telegram.org'.freeze
|
6
|
-
TYPES = JSON.parse(File.read File.expand_path '../types.json' , __dir__).freeze
|
7
|
-
METHODS = JSON.parse(File.read File.expand_path '../methods.json', __dir__).freeze
|
8
|
-
|
9
|
-
# This bot supports a minimal usage of Telegram Bot APIs.
|
10
|
-
# bot = Bot.new TOKEN, proxy: 'https://127.0.0.1:1080'
|
11
|
-
#
|
12
|
-
# API's methods' input and output are hash.
|
13
|
-
# bot.get_updates offset: 0 #=> { 'ok' => 'true', 'result' => [] }
|
14
|
-
#
|
15
|
-
# It will check type of params before post method, and
|
16
|
-
# if invalid, it will raise an error with detail.
|
17
|
-
class Bot
|
18
|
-
attr_accessor :token
|
19
|
-
|
20
|
-
# Initialize a bot, and call getMe at once to see if given token is valid.
|
21
|
-
# If everything ok, the bot will get its id and name and so on.
|
22
|
-
# token :: String = TOKEN of your bot from botfather
|
23
|
-
# opts :: Hash = Options passed to Faraday.new
|
24
|
-
def initialize(token, **opts)
|
25
|
-
@token = token
|
26
|
-
get_connection(**opts)
|
27
|
-
identify_self
|
28
|
-
end
|
29
|
-
|
30
|
-
# Get bot's info.
|
31
|
-
def identify_self
|
32
|
-
x = get_me
|
33
|
-
if x['ok']
|
34
|
-
@me = x['result']
|
35
|
-
else
|
36
|
-
raise ArgumentError, 'not found myself, check your token.'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Shortcuts for bot's info.
|
41
|
-
def id ; @me && @me['id'] ; end
|
42
|
-
def first_name; @me && @me['first_name']; end
|
43
|
-
def username ; @me && @me['username'] ; end
|
44
|
-
alias name first_name
|
45
|
-
|
46
|
-
# Connect to API_URL. It will take few seconds.
|
47
|
-
# opts :: Hash = Options passed to Faraday.new
|
48
|
-
def get_connection(**opts)
|
49
|
-
@conn = Faraday.new(url: API_URL, **opts) do |faraday|
|
50
|
-
faraday.request :multipart
|
51
|
-
faraday.request :url_encoded
|
52
|
-
faraday.adapter Faraday.default_adapter
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Verify methods and params then call(post) it.
|
57
|
-
# `:get_me' and `:getMe' are both valid.
|
58
|
-
def method_missing(meth, **kwargs)
|
59
|
-
camelized_meth = camelize meth
|
60
|
-
meth_body = METHODS[camelized_meth]
|
61
|
-
super unless meth_body
|
62
|
-
ret, params = meth_body.values_at 'ret', 'params'
|
63
|
-
check_params! (JSON.parse JSON.generate kwargs), params
|
64
|
-
call camelized_meth, kwargs
|
65
|
-
end
|
66
|
-
|
67
|
-
def call meth, kwargs
|
68
|
-
JSON.parse @conn.post("/bot#{@token}/#{meth}", kwargs).body
|
69
|
-
rescue
|
70
|
-
{}
|
71
|
-
end
|
72
|
-
|
73
|
-
# Check args to meet method declaration. Raises error if invalid.
|
74
|
-
def check_params! kwargs, params
|
75
|
-
params.each do |param, info|
|
76
|
-
arg = kwargs[param]
|
77
|
-
type, optional = info.values_at 'type', 'optional'
|
78
|
-
if (arg.nil? && !optional) || (!arg.nil? && !check_type(arg, type))
|
79
|
-
raise ArgumentError, "[#{param}] should be #{type}\n#{error_message_of_type type}"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Get declaration of type in form of:
|
85
|
-
# User := { id :: Integer, first_name :: String }
|
86
|
-
def error_message_of_type type
|
87
|
-
(type.delete('[]').split('|') - ['True', 'Boolean', 'Integer', 'Float', 'String']).map { |type|
|
88
|
-
"#{type} := { #{TYPES[type].map { |field, info|
|
89
|
-
"#{info['optional'] ? '' : '*'}#{field} :: #{info['type']}"
|
90
|
-
}.join(', ')} }"
|
91
|
-
}.join(' ')
|
92
|
-
end
|
93
|
-
|
94
|
-
# Check arg to meet type declaration. Returns false if invalid.
|
95
|
-
def check_type arg, type
|
96
|
-
case type
|
97
|
-
when 'True' then return arg == true
|
98
|
-
when 'Boolean' then return arg == true || arg == false
|
99
|
-
when 'Integer' then return arg.is_a? Integer
|
100
|
-
when 'Float' then return arg.is_a? Float
|
101
|
-
when 'String' then return arg.is_a? String
|
102
|
-
end
|
103
|
-
if type[0] == '['
|
104
|
-
return arg.is_a?(Array) ? arg.all? { |a| check_type a, type[1..-2] } : false
|
105
|
-
elsif type.include? '|'
|
106
|
-
return type.split('|').any? { |t| check_type arg, t }
|
107
|
-
end
|
108
|
-
return false unless TYPES[type]
|
109
|
-
check_params(arg, TYPES[type])
|
110
|
-
end
|
111
|
-
|
112
|
-
# Check args to meet method declaration. Returns false if invalid.
|
113
|
-
def check_params kwargs, params
|
114
|
-
check_params!(kwargs, params)
|
115
|
-
true
|
116
|
-
rescue
|
117
|
-
false
|
118
|
-
end
|
119
|
-
|
120
|
-
def get_types
|
121
|
-
TYPES.keys.map(&:to_sym)
|
122
|
-
end
|
123
|
-
|
124
|
-
def get_methods
|
125
|
-
METHODS.keys.map { |e| underscore e }.map(&:to_sym)
|
126
|
-
end
|
127
|
-
|
128
|
-
# Transform 'TheName' or 'theName' to 'the_name'.
|
129
|
-
def underscore str
|
130
|
-
str.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
131
|
-
.gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
132
|
-
end
|
133
|
-
|
134
|
-
# Transform 'the_name' to 'theName'.
|
135
|
-
def camelize meth
|
136
|
-
ret = String(meth).split('_')
|
137
|
-
ret.drop(1).map(&:capitalize!)
|
138
|
-
ret.join
|
139
|
-
end
|
140
|
-
|
141
|
-
def inspect
|
142
|
-
"#<Bot token=#{@token} id=#{id} first_name=#{first_name} username=#{username}>"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
data/lib/tgbot/dsl.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'tgbot/runner'
|
2
|
-
|
3
|
-
module Tgbot
|
4
|
-
class DSL
|
5
|
-
attr_accessor :runner
|
6
|
-
def initialize(token, **opts)
|
7
|
-
@runner = Runner.new(token, **opts)
|
8
|
-
@procs = { command: {} }
|
9
|
-
end
|
10
|
-
def start(&blk)
|
11
|
-
@procs[:start] = blk
|
12
|
-
end
|
13
|
-
def finish(&blk)
|
14
|
-
@procs[:finish] = blk
|
15
|
-
end
|
16
|
-
def before(&blk)
|
17
|
-
@procs[:before] = blk
|
18
|
-
end
|
19
|
-
def after(&blk)
|
20
|
-
@procs[:after] = blk
|
21
|
-
end
|
22
|
-
def on(*regexes, &blk)
|
23
|
-
regexes.each { |regex| @procs[:command][regex] = blk }
|
24
|
-
end
|
25
|
-
alias get on
|
26
|
-
def alias(ori, *args)
|
27
|
-
args.each { |regex| @procs[:command][regex] = @procs[:command][ori] }
|
28
|
-
end
|
29
|
-
def run
|
30
|
-
yield self if block_given?
|
31
|
-
@procs[:start]&.call
|
32
|
-
begin
|
33
|
-
@runner.mainloop do |update|
|
34
|
-
@procs[:before]&.call update
|
35
|
-
update.done = true
|
36
|
-
@procs[:command].each do |key, blk|
|
37
|
-
x = update.text&.match key
|
38
|
-
update.instance_exec(x, &blk) if x
|
39
|
-
end
|
40
|
-
@procs[:after]&.call update
|
41
|
-
end
|
42
|
-
rescue Interrupt
|
43
|
-
@procs[:finish]&.call
|
44
|
-
rescue => e
|
45
|
-
puts e.backtrace.unshift(e.to_s).join("\n")
|
46
|
-
retry
|
47
|
-
end
|
48
|
-
end
|
49
|
-
def method_missing(meth, *args, &blk)
|
50
|
-
@runner.send(meth, *args, &blk)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
def self.run(token, **opts, &blk)
|
54
|
-
DSL.new(token, **opts).run(&blk)
|
55
|
-
end
|
56
|
-
def self.new(token, **opts)
|
57
|
-
DSL.new(token, **opts)
|
58
|
-
end
|
59
|
-
end
|
data/lib/tgbot/runner.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'ostruct'
|
3
|
-
require 'tgbot/core'
|
4
|
-
require 'tgbot/update'
|
5
|
-
|
6
|
-
module Tgbot
|
7
|
-
class Runner
|
8
|
-
attr_accessor :bot, :offset, :timeout, :updates
|
9
|
-
def initialize(token, **opts)
|
10
|
-
@bot = Bot.new(token, **opts)
|
11
|
-
@offset = 0
|
12
|
-
@timeout = 2
|
13
|
-
@updates = []
|
14
|
-
end
|
15
|
-
def mainloop
|
16
|
-
loop do
|
17
|
-
@updates.each { |u| u.count += 1 }
|
18
|
-
update_updates
|
19
|
-
@updates.each { |update| yield update }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
def update_updates
|
23
|
-
@updates.delete_if(&:done?)
|
24
|
-
x = x
|
25
|
-
t = time { x = @bot.get_updates offset: @offset + 1, limit: 7, timeout: @timeout }
|
26
|
-
case
|
27
|
-
when t > @timeout then @timeout += [@timeout / 2, 1].max
|
28
|
-
when t < @timeout then @timeout -= 1
|
29
|
-
end
|
30
|
-
@timeout = [[0, @timeout].max, 15].min
|
31
|
-
x['result'].each { |e| @updates.push Update.new(@bot, hash_to_ostruct(e)) } if x['ok']
|
32
|
-
@offset = [*@updates.map(&:update_id), @offset].max
|
33
|
-
end
|
34
|
-
def hash_to_ostruct hash
|
35
|
-
JSON.parse JSON.generate(hash), object_class: OpenStruct
|
36
|
-
end
|
37
|
-
def time
|
38
|
-
t = Time.now
|
39
|
-
yield
|
40
|
-
Time.now - t
|
41
|
-
end
|
42
|
-
def method_missing(meth, *args, &blk)
|
43
|
-
@bot.send(meth, *args, &blk)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/lib/tgbot/update.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
require 'mimemagic'
|
3
|
-
module Tgbot
|
4
|
-
class Update
|
5
|
-
attr_accessor :bot, :update, :type, :done, :count
|
6
|
-
def initialize bot, update
|
7
|
-
@bot, @update = bot, update
|
8
|
-
@type = get_type
|
9
|
-
@done = false
|
10
|
-
@count = 0
|
11
|
-
end
|
12
|
-
alias done? done
|
13
|
-
def id
|
14
|
-
@update.update_id
|
15
|
-
end
|
16
|
-
def chat_id
|
17
|
-
@update[@type].chat&.id
|
18
|
-
end
|
19
|
-
def text
|
20
|
-
@update[@type].text
|
21
|
-
end
|
22
|
-
def done!
|
23
|
-
@done = true
|
24
|
-
end
|
25
|
-
def retry n = 1
|
26
|
-
@done = false if @count < n
|
27
|
-
end
|
28
|
-
def send_message(text = nil, **kwargs)
|
29
|
-
return unless chat_id
|
30
|
-
return unless text = text || kwargs.delete(:text)
|
31
|
-
@bot.send_message(chat_id: chat_id, text: text, **kwargs)
|
32
|
-
end
|
33
|
-
def reply_message(text = nil, **kwargs)
|
34
|
-
return unless chat_id
|
35
|
-
return unless text = text || kwargs.delete(:text)
|
36
|
-
@bot.send_message(
|
37
|
-
chat_id: chat_id, text: text,
|
38
|
-
reply_to_message_id: @update[@type].message_id, **kwargs)
|
39
|
-
end
|
40
|
-
alias reply reply_message
|
41
|
-
%i(photo audio document video voice video_note).each do |name|
|
42
|
-
class_eval %{
|
43
|
-
def send_#{name}(#{name} = nil, **kwargs)
|
44
|
-
return unless chat_id
|
45
|
-
return unless #{name} = #{name} || kwargs.delete(:#{name})
|
46
|
-
@bot.send_#{name}(
|
47
|
-
chat_id: chat_id,
|
48
|
-
#{name}: Faraday::UploadIO.new(#{name}, MimeMagic.by_path(#{name}).type),
|
49
|
-
**kwargs)
|
50
|
-
end
|
51
|
-
def reply_#{name}(#{name} = nil, **kwargs)
|
52
|
-
return unless chat_id
|
53
|
-
return unless #{name} = #{name} || kwargs.delete(:#{name})
|
54
|
-
@bot.send_#{name}(
|
55
|
-
chat_id: chat_id,
|
56
|
-
#{name}: Faraday::UploadIO.new(#{name}, MimeMagic.by_path(#{name}).type),
|
57
|
-
reply_to_message_id: @update[@type].message_id, **kwargs)
|
58
|
-
end
|
59
|
-
}
|
60
|
-
end
|
61
|
-
def get_type
|
62
|
-
%i(
|
63
|
-
message
|
64
|
-
edited_message
|
65
|
-
channel_post
|
66
|
-
edited_channel_post
|
67
|
-
inline_query
|
68
|
-
chosen_inline_result
|
69
|
-
callback_query
|
70
|
-
shipping_query
|
71
|
-
pre_checkout_query
|
72
|
-
).find { |f| @update[f] }
|
73
|
-
end
|
74
|
-
def method_missing(field)
|
75
|
-
@update[field]
|
76
|
-
end
|
77
|
-
def inspect
|
78
|
-
"#<Update ##{id} #{@type}=#{@update[@type]}>"
|
79
|
-
end
|
80
|
-
alias to_str inspect
|
81
|
-
alias to_s inspect
|
82
|
-
end
|
83
|
-
end
|