Class: TelegramBotMiddleware
- Inherits:
-
Object
- Object
- TelegramBotMiddleware
- Includes:
- HTTMultiParty
- Defined in:
- lib/telegram_bot_middleware.rb,
lib/telegram_bot_middleware/version.rb
Constant Summary collapse
- VERSION =
"0.3.2"
Instance Method Summary collapse
- #_call(env) ⇒ Object
-
#call(env) ⇒ Object
necessary for thread safe.
-
#get_command(params) ⇒ Object
build command based on message.
-
#initialize(app) {|@config| ... } ⇒ TelegramBotMiddleware
constructor
A new instance of TelegramBotMiddleware.
-
#log(level, message) ⇒ Object
TODO: to fix env.
- #log_debug(message) ⇒ Object
- #log_error(exception) ⇒ Object
- #log_info(message) ⇒ Object
- #process_hash_message(message, params) ⇒ Object
- #process_json_message(message, params) ⇒ Object
- #send_to_telegram(path, query) ⇒ Object
- #start_get_updates_thread ⇒ Object
Constructor Details
#initialize(app) {|@config| ... } ⇒ TelegramBotMiddleware
Returns a new instance of TelegramBotMiddleware.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/telegram_bot_middleware.rb', line 13 def initialize(app, &_block) # save the app var @app = app # local cookies hash @cookies = Hash.new # create the config and populate passing do the block function @config = OpenStruct.new yield(@config) if block_given? # validate required input params raise ArgumentError.new("Config error: host can't be null || empty.") if @config.host.nil? || @config.host.empty? raise ArgumentError.new("Config error: token can't be null || empty.") if @config.token.nil? || @config.token.empty? # initialize persistent connection to telegram self.class.persistent_connection_adapter pool_size: (@config.connection_pool_size || 2), keep_alive: (@config.connection_keep_alive || 30), force_retry: (@config.connection_force_retry || true) # if get_updates is empty set to :polling by default @config.get_updates ||= :polling # setup webhook if @config.webhook.nil? @config.host = "#{@config.host}/" unless @config.host.end_with?('/') @config.webhook = "#{@config.host}#{@config.token}" end # setup telegram messages input case @config.get_updates # setup polling when :polling # clear the webhook in case was set in the past send_to_telegram('setWebhook', {url: ''}) # setup a thread with get_updates function start_get_updates_thread # setup webhook when :webhook send_to_telegram('setWebhook', {url: @config.webhook}) # in this case get_updates is a non valid value else raise ArgumentError.new('Config error: get_updates must be :webhook || :polling.') end end |
Instance Method Details
#_call(env) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/telegram_bot_middleware.rb', line 92 def _call(env) # retrieve the request object request = Rack::Request.new(env) # if the request is a post to bot webhhok if request.post? and request.path == "/#{@config.token}" # in case someone already read it request.body.rewind # build an openstruct based on post params params = OpenStruct.from_json(request.body.read) log_debug("Message from chat: #{params}") # build command based on message command = get_command(params) # transform the POST in GET env['PATH_INFO'] = command env['QUERY_STRING'] = Rack::Utils.build_nested_query(params..to_h_nested) env['REQUEST_METHOD'] = 'GET' env['REQUEST_URI'] = "https://#{request.host}#{command}" # if in cache a cookie for this chat was present add to the header env['HTTP_COOKIE'] = @cookies[params..chat.id] if @cookies.include?(params..chat.id) # call the rack stack status, headers, body = @app.call(env) # try to send to telegram only if no errors if status == 200 || status == '200' # if the call setted a cookie save to local cache @cookies[params..chat.id] = headers['Set-Cookie'] if headers.include?('Set-Cookie') case headers['Content-Type'].split(';').first when 'text/html', 'application/json' if body.is_a? Hash (body.clone, params) body = Array.new(1) { '' } else body.each do |data| begin #TODO: add better json parsing to support symbols too (JSON.parse(data.gsub('=>', ':')), params) rescue send_to_telegram('sendMessage', {chat_id: params..chat.id, text: data}) end end end when /(^image\/)/ send_to_telegram('sendPhoto', {chat_id: params..chat.id, photo: File.new(body)}) when /(^audio\/)/ send_to_telegram('sendAudio', {chat_id: params..chat.id, audio: File.new(body)}) when /(^video\/)/ send_to_telegram('sendVideo', {chat_id: params..chat.id, video: File.new(body)}) end end # return result [status, headers, body] else # normal rack flow - not a bot call @app.call(env) end end |
#call(env) ⇒ Object
necessary for thread safe
88 89 90 |
# File 'lib/telegram_bot_middleware.rb', line 88 def call(env) dup._call(env) end |
#get_command(params) ⇒ Object
build command based on message
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/telegram_bot_middleware.rb', line 163 def get_command(params) unless params.['text'].nil? # build path based on message # - get only message part of post params # - remove empty chars from beginning || end (strip) # - replace first sequence of spaces with / # - encode as uri command = URI.escape(params..text.strip.sub(/\s+/, '/')) # - add first / if not present command = "/#{command}" unless command.start_with?('/') return command else %w(audio document photo sticker video voice contact location new_chat_participant left_chat_participant new_chat_title new_chat_photo delete_chat_photo group_chat_created).each do |type| unless params.[type].nil? return "/#{type}" end end end end |
#log(level, message) ⇒ Object
TODO: to fix env
239 240 241 242 243 244 245 246 |
# File 'lib/telegram_bot_middleware.rb', line 239 def log(level, ) #return if @env.nil? #if @env['rack.logger'] # @env['rack.logger'].send(level, message) #else # @env['rack.errors'].write(message) #end end |
#log_debug(message) ⇒ Object
234 235 236 |
# File 'lib/telegram_bot_middleware.rb', line 234 def log_debug() log(:debug, ) end |
#log_error(exception) ⇒ Object
225 226 227 228 |
# File 'lib/telegram_bot_middleware.rb', line 225 def log_error(exception) = "Error: #{exception.}\n#{exception.backtrace.join("\n")}\n" log(:error, ) end |
#log_info(message) ⇒ Object
230 231 232 |
# File 'lib/telegram_bot_middleware.rb', line 230 def log_info() log(:info, ) end |
#process_hash_message(message, params) ⇒ Object
183 184 185 186 187 188 189 190 191 |
# File 'lib/telegram_bot_middleware.rb', line 183 def (, params) if (.include?(:multiple) && [:multiple].is_a?(Array)) [:multiple].each { |item| (item, params) } elsif (.include?('multiple') && ['multiple'].is_a?(Array)) ['multiple'].each { |item| (item, params) } else (, params) end end |
#process_json_message(message, params) ⇒ Object
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/telegram_bot_middleware.rb', line 193 def (, params) [:chat_id] = params..chat.id unless .include?(:chat_id) || .include?('chat_id') ['reply_markup', :reply_markup].each do |item| [item] = [item].to_json if .include?(item) end ['photo', :photo, 'audio', :audio, 'video', :video].each do |item| [item] = File.new([item]) if .include?(item) end if .include?(:text) || .include?('text') send_to_telegram('sendMessage', ) elsif (.include?(:latitude) and .include?(:longitude)) || (.include?('latitude') and .include?('longitude')) send_to_telegram('sendLocation', ) elsif .include?(:photo) || .include?('photo') send_to_telegram('sendPhoto', ) elsif .include?(:audio) || .include?('audio') send_to_telegram('sendAudio', ) elsif .include?(:video) || .include?('video') send_to_telegram('sendVideo', ) else # TODO: invalid query end end |
#send_to_telegram(path, query) ⇒ Object
219 220 221 222 223 |
# File 'lib/telegram_bot_middleware.rb', line 219 def send_to_telegram(path, query) log_debug("Sending to chat: #{path} - #{query}") self.class.post("/bot#{@config.token}/#{path}", query: query) # TODO check response error and return response end |
#start_get_updates_thread ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/telegram_bot_middleware.rb', line 63 def start_get_updates_thread # start a new thread Thread.new do # the initial offset is always 0 @offset = 0 # wait 5 seconds to don't risk to post message too early when the app is not still up sleep 5 # loop forever loop do # call the getUpdates telegram function response = send_to_telegram('getUpdates', {offset: @offset}) # enumerate the results response.to_hash['result'].each do |data| # create an update message from the post data update = OpenStruct.new(data) # store the last offset +1 but ensure that is not lower than the already stored @offset = (update.update_id + 1) if update.update_id + 1 > @offset # simulate a post to itself HTTP.post @config.webhook, json: update.to_h_nested end end end end |