mtproto 0.0.6 → 0.0.8
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/.env.example +4 -0
- data/lib/mtproto/async/middleware/base.rb +17 -0
- data/lib/mtproto/async/middleware/flood_wait.rb +42 -0
- data/lib/mtproto/async/request.rb +18 -0
- data/lib/mtproto/async/request_queue.rb +63 -0
- data/lib/mtproto/async_client.rb +201 -0
- data/lib/mtproto/auth_key_generator.rb +22 -12
- data/lib/mtproto/client/rpc.rb +165 -0
- data/lib/mtproto/client.rb +65 -176
- data/lib/mtproto/crypto/aes_ige.rb +1 -1
- data/lib/mtproto/crypto/factorization.rb +1 -1
- data/lib/mtproto/message_id.rb +13 -0
- data/lib/mtproto/rpc/get_config.rb +34 -0
- data/lib/mtproto/rpc/get_contacts.rb +29 -0
- data/lib/mtproto/rpc/get_updates_difference.rb +51 -0
- data/lib/mtproto/rpc/get_updates_state.rb +29 -0
- data/lib/mtproto/rpc/get_users.rb +29 -0
- data/lib/mtproto/rpc/ping.rb +33 -0
- data/lib/mtproto/rpc/send_code.rb +41 -0
- data/lib/mtproto/rpc/send_message.rb +47 -0
- data/lib/mtproto/rpc/sign_in.rb +48 -0
- data/lib/mtproto/type/auth_key/dh_gen_response.rb +37 -0
- data/lib/mtproto/type/auth_key/req_dh_params.rb +31 -0
- data/lib/mtproto/type/auth_key/req_pq_multi.rb +18 -0
- data/lib/mtproto/type/auth_key/res_pq.rb +62 -0
- data/lib/mtproto/type/auth_key/server_dh_params.rb +43 -0
- data/lib/mtproto/type/auth_key/set_client_dh_params.rb +25 -0
- data/lib/mtproto/{tl → type}/bad_msg_notification.rb +1 -1
- data/lib/mtproto/{tl → type}/client_dh_inner_data.rb +1 -1
- data/lib/mtproto/{tl → type}/code_settings.rb +1 -1
- data/lib/mtproto/{tl → type}/config.rb +1 -1
- data/lib/mtproto/{tl → type}/gzip_packed.rb +1 -1
- data/lib/mtproto/type/message.rb +38 -0
- data/lib/mtproto/{tl → type}/msg_container.rb +1 -1
- data/lib/mtproto/{tl → type}/new_session_created.rb +1 -1
- data/lib/mtproto/{tl/p_q_inner_data.rb → type/pq_inner_data.rb} +1 -1
- data/lib/mtproto/type/rpc/auth/authorization.rb +107 -0
- data/lib/mtproto/type/rpc/auth/send_code.rb +28 -0
- data/lib/mtproto/type/rpc/auth/sent_code.rb +36 -0
- data/lib/mtproto/type/rpc/auth/sign_in.rb +32 -0
- data/lib/mtproto/type/rpc/contacts/contacts.rb +155 -0
- data/lib/mtproto/type/rpc/contacts/get_contacts.rb +18 -0
- data/lib/mtproto/type/rpc/help/config.rb +35 -0
- data/lib/mtproto/type/rpc/help/get_config.rb +17 -0
- data/lib/mtproto/type/rpc/init_connection.rb +28 -0
- data/lib/mtproto/type/rpc/invoke_with_layer.rb +19 -0
- data/lib/mtproto/type/rpc/messages/send_message.rb +43 -0
- data/lib/mtproto/type/rpc/messages/updates.rb +87 -0
- data/lib/mtproto/type/rpc/ping.rb +18 -0
- data/lib/mtproto/type/rpc/pong.rb +46 -0
- data/lib/mtproto/type/rpc/updates/difference.rb +332 -0
- data/lib/mtproto/type/rpc/updates/get_difference.rb +42 -0
- data/lib/mtproto/type/rpc/updates/get_state.rb +17 -0
- data/lib/mtproto/type/rpc/updates/state.rb +59 -0
- data/lib/mtproto/type/rpc/users/get_users.rb +25 -0
- data/lib/mtproto/type/rpc/users/users.rb +99 -0
- data/lib/mtproto/{tl → type}/rpc_error.rb +1 -1
- data/lib/mtproto/{tl → type}/sent_code.rb +1 -1
- data/lib/mtproto/{tl → type}/serializer.rb +1 -1
- data/lib/mtproto/{tl → type}/server_dh_inner_data.rb +1 -1
- data/lib/mtproto/updates_poller.rb +111 -0
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +28 -14
- metadata +86 -18
- data/ext/aes_ige/Makefile +0 -273
- data/ext/factorization/Makefile +0 -273
- data/lib/mtproto/connection.rb +0 -103
- data/lib/mtproto/tl/message.rb +0 -252
data/lib/mtproto/client.rb
CHANGED
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
require 'securerandom'
|
|
4
4
|
require 'digest'
|
|
5
|
+
require 'base64'
|
|
5
6
|
require_relative 'transport/tcp_connection'
|
|
6
7
|
require_relative 'transport/abridged_packet_codec'
|
|
7
|
-
require_relative '
|
|
8
|
+
require_relative 'type/message'
|
|
9
|
+
require_relative 'client/rpc'
|
|
10
|
+
require_relative 'type/rpc/help/get_config'
|
|
11
|
+
require_relative 'type/rpc/help/config'
|
|
12
|
+
require_relative 'type/rpc/invoke_with_layer'
|
|
13
|
+
require_relative 'type/rpc/init_connection'
|
|
8
14
|
|
|
9
15
|
module MTProto
|
|
10
16
|
class Client
|
|
11
|
-
attr_reader :connection, :server_key, :auth_key, :server_salt, :time_offset, :session, :timeout
|
|
12
|
-
attr_accessor :api_id, :api_hash, :device_model, :system_version, :app_version, :system_lang_code, :lang_pack, :lang_code
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
attr_reader :connection, :server_key, :auth_key, :server_salt, :time_offset, :session, :timeout, :user_id, :access_hash, :dc_number
|
|
19
|
+
attr_accessor :api_id, :api_hash, :device_model, :system_version, :app_version, :system_lang_code, :lang_pack, :lang_code
|
|
15
20
|
|
|
16
21
|
def initialize(api_id: nil, api_hash: nil, host:, port: 443, public_key: nil, dc_number: nil, test_mode: false, timeout: 10)
|
|
17
22
|
raise ArgumentError, "host is required" if host.nil? || host.empty?
|
|
@@ -29,6 +34,8 @@ module MTProto
|
|
|
29
34
|
@time_offset = 0
|
|
30
35
|
@session = nil
|
|
31
36
|
@connection_initialized = false
|
|
37
|
+
@user_id = nil
|
|
38
|
+
@access_hash = nil
|
|
32
39
|
|
|
33
40
|
# Client configuration defaults
|
|
34
41
|
@api_id = api_id || 0
|
|
@@ -45,29 +52,15 @@ module MTProto
|
|
|
45
52
|
@connection.connect!
|
|
46
53
|
end
|
|
47
54
|
|
|
48
|
-
def
|
|
49
|
-
@connection
|
|
55
|
+
def connected?
|
|
56
|
+
@connection&.connected?
|
|
50
57
|
end
|
|
51
58
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
message = TL::Message.req_pq_multi(nonce)
|
|
56
|
-
payload = message.serialize
|
|
57
|
-
|
|
58
|
-
@connection.send(payload)
|
|
59
|
-
|
|
60
|
-
response_data = @connection.recv(timeout: @timeout)
|
|
61
|
-
response_message = TL::Message.deserialize(response_data)
|
|
62
|
-
|
|
63
|
-
res_pq = response_message.parse_res_pq
|
|
64
|
-
|
|
65
|
-
raise 'Nonce mismatch!' unless res_pq[:nonce] == nonce
|
|
66
|
-
|
|
67
|
-
res_pq
|
|
59
|
+
def disconnect!
|
|
60
|
+
@connection.close if @connection
|
|
68
61
|
end
|
|
69
62
|
|
|
70
|
-
def
|
|
63
|
+
def exchange_keys!
|
|
71
64
|
raise ArgumentError, "public_key is required for auth key generation" if @public_key.nil? || @public_key.empty?
|
|
72
65
|
|
|
73
66
|
generator = AuthKeyGenerator.new(@connection, @public_key, @dc_number, test_mode: @test_mode, timeout: @timeout)
|
|
@@ -81,175 +74,71 @@ module MTProto
|
|
|
81
74
|
result
|
|
82
75
|
end
|
|
83
76
|
|
|
84
|
-
def
|
|
85
|
-
|
|
86
|
-
msg_id = (time * (2**32)).to_i
|
|
87
|
-
(msg_id / 4) * 4
|
|
77
|
+
def rpc
|
|
78
|
+
@rpc ||= RPC.new(self)
|
|
88
79
|
end
|
|
89
80
|
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
msg_id = generate_msg_id
|
|
95
|
-
seq_no = @session.next_seq_no(content_related: content_related)
|
|
96
|
-
|
|
97
|
-
encrypted_msg = EncryptedMessage.encrypt(
|
|
98
|
-
auth_key: @auth_key,
|
|
99
|
-
server_salt: @server_salt,
|
|
100
|
-
session_id: @session.session_id,
|
|
101
|
-
msg_id: msg_id,
|
|
102
|
-
seq_no: seq_no,
|
|
103
|
-
body: body
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
@connection.send(encrypted_msg.serialize)
|
|
107
|
-
|
|
108
|
-
response_data = @connection.recv(timeout: @timeout)
|
|
109
|
-
|
|
110
|
-
decrypted = EncryptedMessage.decrypt(
|
|
111
|
-
auth_key: @auth_key,
|
|
112
|
-
encrypted_message_data: response_data,
|
|
113
|
-
sender: :server
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
response_body = decrypted[:body]
|
|
117
|
-
|
|
118
|
-
constructor = response_body[0, 4].unpack1('L<')
|
|
119
|
-
|
|
120
|
-
if constructor == TL::NewSessionCreated::CONSTRUCTOR
|
|
121
|
-
session_info = TL::NewSessionCreated.deserialize(response_body)
|
|
122
|
-
@server_salt = session_info.server_salt
|
|
81
|
+
def call(body, content_related: true)
|
|
82
|
+
rpc.call(body, content_related: content_related)
|
|
83
|
+
end
|
|
123
84
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
85
|
+
def init_connection!
|
|
86
|
+
return if @connection_initialized
|
|
87
|
+
|
|
88
|
+
query = Type::RPC::InvokeWithLayer.build(
|
|
89
|
+
layer: 214,
|
|
90
|
+
query: Type::RPC::InitConnection.build(
|
|
91
|
+
api_id: api_id,
|
|
92
|
+
device_model: device_model,
|
|
93
|
+
system_version: system_version,
|
|
94
|
+
app_version: app_version,
|
|
95
|
+
system_lang_code: system_lang_code,
|
|
96
|
+
lang_pack: lang_pack,
|
|
97
|
+
lang_code: lang_code,
|
|
98
|
+
query: Type::RPC::Help::GetConfig.build
|
|
129
99
|
)
|
|
130
|
-
|
|
131
|
-
constructor = response_body[0, 4].unpack1('L<')
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
if constructor == TL::Message::CONSTRUCTOR_MSG_CONTAINER
|
|
135
|
-
container = TL::MsgContainer.deserialize(response_body)
|
|
136
|
-
|
|
137
|
-
rpc_result = container.messages.find do |msg|
|
|
138
|
-
msg[:body][0, 4].unpack1('L<') == 0xf35c6d01
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
return rpc_result[:body][12..] if rpc_result
|
|
142
|
-
|
|
143
|
-
new_session = container.messages.find { |msg| msg[:body][0, 4].unpack1('L<') == TL::NewSessionCreated::CONSTRUCTOR }
|
|
144
|
-
if new_session
|
|
145
|
-
session_info = TL::NewSessionCreated.deserialize(new_session[:body])
|
|
146
|
-
@server_salt = session_info.server_salt
|
|
147
|
-
|
|
148
|
-
other_messages = container.messages.reject do |msg|
|
|
149
|
-
constructor = msg[:body][0, 4].unpack1('L<')
|
|
150
|
-
constructor == TL::NewSessionCreated::CONSTRUCTOR || constructor == CONSTRUCTOR_MSGS_ACK
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
if !other_messages.empty?
|
|
154
|
-
return other_messages.first[:body]
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
response_data = @connection.recv(timeout: @timeout)
|
|
158
|
-
decrypted = EncryptedMessage.decrypt(
|
|
159
|
-
auth_key: @auth_key,
|
|
160
|
-
encrypted_message_data: response_data,
|
|
161
|
-
sender: :server
|
|
162
|
-
)
|
|
163
|
-
response_body = decrypted[:body]
|
|
164
|
-
constructor = response_body[0, 4].unpack1('L<')
|
|
165
|
-
|
|
166
|
-
return response_body[12..] if constructor == 0xf35c6d01
|
|
100
|
+
)
|
|
167
101
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
rpc_result = container.messages.find { |msg| msg[:body][0, 4].unpack1('L<') == 0xf35c6d01 }
|
|
171
|
-
return rpc_result[:body][12..] if rpc_result
|
|
172
|
-
end
|
|
102
|
+
response = rpc.call_sync(query)
|
|
103
|
+
config = Type::RPC::Help::Config.parse(response)
|
|
173
104
|
|
|
174
|
-
|
|
175
|
-
end
|
|
105
|
+
@connection_initialized = true
|
|
176
106
|
|
|
177
|
-
|
|
178
|
-
|
|
107
|
+
config
|
|
108
|
+
end
|
|
179
109
|
|
|
180
|
-
|
|
110
|
+
def save_auth_data
|
|
111
|
+
raise 'Cannot save auth_data: auth_key not set' unless @auth_key
|
|
181
112
|
|
|
182
|
-
|
|
113
|
+
{
|
|
114
|
+
auth_key: Base64.strict_encode64(@auth_key),
|
|
115
|
+
server_salt: @server_salt,
|
|
116
|
+
user_id: @user_id,
|
|
117
|
+
access_hash: @access_hash,
|
|
118
|
+
dc_number: @dc_number,
|
|
119
|
+
time_offset: @time_offset
|
|
120
|
+
}
|
|
183
121
|
end
|
|
184
122
|
|
|
185
|
-
def
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
body
|
|
190
|
-
end
|
|
123
|
+
def load_auth_data(auth_data)
|
|
124
|
+
raise ArgumentError, 'auth_data must be a Hash' unless auth_data.is_a?(Hash)
|
|
125
|
+
raise ArgumentError, 'auth_key is required' unless auth_data[:auth_key]
|
|
126
|
+
raise ArgumentError, 'server_salt is required' unless auth_data[:server_salt]
|
|
191
127
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
body += TL::Serializer.serialize_string(device_model)
|
|
198
|
-
body += TL::Serializer.serialize_string(system_version)
|
|
199
|
-
body += TL::Serializer.serialize_string(app_version)
|
|
200
|
-
body += TL::Serializer.serialize_string(system_lang_code)
|
|
201
|
-
body += TL::Serializer.serialize_string(lang_pack)
|
|
202
|
-
body += TL::Serializer.serialize_string(lang_code)
|
|
203
|
-
body += query
|
|
204
|
-
body
|
|
205
|
-
end
|
|
128
|
+
@auth_key = Base64.strict_decode64(auth_data[:auth_key])
|
|
129
|
+
@server_salt = auth_data[:server_salt]
|
|
130
|
+
@time_offset = auth_data[:time_offset] || 0
|
|
131
|
+
@user_id = auth_data[:user_id]
|
|
132
|
+
@access_hash = auth_data[:access_hash]
|
|
206
133
|
|
|
207
|
-
|
|
208
|
-
query = [0xc4f9186b].pack('L<')
|
|
209
|
-
|
|
210
|
-
unless @connection_initialized
|
|
211
|
-
query = init_connection(
|
|
212
|
-
api_id: @api_id,
|
|
213
|
-
device_model: @device_model,
|
|
214
|
-
system_version: @system_version,
|
|
215
|
-
app_version: @app_version,
|
|
216
|
-
system_lang_code: @system_lang_code,
|
|
217
|
-
lang_pack: @lang_pack,
|
|
218
|
-
lang_code: @lang_code,
|
|
219
|
-
query: query
|
|
220
|
-
)
|
|
221
|
-
query = invoke_with_layer(214, query)
|
|
222
|
-
@connection_initialized = true
|
|
223
|
-
end
|
|
134
|
+
@session = Session.new
|
|
224
135
|
|
|
225
|
-
|
|
136
|
+
true
|
|
226
137
|
end
|
|
227
138
|
|
|
228
|
-
def
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
query = [0xa677244f].pack('L<')
|
|
232
|
-
query += TL::Serializer.serialize_string(phone_number)
|
|
233
|
-
query += TL::Serializer.serialize_int(@api_id)
|
|
234
|
-
query += TL::Serializer.serialize_string(@api_hash)
|
|
235
|
-
query += TL::CodeSettings.serialize(code_settings)
|
|
236
|
-
|
|
237
|
-
unless @connection_initialized
|
|
238
|
-
query = init_connection(
|
|
239
|
-
api_id: @api_id,
|
|
240
|
-
device_model: @device_model,
|
|
241
|
-
system_version: @system_version,
|
|
242
|
-
app_version: @app_version,
|
|
243
|
-
system_lang_code: @system_lang_code,
|
|
244
|
-
lang_pack: @lang_pack,
|
|
245
|
-
lang_code: @lang_code,
|
|
246
|
-
query: query
|
|
247
|
-
)
|
|
248
|
-
query = invoke_with_layer(214, query)
|
|
249
|
-
@connection_initialized = true
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
rpc_call(query)
|
|
139
|
+
def update_user(user_id:, access_hash: nil)
|
|
140
|
+
@user_id = user_id
|
|
141
|
+
@access_hash = access_hash
|
|
253
142
|
end
|
|
254
143
|
end
|
|
255
144
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/help/get_config'
|
|
4
|
+
require_relative '../type/rpc/help/config'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class GetConfig
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
query = build_query
|
|
15
|
+
|
|
16
|
+
@client.rpc.call(query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call_sync
|
|
20
|
+
query = build_query
|
|
21
|
+
|
|
22
|
+
response = @client.rpc.call_sync(query)
|
|
23
|
+
|
|
24
|
+
Type::RPC::Help::Config.parse(response)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def build_query
|
|
30
|
+
Type::RPC::Help::GetConfig.build
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/contacts/get_contacts'
|
|
4
|
+
require_relative '../type/rpc/contacts/contacts'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class GetContacts
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(hash: 0)
|
|
14
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
15
|
+
|
|
16
|
+
query = Type::RPC::Contacts::GetContacts.build(hash: hash)
|
|
17
|
+
@client.rpc.call(query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call_sync(hash: 0)
|
|
21
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
22
|
+
|
|
23
|
+
query = Type::RPC::Contacts::GetContacts.build(hash: hash)
|
|
24
|
+
response = @client.rpc.call_sync(query)
|
|
25
|
+
Type::RPC::Contacts::Contacts.parse(response)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/updates/get_difference'
|
|
4
|
+
require_relative '../type/rpc/updates/difference'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class GetUpdatesDifference
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(pts:, date:, qts:, pts_limit: 100, qts_limit: 100, pts_total_limit: nil)
|
|
14
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
15
|
+
raise ArgumentError, 'pts is required' if pts.nil?
|
|
16
|
+
raise ArgumentError, 'date is required' if date.nil?
|
|
17
|
+
raise ArgumentError, 'qts is required' if qts.nil?
|
|
18
|
+
|
|
19
|
+
query = Type::RPC::Updates::GetDifference.build(
|
|
20
|
+
pts: pts,
|
|
21
|
+
pts_limit: pts_limit,
|
|
22
|
+
pts_total_limit: pts_total_limit,
|
|
23
|
+
date: date,
|
|
24
|
+
qts: qts,
|
|
25
|
+
qts_limit: qts_limit
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@client.rpc.call(query)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def call_sync(pts:, date:, qts:, pts_limit: 100, qts_limit: 100, pts_total_limit: nil)
|
|
32
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
33
|
+
raise ArgumentError, 'pts is required' if pts.nil?
|
|
34
|
+
raise ArgumentError, 'date is required' if date.nil?
|
|
35
|
+
raise ArgumentError, 'qts is required' if qts.nil?
|
|
36
|
+
|
|
37
|
+
query = Type::RPC::Updates::GetDifference.build(
|
|
38
|
+
pts: pts,
|
|
39
|
+
pts_limit: pts_limit,
|
|
40
|
+
pts_total_limit: pts_total_limit,
|
|
41
|
+
date: date,
|
|
42
|
+
qts: qts,
|
|
43
|
+
qts_limit: qts_limit
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
response = @client.rpc.call_sync(query)
|
|
47
|
+
Type::RPC::Updates::Difference.parse(response)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/updates/get_state'
|
|
4
|
+
require_relative '../type/rpc/updates/state'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class GetUpdatesState
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
15
|
+
|
|
16
|
+
query = Type::RPC::Updates::GetState.build
|
|
17
|
+
@client.rpc.call(query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call_sync
|
|
21
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
22
|
+
|
|
23
|
+
query = Type::RPC::Updates::GetState.build
|
|
24
|
+
response = @client.rpc.call_sync(query)
|
|
25
|
+
Type::RPC::Updates::State.parse(response)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/users/get_users'
|
|
4
|
+
require_relative '../type/rpc/users/users'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class GetUsers
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
15
|
+
|
|
16
|
+
query = Type::RPC::Users::GetUsers.build
|
|
17
|
+
@client.rpc.call(query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call_sync
|
|
21
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
22
|
+
|
|
23
|
+
query = Type::RPC::Users::GetUsers.build
|
|
24
|
+
response = @client.rpc.call_sync(query)
|
|
25
|
+
Type::RPC::Users::Users.parse(response)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/ping'
|
|
4
|
+
require_relative '../type/rpc/pong'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class Ping
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(ping_id = nil)
|
|
14
|
+
ping_id ||= rand(2**63)
|
|
15
|
+
body = Type::RPC::Ping.build(ping_id)
|
|
16
|
+
|
|
17
|
+
@client.rpc.call(body)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call_sync(ping_id = nil)
|
|
21
|
+
ping_id ||= rand(2**63)
|
|
22
|
+
body = Type::RPC::Ping.build(ping_id)
|
|
23
|
+
|
|
24
|
+
response_body = @client.rpc.call_sync(body)
|
|
25
|
+
pong = Type::RPC::Pong.parse(response_body)
|
|
26
|
+
|
|
27
|
+
raise PingMismatchError unless pong[:ping_id] == ping_id
|
|
28
|
+
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/auth/send_code'
|
|
4
|
+
require_relative '../type/rpc/auth/sent_code'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class SendCode
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(phone_number, code_settings: {})
|
|
14
|
+
query = build_query(phone_number, code_settings)
|
|
15
|
+
|
|
16
|
+
@client.rpc.call(query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call_sync(phone_number, code_settings: {})
|
|
20
|
+
query = build_query(phone_number, code_settings)
|
|
21
|
+
|
|
22
|
+
response = @client.rpc.call_sync(query)
|
|
23
|
+
|
|
24
|
+
Type::RPC::Auth::SentCode.parse(response)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def build_query(phone_number, code_settings)
|
|
30
|
+
raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
|
|
31
|
+
|
|
32
|
+
Type::RPC::Auth::SendCode.build(
|
|
33
|
+
phone_number: phone_number,
|
|
34
|
+
api_id: @client.api_id,
|
|
35
|
+
api_hash: @client.api_hash,
|
|
36
|
+
code_settings: code_settings
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/messages/send_message'
|
|
4
|
+
require_relative '../type/rpc/messages/updates'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class SendMessage
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(user_id:, access_hash:, message:, random_id: nil)
|
|
14
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
15
|
+
raise ArgumentError, 'user_id is required' if user_id.nil?
|
|
16
|
+
raise ArgumentError, 'access_hash is required' if access_hash.nil?
|
|
17
|
+
raise ArgumentError, 'message is required and cannot be empty' if message.nil? || message.empty?
|
|
18
|
+
|
|
19
|
+
query = Type::RPC::Messages::SendMessage.build(
|
|
20
|
+
user_id: user_id,
|
|
21
|
+
access_hash: access_hash,
|
|
22
|
+
message: message,
|
|
23
|
+
random_id: random_id
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
@client.rpc.call(query)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call_sync(user_id:, access_hash:, message:, random_id: nil)
|
|
30
|
+
raise 'Auth key not generated' unless @client.auth_key
|
|
31
|
+
raise ArgumentError, 'user_id is required' if user_id.nil?
|
|
32
|
+
raise ArgumentError, 'access_hash is required' if access_hash.nil?
|
|
33
|
+
raise ArgumentError, 'message is required and cannot be empty' if message.nil? || message.empty?
|
|
34
|
+
|
|
35
|
+
query = Type::RPC::Messages::SendMessage.build(
|
|
36
|
+
user_id: user_id,
|
|
37
|
+
access_hash: access_hash,
|
|
38
|
+
message: message,
|
|
39
|
+
random_id: random_id
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
response = @client.rpc.call_sync(query)
|
|
43
|
+
Type::RPC::Messages::Updates.parse(response)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type/rpc/auth/sign_in'
|
|
4
|
+
require_relative '../type/rpc/auth/authorization'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module RPC
|
|
8
|
+
class SignIn
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(phone_number:, phone_code_hash:, phone_code:)
|
|
14
|
+
query = build_query(phone_number, phone_code_hash, phone_code)
|
|
15
|
+
|
|
16
|
+
@client.rpc.call(query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call_sync(phone_number:, phone_code_hash:, phone_code:)
|
|
20
|
+
query = build_query(phone_number, phone_code_hash, phone_code)
|
|
21
|
+
|
|
22
|
+
response = @client.rpc.call_sync(query)
|
|
23
|
+
|
|
24
|
+
result = Type::RPC::Auth::Authorization.parse(response)
|
|
25
|
+
|
|
26
|
+
if result[:authorization] && result[:user_id]
|
|
27
|
+
@client.update_user(user_id: result[:user_id], access_hash: result[:access_hash])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def build_query(phone_number, phone_code_hash, phone_code)
|
|
36
|
+
raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
|
|
37
|
+
raise ArgumentError, 'phone_code_hash is required' if phone_code_hash.nil? || phone_code_hash.empty?
|
|
38
|
+
raise ArgumentError, 'phone_code is required' if phone_code.nil? || phone_code.empty?
|
|
39
|
+
|
|
40
|
+
Type::RPC::Auth::SignIn.build(
|
|
41
|
+
phone_number: phone_number,
|
|
42
|
+
phone_code_hash: phone_code_hash,
|
|
43
|
+
phone_code: phone_code
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|