Class: MTProto::Client
- Inherits:
-
Object
- Object
- MTProto::Client
- Extended by:
- DelegateMethods
- Defined in:
- lib/mtproto/client.rb,
lib/mtproto/client/api.rb,
lib/mtproto/client/rpc.rb,
lib/mtproto/client/api/sign_in.rb,
lib/mtproto/client/rpc/response.rb,
lib/mtproto/client/api/get_users.rb,
lib/mtproto/client/api/send_code.rb,
lib/mtproto/client/api/get_dialogs.rb,
lib/mtproto/client/api/get_history.rb,
lib/mtproto/client/api/get_contacts.rb,
lib/mtproto/client/api/send_message.rb,
lib/mtproto/client/api/check_password.rb,
lib/mtproto/client/api/get_updates_state.rb,
lib/mtproto/client/api/export_login_token.rb,
lib/mtproto/client/api/import_login_token.rb,
lib/mtproto/client/api/get_updates_difference.rb
Defined Under Namespace
Constant Summary collapse
- API_LAYER =
214- ACK_INTERVAL =
Keepalive cadence: flush pending acks every ACK_INTERVAL seconds, send a ping every PING_INTERVAL seconds.
5- PING_INTERVAL =
30
Instance Attribute Summary collapse
-
#access_hash ⇒ Object
readonly
Returns the value of attribute access_hash.
-
#api_hash ⇒ Object
Returns the value of attribute api_hash.
-
#api_id ⇒ Object
Returns the value of attribute api_id.
-
#app_version ⇒ Object
Returns the value of attribute app_version.
-
#auth_key ⇒ Object
readonly
Returns the value of attribute auth_key.
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
-
#dc_number ⇒ Object
readonly
Returns the value of attribute dc_number.
-
#device_model ⇒ Object
Returns the value of attribute device_model.
-
#lang_code ⇒ Object
Returns the value of attribute lang_code.
-
#lang_pack ⇒ Object
Returns the value of attribute lang_pack.
-
#server_key ⇒ Object
readonly
Returns the value of attribute server_key.
-
#server_salt ⇒ Object
readonly
Returns the value of attribute server_salt.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#system_lang_code ⇒ Object
Returns the value of attribute system_lang_code.
-
#system_version ⇒ Object
Returns the value of attribute system_version.
-
#time_offset ⇒ Object
readonly
Returns the value of attribute time_offset.
-
#timeout ⇒ Object
readonly
Returns the value of attribute timeout.
-
#user_id ⇒ Object
readonly
Returns the value of attribute user_id.
Instance Method Summary collapse
- #api ⇒ Object
- #auth_key? ⇒ Boolean
- #disconnect! ⇒ Object
- #exchange_keys! ⇒ Object
- #init_connection! ⇒ Object
-
#initialize(host:, api_id:, api_hash:, port: 443, public_key: nil, dc_number: nil, test_mode: false, timeout: 10) ⇒ Client
constructor
A new instance of Client.
- #load_auth_data(auth_data) ⇒ Object
- #mainloop_running? ⇒ Boolean
- #on_update(&block) ⇒ Object
- #rpc ⇒ Object
- #run_mainloop ⇒ Object
- #save_auth_data ⇒ Object
-
#start_receiving! ⇒ Object
Start the receiver task without taking over the current Async reactor.
- #update_server_salt(new_salt) ⇒ Object
- #update_user(user_id:, access_hash: nil) ⇒ Object
Methods included from DelegateMethods
Constructor Details
#initialize(host:, api_id:, api_hash:, port: 443, public_key: nil, dc_number: nil, test_mode: false, timeout: 10) ⇒ Client
Returns a new instance of Client.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/mtproto/client.rb', line 40 def initialize( host:, api_id:, api_hash:, port: 443, public_key: nil, dc_number: nil, test_mode: false, timeout: 10 ) raise ArgumentError, 'host is required' if host.nil? || host.empty? raise ArgumentError, 'dc_number must be positive. Use test_mode: true for test DCs' if dc_number && dc_number < 0 @api_id = api_id @api_hash = api_hash transport = Transport::TCPConnection.new(host, port) @connection = Transport::Connection.new(transport) @public_key = public_key @dc_number = dc_number @test_mode = test_mode @timeout = timeout @server_key = nil @auth_key = nil @server_salt = nil @time_offset = 0 @session = nil @connection_initialized = false @user_id = nil @access_hash = nil @device_model = 'Ruby MTProto' @system_version = RUBY_DESCRIPTION @app_version = '0.1.0' @system_lang_code = 'en' @lang_pack = '' @lang_code = 'en' @receiver_task = nil @keepalive_task = nil @ack_ids = [] @running = false @on_update_callbacks = [] end |
Instance Attribute Details
#access_hash ⇒ Object (readonly)
Returns the value of attribute access_hash.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def access_hash @access_hash end |
#api_hash ⇒ Object
Returns the value of attribute api_hash.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def api_hash @api_hash end |
#api_id ⇒ Object
Returns the value of attribute api_id.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def api_id @api_id end |
#app_version ⇒ Object
Returns the value of attribute app_version.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def app_version @app_version end |
#auth_key ⇒ Object (readonly)
Returns the value of attribute auth_key.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def auth_key @auth_key end |
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def connection @connection end |
#dc_number ⇒ Object (readonly)
Returns the value of attribute dc_number.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def dc_number @dc_number end |
#device_model ⇒ Object
Returns the value of attribute device_model.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def device_model @device_model end |
#lang_code ⇒ Object
Returns the value of attribute lang_code.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def lang_code @lang_code end |
#lang_pack ⇒ Object
Returns the value of attribute lang_pack.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def lang_pack @lang_pack end |
#server_key ⇒ Object (readonly)
Returns the value of attribute server_key.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def server_key @server_key end |
#server_salt ⇒ Object (readonly)
Returns the value of attribute server_salt.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def server_salt @server_salt end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def session @session end |
#system_lang_code ⇒ Object
Returns the value of attribute system_lang_code.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def system_lang_code @system_lang_code end |
#system_version ⇒ Object
Returns the value of attribute system_version.
27 28 29 |
# File 'lib/mtproto/client.rb', line 27 def system_version @system_version end |
#time_offset ⇒ Object (readonly)
Returns the value of attribute time_offset.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def time_offset @time_offset end |
#timeout ⇒ Object (readonly)
Returns the value of attribute timeout.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def timeout @timeout end |
#user_id ⇒ Object (readonly)
Returns the value of attribute user_id.
25 26 27 |
# File 'lib/mtproto/client.rb', line 25 def user_id @user_id end |
Instance Method Details
#api ⇒ Object
179 180 181 |
# File 'lib/mtproto/client.rb', line 179 def api @api ||= API.new(self) end |
#auth_key? ⇒ Boolean
32 33 34 |
# File 'lib/mtproto/client.rb', line 32 def auth_key? !@auth_key.nil? end |
#disconnect! ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/mtproto/client.rb', line 142 def disconnect! @running = false @keepalive_task&.stop @keepalive_task = nil @receiver_task&.stop @receiver_task = nil @ack_ids = [] rpc.signal_all_error(Transport::ConnectionError.new('Client shutting down')) @connection.disconnect! if @connection&.connected? end |
#exchange_keys! ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/mtproto/client.rb', line 155 def exchange_keys! raise ArgumentError, 'public_key is required for auth key generation' if @public_key.nil? || @public_key.empty? generator = AuthKeyGenerator.new( @connection, @public_key, @dc_number, test_mode: @test_mode, timeout: @timeout ) result = generator.generate @auth_key = generator.auth_key @server_salt = generator.server_salt @time_offset = generator.time_offset @session = Session.new result end |
#init_connection! ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/mtproto/client.rb', line 183 def init_connection! return if @connection_initialized query = TL::InvokeWithLayer.new( layer: API_LAYER, query: TL::InitConnection.new( api_id: api_id, device_model: device_model, system_version: system_version, app_version: app_version, system_lang_code: system_lang_code, lang_pack: lang_pack, lang_code: lang_code, query: TL::GetConfig.new ) ) response = rpc.call(query, TL::HelpConfig) response.wait!(timeout) @connection_initialized = true response.body end |
#load_auth_data(auth_data) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/mtproto/client.rb', line 221 def load_auth_data(auth_data) raise ArgumentError, 'auth_data must be a Hash' unless auth_data.is_a?(Hash) raise ArgumentError, 'auth_key is required' unless auth_data[:auth_key] raise ArgumentError, 'server_salt is required' unless auth_data[:server_salt] @auth_key = Base64.strict_decode64(auth_data[:auth_key]) @server_salt = auth_data[:server_salt] @time_offset = auth_data[:time_offset] || 0 @user_id = auth_data[:user_id] @access_hash = auth_data[:access_hash] @session = Session.new true end |
#mainloop_running? ⇒ Boolean
36 37 38 |
# File 'lib/mtproto/client.rb', line 36 def mainloop_running? @running end |
#on_update(&block) ⇒ Object
91 92 93 |
# File 'lib/mtproto/client.rb', line 91 def on_update(&block) @on_update_callbacks << block end |
#rpc ⇒ Object
175 176 177 |
# File 'lib/mtproto/client.rb', line 175 def rpc @rpc ||= RPC.new(self) end |
#run_mainloop ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/mtproto/client.rb', line 95 def run_mainloop raise 'Auth key not set' unless auth_key? raise 'Mainloop already running' if @running raise ArgumentError, 'Block is required' unless block_given? begin Async do start_receiving! yield self ensure disconnect! end rescue Interrupt # Ctrl+C end end |
#save_auth_data ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/mtproto/client.rb', line 208 def save_auth_data raise 'Cannot save auth_data: auth_key not set' unless @auth_key { auth_key: Base64.strict_encode64(@auth_key), server_salt: @server_salt, user_id: @user_id, access_hash: @access_hash, dc_number: @dc_number, time_offset: @time_offset } end |
#start_receiving! ⇒ Object
Start the receiver task without taking over the current Async reactor. Use when orchestrating multiple clients in a shared Async block — call from inside an Async do … end. The caller is responsible for disconnect! at the end.
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 |
# File 'lib/mtproto/client.rb', line 116 def start_receiving! raise 'Auth key not set' unless auth_key? raise 'Mainloop already running' if @running @running = true @ack_ids = [] @receiver_task = Async do @connection.receive do |packet, error| if error warn "[MTProto] Packet read error: #{error.}" next end decrypted = EncryptedMessage.decrypt( auth_key: @auth_key, encrypted_message_data: packet.data.pack('C*'), sender: :server ) collect_ack(decrypted[:msg_id], decrypted[:seq_no], decrypted[:body]) (decrypted[:body]) end end @keepalive_task = Async { keepalive_loop } end |
#update_server_salt(new_salt) ⇒ Object
242 243 244 |
# File 'lib/mtproto/client.rb', line 242 def update_server_salt(new_salt) @server_salt = new_salt end |
#update_user(user_id:, access_hash: nil) ⇒ Object
237 238 239 240 |
# File 'lib/mtproto/client.rb', line 237 def update_user(user_id:, access_hash: nil) @user_id = user_id @access_hash = access_hash end |