mtproto 0.0.13 → 0.0.14
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/FUTURE.md +9 -0
- data/docs/test_architecture_level1.md +237 -0
- data/lib/mtproto/auth_key_generator.rb +5 -5
- data/lib/mtproto/client/api/get_contacts.rb +14 -0
- data/lib/mtproto/client/api/send_message.rb +15 -0
- data/lib/mtproto/client/api.rb +2 -0
- data/lib/mtproto/client/rpc/response.rb +1 -1
- data/lib/mtproto/client/rpc.rb +2 -2
- data/lib/mtproto/client.rb +28 -18
- data/lib/mtproto/tl/constructors.rb +26 -0
- data/lib/mtproto/tl/object.rb +1 -1
- data/lib/mtproto/tl/objects/account_password.rb +1 -1
- data/lib/mtproto/tl/objects/authorization.rb +1 -1
- data/lib/mtproto/tl/objects/channels_create_channel.rb +48 -0
- data/lib/mtproto/tl/objects/channels_delete_messages.rb +32 -0
- data/lib/mtproto/tl/objects/channels_delete_participant_history.rb +34 -0
- data/lib/mtproto/tl/objects/channels_edit_banned.rb +54 -0
- data/lib/mtproto/tl/objects/channels_get_messages.rb +33 -0
- data/lib/mtproto/tl/objects/channels_get_participant.rb +36 -0
- data/lib/mtproto/tl/objects/channels_join_channel.rb +22 -0
- data/lib/mtproto/tl/objects/channels_leave_channel.rb +22 -0
- data/lib/mtproto/tl/objects/channels_report_spam.rb +37 -0
- data/lib/mtproto/tl/objects/check_password.rb +1 -1
- data/lib/mtproto/tl/objects/client_dh_inner_data.rb +1 -1
- data/lib/mtproto/tl/objects/contacts.rb +156 -0
- data/lib/mtproto/tl/objects/delete_messages.rb +25 -0
- data/lib/mtproto/tl/objects/dh_gen_response.rb +1 -1
- data/lib/mtproto/tl/objects/dialogs.rb +8 -4
- data/lib/mtproto/tl/objects/edit_message.rb +58 -0
- data/lib/mtproto/tl/objects/export_login_token.rb +1 -1
- data/lib/mtproto/tl/objects/forward_messages.rb +49 -0
- data/lib/mtproto/tl/objects/get_channel_difference.rb +41 -0
- data/lib/mtproto/tl/objects/get_config.rb +1 -1
- data/lib/mtproto/tl/objects/get_contacts.rb +17 -0
- data/lib/mtproto/tl/objects/get_dialogs.rb +1 -1
- data/lib/mtproto/tl/objects/get_difference.rb +1 -1
- data/lib/mtproto/tl/objects/get_file.rb +54 -0
- data/lib/mtproto/tl/objects/get_full_channel.rb +29 -0
- data/lib/mtproto/tl/objects/get_full_user.rb +28 -0
- data/lib/mtproto/tl/objects/get_history.rb +1 -1
- data/lib/mtproto/tl/objects/get_messages_reactions.rb +39 -0
- data/lib/mtproto/tl/objects/get_password.rb +1 -1
- data/lib/mtproto/tl/objects/get_state.rb +1 -1
- data/lib/mtproto/tl/objects/get_users.rb +1 -1
- data/lib/mtproto/tl/objects/help_config.rb +1 -1
- data/lib/mtproto/tl/objects/import_bot_authorization.rb +44 -0
- data/lib/mtproto/tl/objects/import_login_token.rb +1 -1
- data/lib/mtproto/tl/objects/init_connection.rb +2 -2
- data/lib/mtproto/tl/objects/invite_to_channel.rb +35 -0
- data/lib/mtproto/tl/objects/invoke_with_layer.rb +2 -2
- data/lib/mtproto/tl/objects/login_token.rb +2 -2
- data/lib/mtproto/tl/objects/messages.rb +1 -1
- data/lib/mtproto/tl/objects/pq_inner_data.rb +1 -1
- data/lib/mtproto/tl/objects/raw_response.rb +29 -0
- data/lib/mtproto/tl/objects/req_dh_params.rb +1 -1
- data/lib/mtproto/tl/objects/req_pq_multi.rb +1 -1
- data/lib/mtproto/tl/objects/res_pq.rb +1 -1
- data/lib/mtproto/tl/objects/resolve_username.rb +40 -0
- data/lib/mtproto/tl/objects/save_file_part.rb +40 -0
- data/lib/mtproto/tl/objects/send_code.rb +1 -1
- data/lib/mtproto/tl/objects/send_media.rb +85 -0
- data/lib/mtproto/tl/objects/send_message.rb +70 -0
- data/lib/mtproto/tl/objects/send_reaction.rb +68 -0
- data/lib/mtproto/tl/objects/sent_code.rb +1 -1
- data/lib/mtproto/tl/objects/server_dh_inner_data.rb +1 -1
- data/lib/mtproto/tl/objects/server_dh_params.rb +1 -1
- data/lib/mtproto/tl/objects/set_client_dh_params.rb +1 -1
- data/lib/mtproto/tl/objects/sign_in.rb +1 -1
- data/lib/mtproto/tl/objects/update.rb +1 -1
- data/lib/mtproto/tl/objects/update_short.rb +2 -2
- data/lib/mtproto/tl/objects/update_short_message.rb +1 -1
- data/lib/mtproto/tl/objects/update_short_sent_message.rb +36 -0
- data/lib/mtproto/tl/objects/update_username.rb +39 -0
- data/lib/mtproto/tl/objects/updates_difference.rb +2 -2
- data/lib/mtproto/tl/objects/updates_state.rb +1 -1
- data/lib/mtproto/tl/objects/users.rb +1 -1
- data/lib/mtproto/version.rb +1 -1
- metadata +36 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class GetFullChannel
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x08736a09
|
|
9
|
+
|
|
10
|
+
def initialize(channel:)
|
|
11
|
+
@channel = channel
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def serialize
|
|
15
|
+
result = u32_b(CONSTRUCTOR)
|
|
16
|
+
result += serialize_input_channel
|
|
17
|
+
result
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def serialize_input_channel
|
|
23
|
+
u32_b(Constructors::INPUT_CHANNEL) +
|
|
24
|
+
u64_b(@channel[:id]) +
|
|
25
|
+
u64_b(@channel[:access_hash])
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class GetFullUser
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0xb60f5918
|
|
9
|
+
INPUT_USER = 0xf21158c6
|
|
10
|
+
INPUT_USER_SELF = 0xf7c1b13f
|
|
11
|
+
|
|
12
|
+
# user: { id:, access_hash: } or { type: :self }
|
|
13
|
+
def initialize(user:)
|
|
14
|
+
@user = user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def serialize
|
|
18
|
+
result = u32_b(CONSTRUCTOR)
|
|
19
|
+
result += if @user[:type] == :self
|
|
20
|
+
u32_b(INPUT_USER_SELF)
|
|
21
|
+
else
|
|
22
|
+
u32_b(INPUT_USER) + u64_b(@user[:id]) + u64_b(@user[:access_hash] || 0)
|
|
23
|
+
end
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class GetMessagesReactions
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x8bba90e6
|
|
9
|
+
|
|
10
|
+
def initialize(peer:, ids:)
|
|
11
|
+
@peer = peer
|
|
12
|
+
@ids = ids
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def serialize
|
|
16
|
+
result = u32_b(CONSTRUCTOR)
|
|
17
|
+
result += serialize_input_peer
|
|
18
|
+
result += u32_b(Constructors::VECTOR) + u32_b(@ids.length)
|
|
19
|
+
@ids.each { |id| result += u32_b(id) }
|
|
20
|
+
result
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def serialize_input_peer
|
|
26
|
+
case @peer[:type]
|
|
27
|
+
when :channel
|
|
28
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
29
|
+
when :user
|
|
30
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
31
|
+
when :chat
|
|
32
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
33
|
+
else
|
|
34
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -14,7 +14,7 @@ module MTProto
|
|
|
14
14
|
@dc_options = dc_options
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def self.
|
|
17
|
+
def self.deserialize(data)
|
|
18
18
|
constructor = data[0, 4].unpack1('L<')
|
|
19
19
|
unless [Constructors::CONFIG, Constructors::GZIP_PACKED].include?(constructor)
|
|
20
20
|
raise UnexpectedConstructorError, constructor
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ImportBotAuthorization
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x67a3ff2c
|
|
9
|
+
|
|
10
|
+
def initialize(api_id:, api_hash:, bot_auth_token:)
|
|
11
|
+
@api_id = api_id
|
|
12
|
+
@api_hash = api_hash
|
|
13
|
+
@bot_auth_token = bot_auth_token
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def serialize
|
|
17
|
+
result = u32_b(CONSTRUCTOR)
|
|
18
|
+
result += u32_b(0) # flags (int, unused)
|
|
19
|
+
result += u32_b(@api_id)
|
|
20
|
+
result += serialize_tl_string(@api_hash)
|
|
21
|
+
result += serialize_tl_string(@bot_auth_token)
|
|
22
|
+
result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def serialize_tl_string(str)
|
|
28
|
+
bytes = str.to_s.b.bytes
|
|
29
|
+
length = bytes.length
|
|
30
|
+
|
|
31
|
+
if length <= 253
|
|
32
|
+
[length] + bytes + padding(length + 1)
|
|
33
|
+
else
|
|
34
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def padding(current_length)
|
|
39
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
40
|
+
[0] * pad_length
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -20,7 +20,7 @@ module MTProto
|
|
|
20
20
|
@query = query
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def
|
|
23
|
+
def serialize
|
|
24
24
|
flags = 0
|
|
25
25
|
|
|
26
26
|
result = u32_b(Constructors::INIT_CONNECTION)
|
|
@@ -32,7 +32,7 @@ module MTProto
|
|
|
32
32
|
result += serialize_tl_string(@system_lang_code)
|
|
33
33
|
result += serialize_tl_string(@lang_pack)
|
|
34
34
|
result += serialize_tl_string(@lang_code)
|
|
35
|
-
result + @query.
|
|
35
|
+
result + @query.serialize
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
private
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class InviteToChannel
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0xc9e33d54
|
|
9
|
+
INPUT_USER = 0xf21158c6
|
|
10
|
+
|
|
11
|
+
def initialize(channel:, users:)
|
|
12
|
+
@channel = channel
|
|
13
|
+
@users = users
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def serialize
|
|
17
|
+
result = u32_b(CONSTRUCTOR)
|
|
18
|
+
result += serialize_input_channel
|
|
19
|
+
result += u32_b(Constructors::VECTOR) + u32_b(@users.length)
|
|
20
|
+
@users.each do |u|
|
|
21
|
+
result += u32_b(INPUT_USER) + u64_b(u[:id]) + u64_b(u[:access_hash] || 0)
|
|
22
|
+
end
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def serialize_input_channel
|
|
29
|
+
u32_b(Constructors::INPUT_CHANNEL) +
|
|
30
|
+
u64_b(@channel[:id]) +
|
|
31
|
+
u64_b(@channel[:access_hash])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -27,7 +27,7 @@ module MTProto
|
|
|
27
27
|
@type == :success
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def self.
|
|
30
|
+
def self.deserialize(data)
|
|
31
31
|
constructor = data[0, 4].unpack1('L<')
|
|
32
32
|
|
|
33
33
|
case constructor
|
|
@@ -36,7 +36,7 @@ module MTProto
|
|
|
36
36
|
when Constructors::AUTH_LOGIN_TOKEN_MIGRATE_TO
|
|
37
37
|
parse_migrate_to(data)
|
|
38
38
|
when Constructors::AUTH_LOGIN_TOKEN_SUCCESS
|
|
39
|
-
new(type: :success, authorization: Authorization.
|
|
39
|
+
new(type: :success, authorization: Authorization.deserialize(data[4..]))
|
|
40
40
|
else
|
|
41
41
|
raise UnexpectedConstructorError, constructor
|
|
42
42
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../constructor_names'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
# Pseudo TL object used as response_class when we want rpc.call to hand
|
|
8
|
+
# back the raw bytes of whatever the server returns, without imposing a
|
|
9
|
+
# specific TL schema. Useful when a method can legally return one of
|
|
10
|
+
# several constructor variants (e.g. messages.sendMessage may return
|
|
11
|
+
# updateShortSentMessage, updates, or updatesCombined depending on
|
|
12
|
+
# context) and we just want to capture the wire bytes for fixtures.
|
|
13
|
+
class RawResponse
|
|
14
|
+
attr_reader :raw_bytes, :constructor_id, :constructor_name
|
|
15
|
+
|
|
16
|
+
def initialize(raw_bytes:, constructor_id:, constructor_name:)
|
|
17
|
+
@raw_bytes = raw_bytes
|
|
18
|
+
@constructor_id = constructor_id
|
|
19
|
+
@constructor_name = constructor_name
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.deserialize(bytes)
|
|
23
|
+
constructor = bytes[0, 4].unpack1('L<')
|
|
24
|
+
name = ConstructorNames::NAMES[constructor] || "0x#{constructor.to_s(16)}"
|
|
25
|
+
new(raw_bytes: bytes, constructor_id: constructor, constructor_name: name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -7,7 +7,7 @@ module MTProto
|
|
|
7
7
|
|
|
8
8
|
attr_reader :nonce, :server_nonce, :pq, :fingerprints
|
|
9
9
|
|
|
10
|
-
def self.
|
|
10
|
+
def self.deserialize(message)
|
|
11
11
|
data = message.body
|
|
12
12
|
constructor = b_u32(data[0, 4])
|
|
13
13
|
raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == Constructors::RES_PQ
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ResolveUsername
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x725afbbc
|
|
9
|
+
|
|
10
|
+
def initialize(username:)
|
|
11
|
+
@username = username
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def serialize
|
|
15
|
+
result = u32_b(CONSTRUCTOR)
|
|
16
|
+
result += u32_b(0) # flags
|
|
17
|
+
result += serialize_tl_string(@username)
|
|
18
|
+
result
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def serialize_tl_string(str)
|
|
24
|
+
bytes = str.encode('UTF-8').bytes
|
|
25
|
+
length = bytes.length
|
|
26
|
+
|
|
27
|
+
if length <= 253
|
|
28
|
+
[length] + bytes + padding(length + 1)
|
|
29
|
+
else
|
|
30
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def padding(current_length)
|
|
35
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
36
|
+
[0] * pad_length
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SaveFilePart
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
def initialize(file_id:, file_part:, bytes:)
|
|
9
|
+
@file_id = file_id
|
|
10
|
+
@file_part = file_part
|
|
11
|
+
@bytes = bytes
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def serialize
|
|
15
|
+
u32_b(Constructors::UPLOAD_SAVE_FILE_PART) +
|
|
16
|
+
u64_b(@file_id) +
|
|
17
|
+
u32_b(@file_part) +
|
|
18
|
+
serialize_tl_bytes(@bytes)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def serialize_tl_bytes(bytes)
|
|
24
|
+
bytes = bytes.bytes if bytes.is_a?(String)
|
|
25
|
+
length = bytes.length
|
|
26
|
+
|
|
27
|
+
if length <= 253
|
|
28
|
+
[length] + bytes + padding(length + 1)
|
|
29
|
+
else
|
|
30
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def padding(current_length)
|
|
35
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
36
|
+
[0] * pad_length
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
class SendMedia
|
|
8
|
+
include Binary
|
|
9
|
+
|
|
10
|
+
def initialize(peer:, media:, message: '', random_id: nil)
|
|
11
|
+
@peer = peer
|
|
12
|
+
@media = media
|
|
13
|
+
@message = message
|
|
14
|
+
@random_id = random_id || SecureRandom.random_number(2**63)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def serialize
|
|
18
|
+
result = u32_b(Constructors::MESSAGES_SEND_MEDIA)
|
|
19
|
+
result += u32_b(0) # flags
|
|
20
|
+
result += serialize_input_peer
|
|
21
|
+
result += serialize_input_media
|
|
22
|
+
result += serialize_tl_string(@message)
|
|
23
|
+
result += u64_b(@random_id)
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def serialize_input_peer
|
|
30
|
+
case @peer[:type]
|
|
31
|
+
when :self
|
|
32
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
33
|
+
when :user
|
|
34
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
35
|
+
when :chat
|
|
36
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
37
|
+
when :channel
|
|
38
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
39
|
+
else
|
|
40
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def serialize_input_media
|
|
45
|
+
case @media[:type]
|
|
46
|
+
when :uploaded_photo
|
|
47
|
+
serialize_input_media_uploaded_photo(@media[:file])
|
|
48
|
+
else
|
|
49
|
+
raise "Unknown media type: #{@media[:type]}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def serialize_input_media_uploaded_photo(file)
|
|
54
|
+
result = u32_b(Constructors::INPUT_MEDIA_UPLOADED_PHOTO)
|
|
55
|
+
result += u32_b(0) # flags
|
|
56
|
+
result += serialize_input_file(file)
|
|
57
|
+
result
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def serialize_input_file(file)
|
|
61
|
+
u32_b(Constructors::INPUT_FILE) +
|
|
62
|
+
u64_b(file[:id]) +
|
|
63
|
+
u32_b(file[:parts]) +
|
|
64
|
+
serialize_tl_string(file[:name].to_s) +
|
|
65
|
+
serialize_tl_string(file[:md5_checksum].to_s)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def serialize_tl_string(str)
|
|
69
|
+
bytes = str.encode('UTF-8').bytes
|
|
70
|
+
length = bytes.length
|
|
71
|
+
|
|
72
|
+
if length <= 253
|
|
73
|
+
[length] + bytes + padding(length + 1)
|
|
74
|
+
else
|
|
75
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def padding(current_length)
|
|
80
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
81
|
+
[0] * pad_length
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
class SendMessage
|
|
8
|
+
include Binary
|
|
9
|
+
|
|
10
|
+
INPUT_REPLY_TO_MESSAGE = 0x869fbe10
|
|
11
|
+
|
|
12
|
+
def initialize(peer:, message:, random_id: nil, reply_to: nil)
|
|
13
|
+
@peer = peer
|
|
14
|
+
@message = message
|
|
15
|
+
@random_id = random_id || SecureRandom.random_number(2**63)
|
|
16
|
+
@reply_to = reply_to
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def serialize
|
|
20
|
+
flags = 0
|
|
21
|
+
flags |= (1 << 0) if @reply_to
|
|
22
|
+
|
|
23
|
+
result = u32_b(Constructors::MESSAGES_SEND_MESSAGE)
|
|
24
|
+
result += u32_b(flags)
|
|
25
|
+
result += serialize_input_peer
|
|
26
|
+
result += serialize_reply_to if @reply_to
|
|
27
|
+
result += serialize_tl_string(@message)
|
|
28
|
+
result += u64_b(@random_id)
|
|
29
|
+
result
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def serialize_reply_to
|
|
35
|
+
u32_b(INPUT_REPLY_TO_MESSAGE) + u32_b(0) + u32_b(@reply_to)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def serialize_input_peer
|
|
39
|
+
case @peer[:type]
|
|
40
|
+
when :self
|
|
41
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
42
|
+
when :user
|
|
43
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
44
|
+
when :chat
|
|
45
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
46
|
+
when :channel
|
|
47
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
48
|
+
else
|
|
49
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def serialize_tl_string(str)
|
|
54
|
+
bytes = str.encode('UTF-8').bytes
|
|
55
|
+
length = bytes.length
|
|
56
|
+
|
|
57
|
+
if length <= 253
|
|
58
|
+
[length] + bytes + padding(length + 1)
|
|
59
|
+
else
|
|
60
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def padding(current_length)
|
|
65
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
66
|
+
[0] * pad_length
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SendReaction
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0xd30d78d4
|
|
9
|
+
REACTION_EMOJI = 0x1b2286b8
|
|
10
|
+
|
|
11
|
+
# emoticons: array of emoji strings (a single-element array is the common case);
|
|
12
|
+
# an empty array clears the reaction.
|
|
13
|
+
def initialize(peer:, msg_id:, emoticons: [])
|
|
14
|
+
@peer = peer
|
|
15
|
+
@msg_id = msg_id
|
|
16
|
+
@emoticons = emoticons
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def serialize
|
|
20
|
+
flags = 0
|
|
21
|
+
flags |= (1 << 0) unless @emoticons.empty? # reaction field present
|
|
22
|
+
|
|
23
|
+
result = u32_b(CONSTRUCTOR)
|
|
24
|
+
result += u32_b(flags)
|
|
25
|
+
result += serialize_input_peer
|
|
26
|
+
result += u32_b(@msg_id)
|
|
27
|
+
unless @emoticons.empty?
|
|
28
|
+
result += u32_b(Constructors::VECTOR) + u32_b(@emoticons.length)
|
|
29
|
+
@emoticons.each { |e| result += u32_b(REACTION_EMOJI) + serialize_tl_string(e) }
|
|
30
|
+
end
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def serialize_input_peer
|
|
37
|
+
case @peer[:type]
|
|
38
|
+
when :self
|
|
39
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
40
|
+
when :user
|
|
41
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
42
|
+
when :chat
|
|
43
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
44
|
+
when :channel
|
|
45
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
46
|
+
else
|
|
47
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def serialize_tl_string(str)
|
|
52
|
+
bytes = str.to_s.b.bytes
|
|
53
|
+
length = bytes.length
|
|
54
|
+
|
|
55
|
+
if length <= 253
|
|
56
|
+
[length] + bytes + padding(length + 1)
|
|
57
|
+
else
|
|
58
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def padding(current_length)
|
|
63
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
64
|
+
[0] * pad_length
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|