Class: MaxBotApi::Client
- Inherits:
-
Object
- Object
- MaxBotApi::Client
- Defined in:
- lib/max_bot_api/client.rb
Overview
Main API client. Holds auth config and provides resource accessors.
Constant Summary collapse
- DEFAULT_BASE_URL =
Default API base URL.
'https://platform-api.max.ru/'- DEFAULT_VERSION =
Default API version appended as query param.
'1.2.5'- SECRET_HEADER =
Webhook secret header name.
'X-Max-Bot-Api-Secret'- DEFAULT_PAUSE =
Default pause between update polling loops.
1- DEFAULT_UPDATES_LIMIT =
Default limit for updates requests.
50- MAX_RETRIES =
Max retry attempts for update polling.
3
Instance Attribute Summary collapse
- #base_url ⇒ String readonly
- #token ⇒ String readonly
- #version ⇒ String readonly
Instance Method Summary collapse
- #bots ⇒ Object
- #chats ⇒ Object
-
#debugs(chat_id: 0) ⇒ Object
Build a debug sender bound to a chat.
-
#each_update(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false, &block) ⇒ Object
Iterates over updates, yielding each update hash.
-
#get_updates(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) ⇒ Object
Fetch updates from the API.
-
#get_updates_with_retry(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) ⇒ Object
Fetch updates with retry/backoff.
- #http_client ⇒ Object
-
#initialize(token:, base_url: DEFAULT_BASE_URL, version: DEFAULT_VERSION, faraday: nil, adapter: Faraday.default_adapter) ⇒ Client
constructor
A new instance of Client.
- #messages ⇒ Object
-
#parse_webhook(body, debug: false) ⇒ Object
Parses a single webhook payload into an update hash.
-
#request(method, path, query: nil, body: nil, headers: {}, reset: false) ⇒ Object
Perform an HTTP request.
- #subscriptions ⇒ Object
-
#updates_enum(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false) ⇒ Object
Returns an enumerator that yields updates indefinitely.
- #uploads ⇒ Object
-
#webhook_secret_valid?(headers:, secret:) ⇒ Boolean
Validates the webhook secret header against the expected secret.
Constructor Details
#initialize(token:, base_url: DEFAULT_BASE_URL, version: DEFAULT_VERSION, faraday: nil, adapter: Faraday.default_adapter) ⇒ Client
Returns a new instance of Client.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/max_bot_api/client.rb', line 31 def initialize(token:, base_url: DEFAULT_BASE_URL, version: DEFAULT_VERSION, faraday: nil, adapter: Faraday.default_adapter) raise EmptyTokenError, 'bot token is empty' if token.to_s.empty? @token = token @base_url = normalize_base_url(base_url) @version = version.to_s.empty? ? DEFAULT_VERSION : version.to_s @conn = faraday || Faraday.new(url: @base_url) do |f| f.request :multipart f.request :url_encoded f.adapter adapter end end |
Instance Attribute Details
#base_url ⇒ String (readonly)
24 25 26 |
# File 'lib/max_bot_api/client.rb', line 24 def base_url @base_url end |
#token ⇒ String (readonly)
24 25 26 |
# File 'lib/max_bot_api/client.rb', line 24 def token @token end |
#version ⇒ String (readonly)
24 25 26 |
# File 'lib/max_bot_api/client.rb', line 24 def version @version end |
Instance Method Details
#bots ⇒ Object
46 47 48 |
# File 'lib/max_bot_api/client.rb', line 46 def bots Resources::Bots.new(self) end |
#chats ⇒ Object
50 51 52 |
# File 'lib/max_bot_api/client.rb', line 50 def chats Resources::Chats.new(self) end |
#debugs(chat_id: 0) ⇒ Object
Build a debug sender bound to a chat.
68 69 70 |
# File 'lib/max_bot_api/client.rb', line 68 def debugs(chat_id: 0) Resources::Debugs.new(self, chat_id: chat_id) end |
#each_update(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false, &block) ⇒ Object
Iterates over updates, yielding each update hash.
125 126 127 128 129 |
# File 'lib/max_bot_api/client.rb', line 125 def each_update(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false, &block) return updates_enum(pause: pause, limit: limit, timeout: timeout, types: types, debug: debug) unless block updates_enum(pause: pause, limit: limit, timeout: timeout, types: types, debug: debug).each(&block) end |
#get_updates(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) ⇒ Object
Fetch updates from the API.
78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/max_bot_api/client.rb', line 78 def get_updates(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) query = {} query['limit'] = limit if limit && limit.to_i > 0 query['timeout'] = timeout.to_i if timeout && timeout.to_i > 0 query['marker'] = marker if marker && marker.to_i > 0 Array(types).each { |t| (query['types'] ||= []) << t } result = request(:get, 'updates', query: query) Updates::Parser.parse_update_list(result, debug: debug) rescue TimeoutError { updates: [], marker: nil } end |
#get_updates_with_retry(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) ⇒ Object
Fetch updates with retry/backoff.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/max_bot_api/client.rb', line 92 def get_updates_with_retry(limit: nil, timeout: nil, marker: nil, types: nil, debug: false) last_error = nil MAX_RETRIES.times do |attempt| return get_updates(limit: limit, timeout: timeout, marker: marker, types: types, debug: debug) rescue Error => e last_error = e raise e if attempt == MAX_RETRIES - 1 sleep(2**attempt) end raise last_error end |
#http_client ⇒ Object
184 185 186 |
# File 'lib/max_bot_api/client.rb', line 184 def http_client @conn end |
#messages ⇒ Object
54 55 56 |
# File 'lib/max_bot_api/client.rb', line 54 def Resources::Messages.new(self) end |
#parse_webhook(body, debug: false) ⇒ Object
Parses a single webhook payload into an update hash.
132 133 134 |
# File 'lib/max_bot_api/client.rb', line 132 def parse_webhook(body, debug: false) Updates::Parser.parse_update(body.to_s, debug: debug) end |
#request(method, path, query: nil, body: nil, headers: {}, reset: false) ⇒ Object
Perform an HTTP request.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/max_bot_api/client.rb', line 150 def request(method, path, query: nil, body: nil, headers: {}, reset: false) query = (query || {}).dup query['v'] = version response = @conn.public_send(method) do |req| req.url(path.to_s.sub(%r{\A/}, '')) req.params.update(query) unless query.empty? req.headers['User-Agent'] = "max-bot-api-client-ruby/#{VERSION}" req.headers['Authorization'] = token unless reset headers.each { |k, v| req.headers[k] = v } if body if body.is_a?(Hash) || body.is_a?(Array) if multipart_body?(body) req.body = body else req.headers['Content-Type'] ||= 'application/json' req.body = JSON.generate(body) end else req.body = body end end end handle_response(response) rescue Faraday::TimeoutError => e raise TimeoutError.new(op: "#{method.to_s.upcase} #{path}", reason: e.) rescue Faraday::ConnectionFailed, Faraday::SSLError, Faraday::Error => e raise NetworkError.new(op: "#{method.to_s.upcase} #{path}", original_error: e) rescue JSON::GeneratorError => e raise SerializationError.new(op: 'marshal', type: 'request body', original_error: e) end |
#subscriptions ⇒ Object
58 59 60 |
# File 'lib/max_bot_api/client.rb', line 58 def subscriptions Resources::Subscriptions.new(self) end |
#updates_enum(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false) ⇒ Object
Returns an enumerator that yields updates indefinitely.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/max_bot_api/client.rb', line 108 def updates_enum(pause: DEFAULT_PAUSE, limit: DEFAULT_UPDATES_LIMIT, timeout: nil, types: nil, debug: false) Enumerator.new do |yielder| marker = nil loop do updates_list = get_updates_with_retry(limit: limit, timeout: timeout, marker: marker, types: types, debug: debug) updates = Array(updates_list[:updates]) updates.each { |update| yielder << update } marker = updates_list[:marker] if updates_list[:marker] sleep(pause) end end end |
#uploads ⇒ Object
62 63 64 |
# File 'lib/max_bot_api/client.rb', line 62 def uploads Resources::Uploads.new(self) end |
#webhook_secret_valid?(headers:, secret:) ⇒ Boolean
Validates the webhook secret header against the expected secret.
139 140 141 |
# File 'lib/max_bot_api/client.rb', line 139 def webhook_secret_valid?(headers:, secret:) header_value(headers, SECRET_HEADER) == secret.to_s end |